From 231d5e649464b8eec741529bbd1821b09e6bfd93 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Tue, 4 Aug 2020 21:32:23 +0400 Subject: [PATCH] [Build-System] Remove SpanDSP library from the FreeSWITCH tree and use packages instead. --- .drone.yml | 12 +- .gitignore | 1 - Freeswitch.2017.sln | 14 +- Makefile.am | 17 +- bootstrap.sh | 2 +- configure.ac | 6 +- debian/bootstrap.sh | 1 + debian/copyright | 44 - debian/license-reconcile.yml | 9 - freeswitch.spec | 1 + libs/.gitignore | 69 +- libs/spandsp/.gitignore | 14 - libs/spandsp/.update | 1 - libs/spandsp/AUTHORS | 1 - libs/spandsp/COPYING | 853 -- libs/spandsp/ChangeLog | 47 - libs/spandsp/DueDiligence | 55 - libs/spandsp/Makefile.am | 91 - libs/spandsp/NEWS | 1 - libs/spandsp/README | 35 - libs/spandsp/README.testdata | 53 - libs/spandsp/autogen.sh | 129 - libs/spandsp/config/.empty | 0 libs/spandsp/configure.ac | 646 - libs/spandsp/configure.gnu | 4 - libs/spandsp/debian/changelog | 119 - libs/spandsp/debian/compat | 1 - libs/spandsp/debian/control | 42 - libs/spandsp/debian/copyright | 25 - libs/spandsp/debian/libspandsp-dev.install | 4 - libs/spandsp/debian/libspandsp-doc.install | 1 - libs/spandsp/debian/libspandsp6.install | 2 - libs/spandsp/debian/rules | 106 - libs/spandsp/debian/watch | 7 - libs/spandsp/doc/Makefile.am | 38 - libs/spandsp/doc/css.css | 564 - libs/spandsp/doc/doxygen.in | 1184 -- libs/spandsp/doc/t38-gateway.dia | Bin 3015 -> 0 bytes libs/spandsp/doc/t38-terminal.dia | Bin 1903 -> 0 bytes libs/spandsp/doc/t38_manual.xml | 290 - libs/spandsp/doc/t38_manual/css.css | 564 - libs/spandsp/doc/wrapper.xsl | 5 - libs/spandsp/m4/ac_func_memmove.m4 | 27 - libs/spandsp/m4/ax_c99_features.m4 | 181 - libs/spandsp/m4/ax_check_arm_neon.m4 | 59 - libs/spandsp/m4/ax_check_export_capability.m4 | 61 - libs/spandsp/m4/ax_check_real_file.m4 | 27 - libs/spandsp/m4/ax_compiler_vendor.m4 | 65 - libs/spandsp/m4/ax_fixed_point_machine.m4 | 35 - libs/spandsp/m4/ax_func_aligned_alloc.m4 | 25 - libs/spandsp/m4/ax_misaligned_access_fails.m4 | 33 - libs/spandsp/spandsp-sim/Makefile.am | 126 - libs/spandsp/spandsp-sim/g1050.c | 1336 -- .../spandsp-sim/libspandsp_sim.2005.vcproj | 110 - .../spandsp-sim/libspandsp_sim.2008.vcproj | 270 - libs/spandsp/spandsp-sim/libspandsp_sim.dsp | 143 - libs/spandsp/spandsp-sim/line_model.c | 576 - libs/spandsp/spandsp-sim/make_line_models.c | 1040 -- .../msvc/make_line_models.2008.vcproj | 121 - libs/spandsp/spandsp-sim/msvc/msvcproj.foot | 7 - libs/spandsp/spandsp-sim/msvc/msvcproj.head | 92 - libs/spandsp/spandsp-sim/msvc/vc8proj.foot | 5 - libs/spandsp/spandsp-sim/msvc/vc8proj.head | 94 - libs/spandsp/spandsp-sim/msvc/vc9proj.foot | 5 - libs/spandsp/spandsp-sim/msvc/vc9proj.head | 254 - libs/spandsp/spandsp-sim/rfc2198_sim.c | 187 - libs/spandsp/spandsp-sim/spandsp-sim.h | 43 - libs/spandsp/spandsp-sim/spandsp/g1050.h | 300 - libs/spandsp/spandsp-sim/spandsp/line_model.h | 177 - .../spandsp/spandsp-sim/spandsp/line_models.h | 61 - .../spandsp/spandsp-sim/spandsp/rfc2198_sim.h | 97 - libs/spandsp/spandsp-sim/spandsp/test_utils.h | 79 - libs/spandsp/spandsp-sim/test_utils.c | 475 - libs/spandsp/spandsp.pc.in | 12 - libs/spandsp/spandsp.spec | 106 - libs/spandsp/spandsp.spec.in | 106 - libs/spandsp/spandsp/fax-tests.dtd | 58 - libs/spandsp/spandsp/fax-tests.xml | 707 - libs/spandsp/spandsp/global-tones.xml | 7363 --------- libs/spandsp/spandsp/tones.dtd | 225 - libs/spandsp/spandsp/tsb85.xml | 7000 --------- libs/spandsp/src/Makefile.am | 582 - libs/spandsp/src/ademco_contactid.c | 1134 -- libs/spandsp/src/adsi.c | 1127 -- libs/spandsp/src/alloc.c | 175 - libs/spandsp/src/async.c | 318 - libs/spandsp/src/at_interpreter.c | 5661 ------- libs/spandsp/src/awgn.c | 192 - libs/spandsp/src/bell_r2_mf.c | 867 -- libs/spandsp/src/bert.c | 516 - libs/spandsp/src/bit_operations.c | 179 - libs/spandsp/src/bitstream.c | 164 - libs/spandsp/src/complex_filters.c | 111 - libs/spandsp/src/complex_vector_float.c | 211 - libs/spandsp/src/complex_vector_int.c | 118 - libs/spandsp/src/crc.c | 212 - libs/spandsp/src/data_modems.c | 713 - libs/spandsp/src/dds_float.c | 2203 --- libs/spandsp/src/dds_int.c | 468 - libs/spandsp/src/dtmf.c | 612 - libs/spandsp/src/echo.c | 621 - libs/spandsp/src/fax.c | 530 - libs/spandsp/src/fax_modems.c | 690 - libs/spandsp/src/faxfont.h | 4642 ------ libs/spandsp/src/filter_tools.c | 243 - libs/spandsp/src/filter_tools.h | 56 - libs/spandsp/src/floating_fudge.h | 137 - libs/spandsp/src/fsk.c | 661 - libs/spandsp/src/g711.c | 195 - libs/spandsp/src/g722.c | 630 - libs/spandsp/src/g726.c | 1191 -- libs/spandsp/src/gsm0610_decode.c | 346 - libs/spandsp/src/gsm0610_encode.c | 341 - libs/spandsp/src/gsm0610_local.h | 217 - libs/spandsp/src/gsm0610_long_term.c | 434 - libs/spandsp/src/gsm0610_lpc.c | 598 - libs/spandsp/src/gsm0610_preprocess.c | 150 - libs/spandsp/src/gsm0610_rpe.c | 593 - libs/spandsp/src/gsm0610_short_term.c | 361 - libs/spandsp/src/hdlc.c | 752 - libs/spandsp/src/ima_adpcm.c | 510 - libs/spandsp/src/image_translate.c | 814 - libs/spandsp/src/libspandsp.2005.vcproj | 367 - libs/spandsp/src/libspandsp.2008.vcproj | 1346 -- .../src/libspandsp.2010.vcxproj.filters | 741 - libs/spandsp/src/libspandsp.2012.sln | 322 - libs/spandsp/src/libspandsp.2017.vcxproj | 470 - libs/spandsp/src/libtiff.2005.vcproj | 352 - libs/spandsp/src/libtiff.2008.vcproj | 483 - libs/spandsp/src/libtiff.2010.vcxproj.filters | 157 - libs/spandsp/src/logging.c | 283 - libs/spandsp/src/lpc10_analyse.c | 711 - libs/spandsp/src/lpc10_decode.c | 1084 -- libs/spandsp/src/lpc10_encdecs.h | 107 - libs/spandsp/src/lpc10_encode.c | 405 - libs/spandsp/src/lpc10_placev.c | 338 - libs/spandsp/src/lpc10_voicing.c | 490 - libs/spandsp/src/make_at_dictionary.c | 670 - libs/spandsp/src/make_cielab_luts.c | 87 - libs/spandsp/src/make_math_fixed_tables.c | 118 - libs/spandsp/src/make_modem_filter.c | 565 - libs/spandsp/src/make_t43_gray_code_tables.c | 105 - libs/spandsp/src/math_fixed.c | 255 - libs/spandsp/src/mmx_sse_decs.h | 65 - libs/spandsp/src/modem_connect_tones.c | 779 - libs/spandsp/src/modem_echo.c | 177 - .../src/msvc/Download_TIFF.2005.vcproj | 49 - .../src/msvc/Download_TIFF.2008.vcproj | 49 - libs/spandsp/src/msvc/config.h | 87 - libs/spandsp/src/msvc/getopt.c | 177 - libs/spandsp/src/msvc/gettimeofday.c | 36 - libs/spandsp/src/msvc/inttypes.h | 83 - .../src/msvc/make_at_dictionary.2005.vcproj | 113 - .../src/msvc/make_at_dictionary.2008.vcproj | 111 - .../make_at_dictionary.2010.vcxproj.filters | 14 - ...ake_math_fixed_tables.2010.vcxproj.filters | 14 - .../src/msvc/make_modem_filter.2005.vcproj | 131 - .../src/msvc/make_modem_filter.2008.vcproj | 129 - .../make_modem_filter.2010.vcxproj.filters | 29 - ..._t43_gray_code_tables.2010.vcxproj.filters | 14 - libs/spandsp/src/msvc/msvcproj.foot | 7 - libs/spandsp/src/msvc/msvcproj.head | 92 - libs/spandsp/src/msvc/spandsp.h | 156 - libs/spandsp/src/msvc/sys/time.h | 21 - libs/spandsp/src/msvc/tgmath.h | 34 - libs/spandsp/src/msvc/tiff/cleancount | 1 - libs/spandsp/src/msvc/unistd.h | 34 - libs/spandsp/src/msvc/util.vbs | 199 - libs/spandsp/src/msvc/vc10proj.foot | 33 - libs/spandsp/src/msvc/vc10proj.head | 157 - libs/spandsp/src/msvc/vc12proj.foot | 47 - libs/spandsp/src/msvc/vc12proj.head | 161 - libs/spandsp/src/msvc/vc8proj.foot | 29 - libs/spandsp/src/msvc/vc8proj.head | 94 - libs/spandsp/src/msvc/vc9proj.foot | 49 - libs/spandsp/src/msvc/vc9proj.head | 164 - libs/spandsp/src/noise.c | 129 - libs/spandsp/src/oki_adpcm.c | 386 - libs/spandsp/src/playout.c | 384 - libs/spandsp/src/plc.c | 262 - libs/spandsp/src/power_meter.c | 220 - libs/spandsp/src/queue.c | 430 - libs/spandsp/src/schedule.c | 167 - libs/spandsp/src/sig_tone.c | 717 - libs/spandsp/src/silence_gen.c | 171 - libs/spandsp/src/spandsp.h.in | 151 - libs/spandsp/src/spandsp/ademco_contactid.h | 365 - libs/spandsp/src/spandsp/adsi.h | 526 - libs/spandsp/src/spandsp/alloc.h | 77 - libs/spandsp/src/spandsp/arctan2.h | 126 - libs/spandsp/src/spandsp/async.h | 222 - libs/spandsp/src/spandsp/at_interpreter.h | 215 - libs/spandsp/src/spandsp/awgn.h | 94 - libs/spandsp/src/spandsp/bell_r2_mf.h | 273 - libs/spandsp/src/spandsp/bert.h | 160 - libs/spandsp/src/spandsp/biquad.h | 115 - libs/spandsp/src/spandsp/bit_operations.h | 319 - libs/spandsp/src/spandsp/bitstream.h | 87 - libs/spandsp/src/spandsp/complex.h | 511 - libs/spandsp/src/spandsp/complex_filters.h | 73 - .../src/spandsp/complex_vector_float.h | 170 - libs/spandsp/src/spandsp/complex_vector_int.h | 129 - libs/spandsp/src/spandsp/crc.h | 105 - libs/spandsp/src/spandsp/data_modems.h | 107 - libs/spandsp/src/spandsp/dc_restore.h | 91 - libs/spandsp/src/spandsp/dds.h | 273 - libs/spandsp/src/spandsp/dtmf.h | 235 - libs/spandsp/src/spandsp/echo.h | 192 - libs/spandsp/src/spandsp/expose.h | 109 - libs/spandsp/src/spandsp/fast_convert.h | 441 - libs/spandsp/src/spandsp/fax.h | 139 - libs/spandsp/src/spandsp/fax_modems.h | 138 - libs/spandsp/src/spandsp/fir.h | 302 - libs/spandsp/src/spandsp/fsk.h | 256 - libs/spandsp/src/spandsp/g168models.h | 338 - libs/spandsp/src/spandsp/g711.h | 324 - libs/spandsp/src/spandsp/g722.h | 121 - libs/spandsp/src/spandsp/g726.h | 120 - libs/spandsp/src/spandsp/gsm0610.h | 151 - libs/spandsp/src/spandsp/hdlc.h | 274 - libs/spandsp/src/spandsp/ima_adpcm.h | 115 - libs/spandsp/src/spandsp/image_translate.h | 120 - libs/spandsp/src/spandsp/logging.h | 138 - libs/spandsp/src/spandsp/lpc10.h | 118 - libs/spandsp/src/spandsp/math_fixed.h | 83 - .../spandsp/src/spandsp/modem_connect_tones.h | 189 - libs/spandsp/src/spandsp/modem_echo.h | 127 - libs/spandsp/src/spandsp/noise.h | 129 - libs/spandsp/src/spandsp/oki_adpcm.h | 102 - libs/spandsp/src/spandsp/playout.h | 147 - libs/spandsp/src/spandsp/plc.h | 156 - libs/spandsp/src/spandsp/power_meter.h | 137 - libs/spandsp/src/spandsp/private/README | 3 - .../src/spandsp/private/ademco_contactid.h | 95 - libs/spandsp/src/spandsp/private/adsi.h | 118 - libs/spandsp/src/spandsp/private/async.h | 93 - .../src/spandsp/private/at_interpreter.h | 130 - libs/spandsp/src/spandsp/private/awgn.h | 47 - libs/spandsp/src/spandsp/private/bell_r2_mf.h | 102 - libs/spandsp/src/spandsp/private/bert.h | 90 - libs/spandsp/src/spandsp/private/bitstream.h | 42 - .../spandsp/src/spandsp/private/data_modems.h | 138 - libs/spandsp/src/spandsp/private/dtmf.h | 119 - libs/spandsp/src/spandsp/private/echo.h | 92 - libs/spandsp/src/spandsp/private/fax.h | 50 - libs/spandsp/src/spandsp/private/fax_modems.h | 163 - libs/spandsp/src/spandsp/private/fsk.h | 98 - libs/spandsp/src/spandsp/private/g711.h | 39 - libs/spandsp/src/spandsp/private/g722.h | 98 - libs/spandsp/src/spandsp/private/g726.h | 85 - libs/spandsp/src/spandsp/private/gsm0610.h | 63 - libs/spandsp/src/spandsp/private/hdlc.h | 138 - libs/spandsp/src/spandsp/private/ima_adpcm.h | 53 - .../src/spandsp/private/image_translate.h | 54 - libs/spandsp/src/spandsp/private/logging.h | 46 - libs/spandsp/src/spandsp/private/lpc10.h | 218 - .../src/spandsp/private/modem_connect_tones.h | 103 - libs/spandsp/src/spandsp/private/modem_echo.h | 56 - libs/spandsp/src/spandsp/private/noise.h | 46 - libs/spandsp/src/spandsp/private/oki_adpcm.h | 58 - 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/queue.h | 50 - libs/spandsp/src/spandsp/private/schedule.h | 48 - libs/spandsp/src/spandsp/private/sig_tone.h | 238 - .../spandsp/src/spandsp/private/silence_gen.h | 41 - .../src/spandsp/private/super_tone_rx.h | 65 - .../src/spandsp/private/super_tone_tx.h | 50 - libs/spandsp/src/spandsp/private/swept_tone.h | 42 - libs/spandsp/src/spandsp/private/t30.h | 337 - .../spandsp/private/t30_dis_dtc_dcs_bits.h | 531 - libs/spandsp/src/spandsp/private/t31.h | 238 - libs/spandsp/src/spandsp/private/t38_core.h | 136 - .../spandsp/src/spandsp/private/t38_gateway.h | 205 - .../src/spandsp/private/t38_non_ecm_buffer.h | 84 - .../src/spandsp/private/t38_terminal.h | 123 - libs/spandsp/src/spandsp/private/t42.h | 153 - libs/spandsp/src/spandsp/private/t43.h | 96 - libs/spandsp/src/spandsp/private/t4_rx.h | 152 - .../src/spandsp/private/t4_t6_decode.h | 123 - .../src/spandsp/private/t4_t6_encode.h | 97 - libs/spandsp/src/spandsp/private/t4_tx.h | 199 - .../spandsp/private/t81_t82_arith_coding.h | 79 - libs/spandsp/src/spandsp/private/t85.h | 212 - libs/spandsp/src/spandsp/private/time_scale.h | 62 - libs/spandsp/src/spandsp/private/timezone.h | 90 - .../spandsp/src/spandsp/private/tone_detect.h | 30 - .../src/spandsp/private/tone_generate.h | 66 - libs/spandsp/src/spandsp/private/v17rx.h | 235 - libs/spandsp/src/spandsp/private/v17tx.h | 108 - libs/spandsp/src/spandsp/private/v18.h | 100 - libs/spandsp/src/spandsp/private/v22bis.h | 278 - libs/spandsp/src/spandsp/private/v27ter_rx.h | 196 - libs/spandsp/src/spandsp/private/v27ter_tx.h | 97 - libs/spandsp/src/spandsp/private/v29rx.h | 201 - libs/spandsp/src/spandsp/private/v29tx.h | 103 - libs/spandsp/src/spandsp/private/v42.h | 155 - libs/spandsp/src/spandsp/private/v42bis.h | 127 - libs/spandsp/src/spandsp/private/v8.h | 78 - libs/spandsp/src/spandsp/queue.h | 178 - libs/spandsp/src/spandsp/saturated.h | 421 - libs/spandsp/src/spandsp/schedule.h | 68 - libs/spandsp/src/spandsp/sig_tone.h | 178 - libs/spandsp/src/spandsp/silence_gen.h | 141 - libs/spandsp/src/spandsp/stdbool.h | 64 - libs/spandsp/src/spandsp/super_tone_rx.h | 171 - libs/spandsp/src/spandsp/super_tone_tx.h | 88 - libs/spandsp/src/spandsp/swept_tone.h | 57 - libs/spandsp/src/spandsp/t30.h | 639 - libs/spandsp/src/spandsp/t30_api.h | 590 - libs/spandsp/src/spandsp/t30_fcf.h | 122 - libs/spandsp/src/spandsp/t30_logging.h | 67 - libs/spandsp/src/spandsp/t31.h | 177 - libs/spandsp/src/spandsp/t35.h | 95 - libs/spandsp/src/spandsp/t38_core.h | 425 - libs/spandsp/src/spandsp/t38_gateway.h | 218 - libs/spandsp/src/spandsp/t38_non_ecm_buffer.h | 134 - libs/spandsp/src/spandsp/t38_terminal.h | 146 - libs/spandsp/src/spandsp/t42.h | 237 - libs/spandsp/src/spandsp/t43.h | 207 - libs/spandsp/src/spandsp/t4_rx.h | 534 - libs/spandsp/src/spandsp/t4_t6_decode.h | 119 - libs/spandsp/src/spandsp/t4_t6_encode.h | 152 - libs/spandsp/src/spandsp/t4_tx.h | 422 - .../src/spandsp/t81_t82_arith_coding.h | 81 - libs/spandsp/src/spandsp/t85.h | 286 - libs/spandsp/src/spandsp/telephony.h | 138 - libs/spandsp/src/spandsp/time_scale.h | 118 - libs/spandsp/src/spandsp/timezone.h | 88 - libs/spandsp/src/spandsp/timing.h | 81 - libs/spandsp/src/spandsp/tone_detect.h | 246 - libs/spandsp/src/spandsp/tone_generate.h | 104 - libs/spandsp/src/spandsp/v17rx.h | 340 - libs/spandsp/src/spandsp/v17tx.h | 165 - libs/spandsp/src/spandsp/v18.h | 194 - libs/spandsp/src/spandsp/v22bis.h | 232 - libs/spandsp/src/spandsp/v27ter_rx.h | 172 - libs/spandsp/src/spandsp/v27ter_tx.h | 146 - libs/spandsp/src/spandsp/v29rx.h | 251 - libs/spandsp/src/spandsp/v29tx.h | 177 - libs/spandsp/src/spandsp/v42.h | 115 - libs/spandsp/src/spandsp/v42bis.h | 146 - libs/spandsp/src/spandsp/v8.h | 205 - libs/spandsp/src/spandsp/vector_float.h | 195 - libs/spandsp/src/spandsp/vector_int.h | 196 - libs/spandsp/src/spandsp/version.h | 36 - libs/spandsp/src/spandsp/version.h.in | 36 - libs/spandsp/src/super_tone_rx.c | 493 - libs/spandsp/src/super_tone_tx.c | 291 - libs/spandsp/src/swept_tone.c | 132 - libs/spandsp/src/t30.c | 7410 --------- libs/spandsp/src/t30_api.c | 1032 -- libs/spandsp/src/t30_local.h | 43 - libs/spandsp/src/t30_logging.c | 1049 -- libs/spandsp/src/t31.c | 3090 ---- libs/spandsp/src/t35.c | 944 -- libs/spandsp/src/t38_core.c | 1256 -- libs/spandsp/src/t38_gateway.c | 2435 --- libs/spandsp/src/t38_non_ecm_buffer.c | 384 - libs/spandsp/src/t38_terminal.c | 1581 -- libs/spandsp/src/t42.c | 1436 -- libs/spandsp/src/t42_t43_local.h | 45 - libs/spandsp/src/t43.c | 934 -- libs/spandsp/src/t4_rx.c | 1408 -- libs/spandsp/src/t4_t6_decode.c | 894 -- libs/spandsp/src/t4_t6_decode_states.h | 12484 ---------------- libs/spandsp/src/t4_t6_encode.c | 1189 -- libs/spandsp/src/t4_tx.c | 2640 ---- libs/spandsp/src/t81_t82_arith_coding.c | 512 - libs/spandsp/src/t85_decode.c | 950 -- libs/spandsp/src/t85_encode.c | 753 - libs/spandsp/src/testcpuid.c | 209 - libs/spandsp/src/time_scale.c | 333 - libs/spandsp/src/timezone.c | 820 - libs/spandsp/src/tone_detect.c | 301 - libs/spandsp/src/tone_generate.c | 260 - .../src/v17_v32bis_rx_constellation_maps.h | 6887 --------- .../src/v17_v32bis_tx_constellation_maps.h | 325 - libs/spandsp/src/v17rx.c | 1636 -- libs/spandsp/src/v17tx.c | 488 - libs/spandsp/src/v18.c | 1235 -- libs/spandsp/src/v22bis_rx.c | 1002 -- libs/spandsp/src/v22bis_tx.c | 762 - libs/spandsp/src/v27ter_rx.c | 1150 -- libs/spandsp/src/v27ter_tx.c | 440 - libs/spandsp/src/v29rx.c | 1217 -- libs/spandsp/src/v29tx.c | 424 - libs/spandsp/src/v29tx_constellation_maps.h | 79 - libs/spandsp/src/v42.c | 1573 -- libs/spandsp/src/v42bis.c | 773 - libs/spandsp/src/v8.c | 1261 -- libs/spandsp/src/vector_float.c | 918 -- libs/spandsp/src/vector_int.c | 626 - libs/spandsp/test-data/Makefile.am | 26 - libs/spandsp/test-data/etsi/Makefile.am | 26 - libs/spandsp/test-data/etsi/fax/Makefile.am | 59 - .../etsi/fax/generate_etsi_300_242_pages.c | 681 - libs/spandsp/test-data/itu/Makefile.am | 26 - libs/spandsp/test-data/itu/fax/Makefile.am | 167 - .../test-data/itu/fax/generate_dithered_tif.c | 157 - .../test-data/itu/fax/generate_sized_pages.c | 720 - .../itu/fax/generate_striped_pages.c | 127 - libs/spandsp/test-data/itu/fax/itu1.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu2.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu3.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu4.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu5.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu6.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu7.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/itu8.pbm | Bin 513229 -> 0 bytes libs/spandsp/test-data/itu/fax/test1.pbm | Bin 271883 -> 0 bytes libs/spandsp/test-data/itu/fax/test2.pbm | Bin 279213 -> 0 bytes libs/spandsp/test-data/itu/fax/test3.pbm | Bin 279213 -> 0 bytes libs/spandsp/test-data/itu/fax/test4.pbm | Bin 279213 -> 0 bytes .../spandsp/test-data/itu/tiff-fx/Makefile.am | 39 - libs/spandsp/test-data/local/Makefile.am | 31 - libs/spandsp/test-data/local/dam9.wav | Bin 343852 -> 0 bytes libs/spandsp/test-data/local/dam9_lpc55.wav | Bin 343844 -> 0 bytes .../test-data/local/lenna-colour-bilevel.tif | Bin 990730 -> 0 bytes libs/spandsp/test-data/local/lenna-colour.tif | Bin 793564 -> 0 bytes .../test-data/local/short_nb_voice.wav | Bin 192044 -> 0 bytes .../test-data/local/short_wb_voice.wav | Bin 98838 -> 0 bytes libs/spandsp/tests/Makefile.am | 427 - libs/spandsp/tests/ademco_contactid_tests.c | 390 - libs/spandsp/tests/adsi_tests.c | 865 -- libs/spandsp/tests/alloc_tests.c | 79 - libs/spandsp/tests/async_tests.c | 244 - libs/spandsp/tests/at_interpreter_tests.c | 571 - libs/spandsp/tests/awgn_tests.c | 151 - libs/spandsp/tests/bell_mf_rx_tests.c | 617 - libs/spandsp/tests/bell_mf_tx_tests.c | 165 - libs/spandsp/tests/bert_tests.c | 482 - libs/spandsp/tests/bit_operations_tests.c | 293 - libs/spandsp/tests/bitstream_tests.c | 187 - libs/spandsp/tests/complex_tests.c | 79 - .../tests/complex_vector_float_tests.c | 146 - libs/spandsp/tests/complex_vector_int_tests.c | 134 - libs/spandsp/tests/crc_tests.c | 130 - libs/spandsp/tests/data_modems_tests.c | 316 - libs/spandsp/tests/dc_restore_tests.c | 92 - libs/spandsp/tests/dds_tests.c | 217 - libs/spandsp/tests/dtmf_rx_tests.c | 926 -- libs/spandsp/tests/dtmf_tx_tests.c | 219 - libs/spandsp/tests/dummy_modems_tests.c | 342 - libs/spandsp/tests/echo_monitor.cpp | 457 - libs/spandsp/tests/echo_monitor.h | 60 - libs/spandsp/tests/echo_tests.c | 1722 --- libs/spandsp/tests/fax_decode.c | 813 - libs/spandsp/tests/fax_tester.c | 1909 --- libs/spandsp/tests/fax_tester.h | 222 - libs/spandsp/tests/fax_tests.c | 1645 -- libs/spandsp/tests/fax_tests.sh | 401 - libs/spandsp/tests/fax_utils.c | 136 - libs/spandsp/tests/fax_utils.h | 51 - libs/spandsp/tests/fsk_tests.c | 543 - libs/spandsp/tests/g1050_tests.c | 241 - libs/spandsp/tests/g168_tests.c | 324 - libs/spandsp/tests/g711_tests.c | 512 - libs/spandsp/tests/g722_tests.c | 692 - libs/spandsp/tests/g726_tests.c | 1280 -- libs/spandsp/tests/gsm0610_tests.c | 622 - libs/spandsp/tests/hdlc_tests.c | 868 -- libs/spandsp/tests/ima_adpcm_tests.c | 211 - libs/spandsp/tests/image_translate_tests.c | 842 -- libs/spandsp/tests/line_model_monitor.cpp | 458 - libs/spandsp/tests/line_model_monitor.h | 60 - libs/spandsp/tests/line_model_tests.c | 402 - libs/spandsp/tests/logging_tests.c | 212 - libs/spandsp/tests/lpc10_tests.c | 258 - libs/spandsp/tests/make_g168_css.c | 429 - libs/spandsp/tests/math_fixed_tests.c | 427 - libs/spandsp/tests/media_monitor.cpp | 319 - libs/spandsp/tests/media_monitor.h | 54 - .../spandsp/tests/modem_connect_tones_tests.c | 1748 --- libs/spandsp/tests/modem_echo_tests.c | 394 - libs/spandsp/tests/modem_monitor.cpp | 591 - libs/spandsp/tests/modem_monitor.h | 68 - libs/spandsp/tests/noise_tests.c | 232 - libs/spandsp/tests/oki_adpcm_tests.c | 297 - libs/spandsp/tests/pcap_parse.c | 312 - libs/spandsp/tests/pcap_parse.h | 53 - libs/spandsp/tests/playout_tests.c | 337 - libs/spandsp/tests/plc_tests.c | 182 - libs/spandsp/tests/power_meter_tests.c | 376 - libs/spandsp/tests/pseudo_terminal_tests.c | 150 - libs/spandsp/tests/pseudo_terminals.c | 201 - libs/spandsp/tests/pseudo_terminals.h | 46 - libs/spandsp/tests/queue_tests.c | 734 - libs/spandsp/tests/r2_mf_rx_tests.c | 667 - libs/spandsp/tests/r2_mf_tx_tests.c | 106 - libs/spandsp/tests/regression_tests.sh | 745 - libs/spandsp/tests/rfc2198_sim_tests.c | 244 - libs/spandsp/tests/saturated_tests.c | 351 - libs/spandsp/tests/schedule_tests.c | 112 - libs/spandsp/tests/sig_tone_tests.c | 660 - libs/spandsp/tests/socket_harness.c | 371 - libs/spandsp/tests/socket_harness.h | 75 - libs/spandsp/tests/super_tone_rx_tests.c | 507 - libs/spandsp/tests/super_tone_tx_tests.c | 303 - libs/spandsp/tests/swept_tone_tests.c | 103 - .../spandsp/tests/t31_pseudo_terminal_tests.c | 839 -- libs/spandsp/tests/t31_tests.c | 953 -- libs/spandsp/tests/t35_tests.c | 110 - libs/spandsp/tests/t38_core_tests.c | 734 - libs/spandsp/tests/t38_decode.c | 598 - libs/spandsp/tests/t38_non_ecm_buffer_tests.c | 710 - libs/spandsp/tests/t42_tests.c | 623 - libs/spandsp/tests/t43_tests.c | 1408 -- libs/spandsp/tests/t4_t6_tests.c | 422 - libs/spandsp/tests/t4_tests.c | 664 - .../tests/t81_t82_arith_coding_tests.c | 234 - libs/spandsp/tests/t85_tests.c | 360 - libs/spandsp/tests/testadsi.c | 684 - libs/spandsp/tests/testfax.c | 650 - libs/spandsp/tests/time_scale_tests.c | 201 - libs/spandsp/tests/timezone_tests.c | 74 - libs/spandsp/tests/tone_detect_tests.c | 140 - libs/spandsp/tests/tone_generate_tests.c | 246 - libs/spandsp/tests/tsb85_extra_tests.sh | 34 - libs/spandsp/tests/tsb85_tests.c | 262 - libs/spandsp/tests/tsb85_tests.sh | 124 - libs/spandsp/tests/udptl.c | 655 - libs/spandsp/tests/udptl.h | 158 - libs/spandsp/tests/v17_tests.c | 604 - libs/spandsp/tests/v17_tests.sh | 16 - libs/spandsp/tests/v18_tests.c | 8995 ----------- libs/spandsp/tests/v22bis_tests.c | 482 - libs/spandsp/tests/v27ter_tests.c | 611 - libs/spandsp/tests/v27ter_tests.sh | 16 - libs/spandsp/tests/v29_tests.c | 590 - libs/spandsp/tests/v29_tests.sh | 16 - libs/spandsp/tests/v42_tests.c | 198 - libs/spandsp/tests/v42bis_tests.c | 225 - libs/spandsp/tests/v42bis_tests.sh | 152 - libs/spandsp/tests/v8_tests.c | 679 - libs/spandsp/tests/vector_float_tests.c | 651 - libs/spandsp/tests/vector_int_tests.c | 185 - libs/spandsp/unpack_g722_data.sh | 56 - libs/spandsp/unpack_g726_data.sh | 61 - libs/spandsp/unpack_gsm0610_data.sh | 353 - libs/spandsp/unpack_v56ter_data.sh | 57 - libs/spandsp/wrapper.xsl | 5 - libs/spandsp/yum-prepare.sh | 25 - .../libtiff}/libtiff.2017.vcxproj | 0 libs/win32/spandsp/libspandsp.2017.vcxproj | 471 + .../spandsp}/make_at_dictionary.2017.vcxproj | 6 +- .../spandsp}/make_cielab_luts.2017.vcxproj | 6 +- .../make_math_fixed_tables.2017.vcxproj | 6 +- .../spandsp}/make_modem_filter.2017.vcxproj | 54 +- .../make_t43_gray_code_tables.2017.vcxproj | 6 +- src/mod/applications/mod_spandsp/Makefile.am | 12 +- .../mod_spandsp/mod_spandsp.2017.vcxproj | 365 +- .../mod_gsmopen/mod_gsmopen.2017.vcxproj | 1 + .../mod_skypopen/mod_skypopen.2015.vcxproj | 1 + w32/Console/FreeSwitchConsole.2017.vcxproj | 9 +- w32/Library/FreeSwitchCore.2017.vcxproj | 1640 +- w32/download_spandsp.props | 41 + w32/spandsp-version.props | 19 + w32/spandsp.props | 15 + 560 files changed, 1624 insertions(+), 226108 deletions(-) delete mode 100644 libs/spandsp/.gitignore delete mode 100644 libs/spandsp/.update delete mode 100644 libs/spandsp/AUTHORS delete mode 100644 libs/spandsp/COPYING delete mode 100644 libs/spandsp/ChangeLog delete mode 100644 libs/spandsp/DueDiligence delete mode 100644 libs/spandsp/Makefile.am delete mode 100644 libs/spandsp/NEWS delete mode 100644 libs/spandsp/README delete mode 100644 libs/spandsp/README.testdata delete mode 100755 libs/spandsp/autogen.sh delete mode 100644 libs/spandsp/config/.empty delete mode 100644 libs/spandsp/configure.ac delete mode 100755 libs/spandsp/configure.gnu delete mode 100644 libs/spandsp/debian/changelog delete mode 100644 libs/spandsp/debian/compat delete mode 100644 libs/spandsp/debian/control delete mode 100644 libs/spandsp/debian/copyright delete mode 100644 libs/spandsp/debian/libspandsp-dev.install delete mode 100644 libs/spandsp/debian/libspandsp-doc.install delete mode 100644 libs/spandsp/debian/libspandsp6.install delete mode 100755 libs/spandsp/debian/rules delete mode 100644 libs/spandsp/debian/watch delete mode 100644 libs/spandsp/doc/Makefile.am delete mode 100644 libs/spandsp/doc/css.css delete mode 100644 libs/spandsp/doc/doxygen.in delete mode 100644 libs/spandsp/doc/t38-gateway.dia delete mode 100644 libs/spandsp/doc/t38-terminal.dia delete mode 100644 libs/spandsp/doc/t38_manual.xml delete mode 100644 libs/spandsp/doc/t38_manual/css.css delete mode 100644 libs/spandsp/doc/wrapper.xsl delete mode 100644 libs/spandsp/m4/ac_func_memmove.m4 delete mode 100644 libs/spandsp/m4/ax_c99_features.m4 delete mode 100644 libs/spandsp/m4/ax_check_arm_neon.m4 delete mode 100644 libs/spandsp/m4/ax_check_export_capability.m4 delete mode 100644 libs/spandsp/m4/ax_check_real_file.m4 delete mode 100644 libs/spandsp/m4/ax_compiler_vendor.m4 delete mode 100644 libs/spandsp/m4/ax_fixed_point_machine.m4 delete mode 100644 libs/spandsp/m4/ax_func_aligned_alloc.m4 delete mode 100644 libs/spandsp/m4/ax_misaligned_access_fails.m4 delete mode 100644 libs/spandsp/spandsp-sim/Makefile.am delete mode 100644 libs/spandsp/spandsp-sim/g1050.c delete mode 100644 libs/spandsp/spandsp-sim/libspandsp_sim.2005.vcproj delete mode 100644 libs/spandsp/spandsp-sim/libspandsp_sim.2008.vcproj delete mode 100644 libs/spandsp/spandsp-sim/libspandsp_sim.dsp delete mode 100644 libs/spandsp/spandsp-sim/line_model.c delete mode 100644 libs/spandsp/spandsp-sim/make_line_models.c delete mode 100644 libs/spandsp/spandsp-sim/msvc/make_line_models.2008.vcproj delete mode 100644 libs/spandsp/spandsp-sim/msvc/msvcproj.foot delete mode 100644 libs/spandsp/spandsp-sim/msvc/msvcproj.head delete mode 100644 libs/spandsp/spandsp-sim/msvc/vc8proj.foot delete mode 100644 libs/spandsp/spandsp-sim/msvc/vc8proj.head delete mode 100644 libs/spandsp/spandsp-sim/msvc/vc9proj.foot delete mode 100644 libs/spandsp/spandsp-sim/msvc/vc9proj.head delete mode 100644 libs/spandsp/spandsp-sim/rfc2198_sim.c delete mode 100644 libs/spandsp/spandsp-sim/spandsp-sim.h delete mode 100644 libs/spandsp/spandsp-sim/spandsp/g1050.h delete mode 100644 libs/spandsp/spandsp-sim/spandsp/line_model.h delete mode 100644 libs/spandsp/spandsp-sim/spandsp/line_models.h delete mode 100644 libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h delete mode 100644 libs/spandsp/spandsp-sim/spandsp/test_utils.h delete mode 100644 libs/spandsp/spandsp-sim/test_utils.c delete mode 100644 libs/spandsp/spandsp.pc.in delete mode 100644 libs/spandsp/spandsp.spec delete mode 100644 libs/spandsp/spandsp.spec.in delete mode 100644 libs/spandsp/spandsp/fax-tests.dtd delete mode 100644 libs/spandsp/spandsp/fax-tests.xml delete mode 100644 libs/spandsp/spandsp/global-tones.xml delete mode 100644 libs/spandsp/spandsp/tones.dtd delete mode 100644 libs/spandsp/spandsp/tsb85.xml delete mode 100644 libs/spandsp/src/Makefile.am delete mode 100644 libs/spandsp/src/ademco_contactid.c delete mode 100644 libs/spandsp/src/adsi.c delete mode 100644 libs/spandsp/src/alloc.c delete mode 100644 libs/spandsp/src/async.c delete mode 100644 libs/spandsp/src/at_interpreter.c delete mode 100644 libs/spandsp/src/awgn.c delete mode 100644 libs/spandsp/src/bell_r2_mf.c delete mode 100644 libs/spandsp/src/bert.c delete mode 100644 libs/spandsp/src/bit_operations.c delete mode 100644 libs/spandsp/src/bitstream.c delete mode 100644 libs/spandsp/src/complex_filters.c delete mode 100644 libs/spandsp/src/complex_vector_float.c delete mode 100644 libs/spandsp/src/complex_vector_int.c delete mode 100644 libs/spandsp/src/crc.c delete mode 100644 libs/spandsp/src/data_modems.c delete mode 100644 libs/spandsp/src/dds_float.c delete mode 100644 libs/spandsp/src/dds_int.c delete mode 100644 libs/spandsp/src/dtmf.c delete mode 100644 libs/spandsp/src/echo.c delete mode 100644 libs/spandsp/src/fax.c delete mode 100644 libs/spandsp/src/fax_modems.c delete mode 100644 libs/spandsp/src/faxfont.h delete mode 100644 libs/spandsp/src/filter_tools.c delete mode 100644 libs/spandsp/src/filter_tools.h delete mode 100644 libs/spandsp/src/floating_fudge.h delete mode 100644 libs/spandsp/src/fsk.c delete mode 100644 libs/spandsp/src/g711.c delete mode 100644 libs/spandsp/src/g722.c delete mode 100644 libs/spandsp/src/g726.c delete mode 100644 libs/spandsp/src/gsm0610_decode.c delete mode 100644 libs/spandsp/src/gsm0610_encode.c delete mode 100644 libs/spandsp/src/gsm0610_local.h delete mode 100644 libs/spandsp/src/gsm0610_long_term.c delete mode 100644 libs/spandsp/src/gsm0610_lpc.c delete mode 100644 libs/spandsp/src/gsm0610_preprocess.c delete mode 100644 libs/spandsp/src/gsm0610_rpe.c delete mode 100644 libs/spandsp/src/gsm0610_short_term.c delete mode 100644 libs/spandsp/src/hdlc.c delete mode 100644 libs/spandsp/src/ima_adpcm.c delete mode 100644 libs/spandsp/src/image_translate.c delete mode 100644 libs/spandsp/src/libspandsp.2005.vcproj delete mode 100644 libs/spandsp/src/libspandsp.2008.vcproj delete mode 100644 libs/spandsp/src/libspandsp.2010.vcxproj.filters delete mode 100644 libs/spandsp/src/libspandsp.2012.sln delete mode 100644 libs/spandsp/src/libspandsp.2017.vcxproj delete mode 100644 libs/spandsp/src/libtiff.2005.vcproj delete mode 100644 libs/spandsp/src/libtiff.2008.vcproj delete mode 100644 libs/spandsp/src/libtiff.2010.vcxproj.filters delete mode 100644 libs/spandsp/src/logging.c delete mode 100644 libs/spandsp/src/lpc10_analyse.c delete mode 100644 libs/spandsp/src/lpc10_decode.c delete mode 100644 libs/spandsp/src/lpc10_encdecs.h delete mode 100644 libs/spandsp/src/lpc10_encode.c delete mode 100644 libs/spandsp/src/lpc10_placev.c delete mode 100644 libs/spandsp/src/lpc10_voicing.c delete mode 100644 libs/spandsp/src/make_at_dictionary.c delete mode 100644 libs/spandsp/src/make_cielab_luts.c delete mode 100644 libs/spandsp/src/make_math_fixed_tables.c delete mode 100644 libs/spandsp/src/make_modem_filter.c delete mode 100644 libs/spandsp/src/make_t43_gray_code_tables.c delete mode 100644 libs/spandsp/src/math_fixed.c delete mode 100644 libs/spandsp/src/mmx_sse_decs.h delete mode 100644 libs/spandsp/src/modem_connect_tones.c delete mode 100644 libs/spandsp/src/modem_echo.c delete mode 100644 libs/spandsp/src/msvc/Download_TIFF.2005.vcproj delete mode 100644 libs/spandsp/src/msvc/Download_TIFF.2008.vcproj delete mode 100644 libs/spandsp/src/msvc/config.h delete mode 100644 libs/spandsp/src/msvc/getopt.c delete mode 100644 libs/spandsp/src/msvc/gettimeofday.c delete mode 100644 libs/spandsp/src/msvc/inttypes.h delete mode 100644 libs/spandsp/src/msvc/make_at_dictionary.2005.vcproj delete mode 100644 libs/spandsp/src/msvc/make_at_dictionary.2008.vcproj delete mode 100644 libs/spandsp/src/msvc/make_at_dictionary.2010.vcxproj.filters delete mode 100644 libs/spandsp/src/msvc/make_math_fixed_tables.2010.vcxproj.filters delete mode 100644 libs/spandsp/src/msvc/make_modem_filter.2005.vcproj delete mode 100644 libs/spandsp/src/msvc/make_modem_filter.2008.vcproj delete mode 100644 libs/spandsp/src/msvc/make_modem_filter.2010.vcxproj.filters delete mode 100644 libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj.filters delete mode 100644 libs/spandsp/src/msvc/msvcproj.foot delete mode 100644 libs/spandsp/src/msvc/msvcproj.head delete mode 100644 libs/spandsp/src/msvc/spandsp.h delete mode 100644 libs/spandsp/src/msvc/sys/time.h delete mode 100644 libs/spandsp/src/msvc/tgmath.h delete mode 100644 libs/spandsp/src/msvc/tiff/cleancount delete mode 100644 libs/spandsp/src/msvc/unistd.h delete mode 100644 libs/spandsp/src/msvc/util.vbs delete mode 100644 libs/spandsp/src/msvc/vc10proj.foot delete mode 100644 libs/spandsp/src/msvc/vc10proj.head delete mode 100644 libs/spandsp/src/msvc/vc12proj.foot delete mode 100644 libs/spandsp/src/msvc/vc12proj.head delete mode 100644 libs/spandsp/src/msvc/vc8proj.foot delete mode 100644 libs/spandsp/src/msvc/vc8proj.head delete mode 100644 libs/spandsp/src/msvc/vc9proj.foot delete mode 100644 libs/spandsp/src/msvc/vc9proj.head delete mode 100644 libs/spandsp/src/noise.c delete mode 100644 libs/spandsp/src/oki_adpcm.c delete mode 100644 libs/spandsp/src/playout.c delete mode 100644 libs/spandsp/src/plc.c delete mode 100644 libs/spandsp/src/power_meter.c delete mode 100644 libs/spandsp/src/queue.c delete mode 100644 libs/spandsp/src/schedule.c delete mode 100644 libs/spandsp/src/sig_tone.c delete mode 100644 libs/spandsp/src/silence_gen.c delete mode 100644 libs/spandsp/src/spandsp.h.in delete mode 100644 libs/spandsp/src/spandsp/ademco_contactid.h delete mode 100644 libs/spandsp/src/spandsp/adsi.h delete mode 100644 libs/spandsp/src/spandsp/alloc.h delete mode 100644 libs/spandsp/src/spandsp/arctan2.h delete mode 100644 libs/spandsp/src/spandsp/async.h delete mode 100644 libs/spandsp/src/spandsp/at_interpreter.h delete mode 100644 libs/spandsp/src/spandsp/awgn.h delete mode 100644 libs/spandsp/src/spandsp/bell_r2_mf.h delete mode 100644 libs/spandsp/src/spandsp/bert.h delete mode 100644 libs/spandsp/src/spandsp/biquad.h delete mode 100644 libs/spandsp/src/spandsp/bit_operations.h delete mode 100644 libs/spandsp/src/spandsp/bitstream.h delete mode 100644 libs/spandsp/src/spandsp/complex.h delete mode 100644 libs/spandsp/src/spandsp/complex_filters.h delete mode 100644 libs/spandsp/src/spandsp/complex_vector_float.h delete mode 100644 libs/spandsp/src/spandsp/complex_vector_int.h delete mode 100644 libs/spandsp/src/spandsp/crc.h delete mode 100644 libs/spandsp/src/spandsp/data_modems.h delete mode 100644 libs/spandsp/src/spandsp/dc_restore.h delete mode 100644 libs/spandsp/src/spandsp/dds.h delete mode 100644 libs/spandsp/src/spandsp/dtmf.h delete mode 100644 libs/spandsp/src/spandsp/echo.h delete mode 100644 libs/spandsp/src/spandsp/expose.h delete mode 100644 libs/spandsp/src/spandsp/fast_convert.h delete mode 100644 libs/spandsp/src/spandsp/fax.h delete mode 100644 libs/spandsp/src/spandsp/fax_modems.h delete mode 100644 libs/spandsp/src/spandsp/fir.h delete mode 100644 libs/spandsp/src/spandsp/fsk.h delete mode 100644 libs/spandsp/src/spandsp/g168models.h delete mode 100644 libs/spandsp/src/spandsp/g711.h delete mode 100644 libs/spandsp/src/spandsp/g722.h delete mode 100644 libs/spandsp/src/spandsp/g726.h delete mode 100644 libs/spandsp/src/spandsp/gsm0610.h delete mode 100644 libs/spandsp/src/spandsp/hdlc.h delete mode 100644 libs/spandsp/src/spandsp/ima_adpcm.h delete mode 100644 libs/spandsp/src/spandsp/image_translate.h delete mode 100644 libs/spandsp/src/spandsp/logging.h delete mode 100644 libs/spandsp/src/spandsp/lpc10.h delete mode 100644 libs/spandsp/src/spandsp/math_fixed.h delete mode 100644 libs/spandsp/src/spandsp/modem_connect_tones.h delete mode 100644 libs/spandsp/src/spandsp/modem_echo.h delete mode 100644 libs/spandsp/src/spandsp/noise.h delete mode 100644 libs/spandsp/src/spandsp/oki_adpcm.h delete mode 100644 libs/spandsp/src/spandsp/playout.h delete mode 100644 libs/spandsp/src/spandsp/plc.h delete mode 100644 libs/spandsp/src/spandsp/power_meter.h delete mode 100644 libs/spandsp/src/spandsp/private/README delete mode 100644 libs/spandsp/src/spandsp/private/ademco_contactid.h delete mode 100644 libs/spandsp/src/spandsp/private/adsi.h delete mode 100644 libs/spandsp/src/spandsp/private/async.h delete mode 100644 libs/spandsp/src/spandsp/private/at_interpreter.h delete mode 100644 libs/spandsp/src/spandsp/private/awgn.h delete mode 100644 libs/spandsp/src/spandsp/private/bell_r2_mf.h delete mode 100644 libs/spandsp/src/spandsp/private/bert.h delete mode 100644 libs/spandsp/src/spandsp/private/bitstream.h delete mode 100644 libs/spandsp/src/spandsp/private/data_modems.h delete mode 100644 libs/spandsp/src/spandsp/private/dtmf.h delete mode 100644 libs/spandsp/src/spandsp/private/echo.h delete mode 100644 libs/spandsp/src/spandsp/private/fax.h delete mode 100644 libs/spandsp/src/spandsp/private/fax_modems.h delete mode 100644 libs/spandsp/src/spandsp/private/fsk.h delete mode 100644 libs/spandsp/src/spandsp/private/g711.h delete mode 100644 libs/spandsp/src/spandsp/private/g722.h delete mode 100644 libs/spandsp/src/spandsp/private/g726.h delete mode 100644 libs/spandsp/src/spandsp/private/gsm0610.h delete mode 100644 libs/spandsp/src/spandsp/private/hdlc.h delete mode 100644 libs/spandsp/src/spandsp/private/ima_adpcm.h delete mode 100644 libs/spandsp/src/spandsp/private/image_translate.h delete mode 100644 libs/spandsp/src/spandsp/private/logging.h delete mode 100644 libs/spandsp/src/spandsp/private/lpc10.h delete mode 100644 libs/spandsp/src/spandsp/private/modem_connect_tones.h delete mode 100644 libs/spandsp/src/spandsp/private/modem_echo.h delete mode 100644 libs/spandsp/src/spandsp/private/noise.h delete mode 100644 libs/spandsp/src/spandsp/private/oki_adpcm.h delete mode 100644 libs/spandsp/src/spandsp/private/playout.h delete mode 100644 libs/spandsp/src/spandsp/private/plc.h delete mode 100644 libs/spandsp/src/spandsp/private/power_meter.h delete mode 100644 libs/spandsp/src/spandsp/private/queue.h delete mode 100644 libs/spandsp/src/spandsp/private/schedule.h delete mode 100644 libs/spandsp/src/spandsp/private/sig_tone.h delete mode 100644 libs/spandsp/src/spandsp/private/silence_gen.h delete mode 100644 libs/spandsp/src/spandsp/private/super_tone_rx.h delete mode 100644 libs/spandsp/src/spandsp/private/super_tone_tx.h delete mode 100644 libs/spandsp/src/spandsp/private/swept_tone.h delete mode 100644 libs/spandsp/src/spandsp/private/t30.h delete mode 100644 libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h delete mode 100644 libs/spandsp/src/spandsp/private/t31.h delete mode 100644 libs/spandsp/src/spandsp/private/t38_core.h delete mode 100644 libs/spandsp/src/spandsp/private/t38_gateway.h delete mode 100644 libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h delete mode 100644 libs/spandsp/src/spandsp/private/t38_terminal.h delete mode 100644 libs/spandsp/src/spandsp/private/t42.h delete mode 100644 libs/spandsp/src/spandsp/private/t43.h delete mode 100644 libs/spandsp/src/spandsp/private/t4_rx.h delete mode 100644 libs/spandsp/src/spandsp/private/t4_t6_decode.h delete mode 100644 libs/spandsp/src/spandsp/private/t4_t6_encode.h delete mode 100644 libs/spandsp/src/spandsp/private/t4_tx.h delete mode 100644 libs/spandsp/src/spandsp/private/t81_t82_arith_coding.h delete mode 100644 libs/spandsp/src/spandsp/private/t85.h delete mode 100644 libs/spandsp/src/spandsp/private/time_scale.h delete mode 100644 libs/spandsp/src/spandsp/private/timezone.h delete mode 100644 libs/spandsp/src/spandsp/private/tone_detect.h delete mode 100644 libs/spandsp/src/spandsp/private/tone_generate.h delete mode 100644 libs/spandsp/src/spandsp/private/v17rx.h delete mode 100644 libs/spandsp/src/spandsp/private/v17tx.h delete mode 100644 libs/spandsp/src/spandsp/private/v18.h delete mode 100644 libs/spandsp/src/spandsp/private/v22bis.h delete mode 100644 libs/spandsp/src/spandsp/private/v27ter_rx.h delete mode 100644 libs/spandsp/src/spandsp/private/v27ter_tx.h delete mode 100644 libs/spandsp/src/spandsp/private/v29rx.h delete mode 100644 libs/spandsp/src/spandsp/private/v29tx.h delete mode 100644 libs/spandsp/src/spandsp/private/v42.h delete mode 100644 libs/spandsp/src/spandsp/private/v42bis.h delete mode 100644 libs/spandsp/src/spandsp/private/v8.h delete mode 100644 libs/spandsp/src/spandsp/queue.h delete mode 100644 libs/spandsp/src/spandsp/saturated.h delete mode 100644 libs/spandsp/src/spandsp/schedule.h delete mode 100644 libs/spandsp/src/spandsp/sig_tone.h delete mode 100644 libs/spandsp/src/spandsp/silence_gen.h delete mode 100644 libs/spandsp/src/spandsp/stdbool.h delete mode 100644 libs/spandsp/src/spandsp/super_tone_rx.h delete mode 100644 libs/spandsp/src/spandsp/super_tone_tx.h delete mode 100644 libs/spandsp/src/spandsp/swept_tone.h delete mode 100644 libs/spandsp/src/spandsp/t30.h delete mode 100644 libs/spandsp/src/spandsp/t30_api.h delete mode 100644 libs/spandsp/src/spandsp/t30_fcf.h delete mode 100644 libs/spandsp/src/spandsp/t30_logging.h delete mode 100644 libs/spandsp/src/spandsp/t31.h delete mode 100644 libs/spandsp/src/spandsp/t35.h delete mode 100644 libs/spandsp/src/spandsp/t38_core.h delete mode 100644 libs/spandsp/src/spandsp/t38_gateway.h delete mode 100644 libs/spandsp/src/spandsp/t38_non_ecm_buffer.h delete mode 100644 libs/spandsp/src/spandsp/t38_terminal.h delete mode 100644 libs/spandsp/src/spandsp/t42.h delete mode 100644 libs/spandsp/src/spandsp/t43.h delete mode 100644 libs/spandsp/src/spandsp/t4_rx.h delete mode 100644 libs/spandsp/src/spandsp/t4_t6_decode.h delete mode 100644 libs/spandsp/src/spandsp/t4_t6_encode.h delete mode 100644 libs/spandsp/src/spandsp/t4_tx.h delete mode 100644 libs/spandsp/src/spandsp/t81_t82_arith_coding.h delete mode 100644 libs/spandsp/src/spandsp/t85.h delete mode 100644 libs/spandsp/src/spandsp/telephony.h delete mode 100644 libs/spandsp/src/spandsp/time_scale.h delete mode 100644 libs/spandsp/src/spandsp/timezone.h delete mode 100644 libs/spandsp/src/spandsp/timing.h delete mode 100644 libs/spandsp/src/spandsp/tone_detect.h delete mode 100644 libs/spandsp/src/spandsp/tone_generate.h delete mode 100644 libs/spandsp/src/spandsp/v17rx.h delete mode 100644 libs/spandsp/src/spandsp/v17tx.h delete mode 100644 libs/spandsp/src/spandsp/v18.h delete mode 100644 libs/spandsp/src/spandsp/v22bis.h delete mode 100644 libs/spandsp/src/spandsp/v27ter_rx.h delete mode 100644 libs/spandsp/src/spandsp/v27ter_tx.h delete mode 100644 libs/spandsp/src/spandsp/v29rx.h delete mode 100644 libs/spandsp/src/spandsp/v29tx.h delete mode 100644 libs/spandsp/src/spandsp/v42.h delete mode 100644 libs/spandsp/src/spandsp/v42bis.h delete mode 100644 libs/spandsp/src/spandsp/v8.h delete mode 100644 libs/spandsp/src/spandsp/vector_float.h delete mode 100644 libs/spandsp/src/spandsp/vector_int.h delete mode 100644 libs/spandsp/src/spandsp/version.h delete mode 100644 libs/spandsp/src/spandsp/version.h.in delete mode 100644 libs/spandsp/src/super_tone_rx.c delete mode 100644 libs/spandsp/src/super_tone_tx.c delete mode 100644 libs/spandsp/src/swept_tone.c delete mode 100644 libs/spandsp/src/t30.c delete mode 100644 libs/spandsp/src/t30_api.c delete mode 100644 libs/spandsp/src/t30_local.h delete mode 100644 libs/spandsp/src/t30_logging.c delete mode 100644 libs/spandsp/src/t31.c delete mode 100644 libs/spandsp/src/t35.c delete mode 100644 libs/spandsp/src/t38_core.c delete mode 100644 libs/spandsp/src/t38_gateway.c delete mode 100644 libs/spandsp/src/t38_non_ecm_buffer.c delete mode 100644 libs/spandsp/src/t38_terminal.c delete mode 100644 libs/spandsp/src/t42.c delete mode 100644 libs/spandsp/src/t42_t43_local.h delete mode 100644 libs/spandsp/src/t43.c delete mode 100644 libs/spandsp/src/t4_rx.c delete mode 100644 libs/spandsp/src/t4_t6_decode.c delete mode 100644 libs/spandsp/src/t4_t6_decode_states.h delete mode 100644 libs/spandsp/src/t4_t6_encode.c delete mode 100644 libs/spandsp/src/t4_tx.c delete mode 100644 libs/spandsp/src/t81_t82_arith_coding.c delete mode 100644 libs/spandsp/src/t85_decode.c delete mode 100644 libs/spandsp/src/t85_encode.c delete mode 100644 libs/spandsp/src/testcpuid.c delete mode 100644 libs/spandsp/src/time_scale.c delete mode 100644 libs/spandsp/src/timezone.c delete mode 100644 libs/spandsp/src/tone_detect.c delete mode 100644 libs/spandsp/src/tone_generate.c delete mode 100644 libs/spandsp/src/v17_v32bis_rx_constellation_maps.h delete mode 100644 libs/spandsp/src/v17_v32bis_tx_constellation_maps.h delete mode 100644 libs/spandsp/src/v17rx.c delete mode 100644 libs/spandsp/src/v17tx.c delete mode 100644 libs/spandsp/src/v18.c delete mode 100644 libs/spandsp/src/v22bis_rx.c delete mode 100644 libs/spandsp/src/v22bis_tx.c delete mode 100644 libs/spandsp/src/v27ter_rx.c delete mode 100644 libs/spandsp/src/v27ter_tx.c delete mode 100644 libs/spandsp/src/v29rx.c delete mode 100644 libs/spandsp/src/v29tx.c delete mode 100644 libs/spandsp/src/v29tx_constellation_maps.h delete mode 100644 libs/spandsp/src/v42.c delete mode 100644 libs/spandsp/src/v42bis.c delete mode 100644 libs/spandsp/src/v8.c delete mode 100644 libs/spandsp/src/vector_float.c delete mode 100644 libs/spandsp/src/vector_int.c delete mode 100644 libs/spandsp/test-data/Makefile.am delete mode 100644 libs/spandsp/test-data/etsi/Makefile.am delete mode 100644 libs/spandsp/test-data/etsi/fax/Makefile.am delete mode 100644 libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c delete mode 100644 libs/spandsp/test-data/itu/Makefile.am delete mode 100644 libs/spandsp/test-data/itu/fax/Makefile.am delete mode 100644 libs/spandsp/test-data/itu/fax/generate_dithered_tif.c delete mode 100644 libs/spandsp/test-data/itu/fax/generate_sized_pages.c delete mode 100644 libs/spandsp/test-data/itu/fax/generate_striped_pages.c delete mode 100644 libs/spandsp/test-data/itu/fax/itu1.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu2.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu3.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu4.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu5.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu6.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu7.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/itu8.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/test1.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/test2.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/test3.pbm delete mode 100644 libs/spandsp/test-data/itu/fax/test4.pbm delete mode 100644 libs/spandsp/test-data/itu/tiff-fx/Makefile.am delete mode 100644 libs/spandsp/test-data/local/Makefile.am delete mode 100644 libs/spandsp/test-data/local/dam9.wav delete mode 100644 libs/spandsp/test-data/local/dam9_lpc55.wav delete mode 100644 libs/spandsp/test-data/local/lenna-colour-bilevel.tif delete mode 100644 libs/spandsp/test-data/local/lenna-colour.tif delete mode 100644 libs/spandsp/test-data/local/short_nb_voice.wav delete mode 100644 libs/spandsp/test-data/local/short_wb_voice.wav delete mode 100644 libs/spandsp/tests/Makefile.am delete mode 100644 libs/spandsp/tests/ademco_contactid_tests.c delete mode 100644 libs/spandsp/tests/adsi_tests.c delete mode 100644 libs/spandsp/tests/alloc_tests.c delete mode 100644 libs/spandsp/tests/async_tests.c delete mode 100644 libs/spandsp/tests/at_interpreter_tests.c delete mode 100644 libs/spandsp/tests/awgn_tests.c delete mode 100644 libs/spandsp/tests/bell_mf_rx_tests.c delete mode 100644 libs/spandsp/tests/bell_mf_tx_tests.c delete mode 100644 libs/spandsp/tests/bert_tests.c delete mode 100644 libs/spandsp/tests/bit_operations_tests.c delete mode 100644 libs/spandsp/tests/bitstream_tests.c delete mode 100644 libs/spandsp/tests/complex_tests.c delete mode 100644 libs/spandsp/tests/complex_vector_float_tests.c delete mode 100644 libs/spandsp/tests/complex_vector_int_tests.c delete mode 100644 libs/spandsp/tests/crc_tests.c delete mode 100644 libs/spandsp/tests/data_modems_tests.c delete mode 100644 libs/spandsp/tests/dc_restore_tests.c delete mode 100644 libs/spandsp/tests/dds_tests.c delete mode 100644 libs/spandsp/tests/dtmf_rx_tests.c delete mode 100644 libs/spandsp/tests/dtmf_tx_tests.c delete mode 100644 libs/spandsp/tests/dummy_modems_tests.c delete mode 100644 libs/spandsp/tests/echo_monitor.cpp delete mode 100644 libs/spandsp/tests/echo_monitor.h delete mode 100644 libs/spandsp/tests/echo_tests.c delete mode 100644 libs/spandsp/tests/fax_decode.c delete mode 100644 libs/spandsp/tests/fax_tester.c delete mode 100644 libs/spandsp/tests/fax_tester.h delete mode 100644 libs/spandsp/tests/fax_tests.c delete mode 100755 libs/spandsp/tests/fax_tests.sh delete mode 100644 libs/spandsp/tests/fax_utils.c delete mode 100644 libs/spandsp/tests/fax_utils.h delete mode 100644 libs/spandsp/tests/fsk_tests.c delete mode 100644 libs/spandsp/tests/g1050_tests.c delete mode 100644 libs/spandsp/tests/g168_tests.c delete mode 100644 libs/spandsp/tests/g711_tests.c delete mode 100644 libs/spandsp/tests/g722_tests.c delete mode 100644 libs/spandsp/tests/g726_tests.c delete mode 100644 libs/spandsp/tests/gsm0610_tests.c delete mode 100644 libs/spandsp/tests/hdlc_tests.c delete mode 100644 libs/spandsp/tests/ima_adpcm_tests.c delete mode 100644 libs/spandsp/tests/image_translate_tests.c delete mode 100644 libs/spandsp/tests/line_model_monitor.cpp delete mode 100644 libs/spandsp/tests/line_model_monitor.h delete mode 100644 libs/spandsp/tests/line_model_tests.c delete mode 100644 libs/spandsp/tests/logging_tests.c delete mode 100644 libs/spandsp/tests/lpc10_tests.c delete mode 100644 libs/spandsp/tests/make_g168_css.c delete mode 100644 libs/spandsp/tests/math_fixed_tests.c delete mode 100644 libs/spandsp/tests/media_monitor.cpp delete mode 100644 libs/spandsp/tests/media_monitor.h delete mode 100644 libs/spandsp/tests/modem_connect_tones_tests.c delete mode 100644 libs/spandsp/tests/modem_echo_tests.c delete mode 100644 libs/spandsp/tests/modem_monitor.cpp delete mode 100644 libs/spandsp/tests/modem_monitor.h delete mode 100644 libs/spandsp/tests/noise_tests.c delete mode 100644 libs/spandsp/tests/oki_adpcm_tests.c delete mode 100644 libs/spandsp/tests/pcap_parse.c delete mode 100644 libs/spandsp/tests/pcap_parse.h delete mode 100644 libs/spandsp/tests/playout_tests.c delete mode 100644 libs/spandsp/tests/plc_tests.c delete mode 100644 libs/spandsp/tests/power_meter_tests.c delete mode 100644 libs/spandsp/tests/pseudo_terminal_tests.c delete mode 100644 libs/spandsp/tests/pseudo_terminals.c delete mode 100644 libs/spandsp/tests/pseudo_terminals.h delete mode 100644 libs/spandsp/tests/queue_tests.c delete mode 100644 libs/spandsp/tests/r2_mf_rx_tests.c delete mode 100644 libs/spandsp/tests/r2_mf_tx_tests.c delete mode 100755 libs/spandsp/tests/regression_tests.sh delete mode 100644 libs/spandsp/tests/rfc2198_sim_tests.c delete mode 100644 libs/spandsp/tests/saturated_tests.c delete mode 100644 libs/spandsp/tests/schedule_tests.c delete mode 100644 libs/spandsp/tests/sig_tone_tests.c delete mode 100644 libs/spandsp/tests/socket_harness.c delete mode 100644 libs/spandsp/tests/socket_harness.h delete mode 100644 libs/spandsp/tests/super_tone_rx_tests.c delete mode 100644 libs/spandsp/tests/super_tone_tx_tests.c delete mode 100644 libs/spandsp/tests/swept_tone_tests.c delete mode 100644 libs/spandsp/tests/t31_pseudo_terminal_tests.c delete mode 100644 libs/spandsp/tests/t31_tests.c delete mode 100644 libs/spandsp/tests/t35_tests.c delete mode 100644 libs/spandsp/tests/t38_core_tests.c delete mode 100644 libs/spandsp/tests/t38_decode.c delete mode 100644 libs/spandsp/tests/t38_non_ecm_buffer_tests.c delete mode 100644 libs/spandsp/tests/t42_tests.c delete mode 100644 libs/spandsp/tests/t43_tests.c delete mode 100644 libs/spandsp/tests/t4_t6_tests.c delete mode 100644 libs/spandsp/tests/t4_tests.c delete mode 100644 libs/spandsp/tests/t81_t82_arith_coding_tests.c delete mode 100644 libs/spandsp/tests/t85_tests.c delete mode 100644 libs/spandsp/tests/testadsi.c delete mode 100644 libs/spandsp/tests/testfax.c delete mode 100644 libs/spandsp/tests/time_scale_tests.c delete mode 100644 libs/spandsp/tests/timezone_tests.c delete mode 100644 libs/spandsp/tests/tone_detect_tests.c delete mode 100644 libs/spandsp/tests/tone_generate_tests.c delete mode 100755 libs/spandsp/tests/tsb85_extra_tests.sh delete mode 100644 libs/spandsp/tests/tsb85_tests.c delete mode 100755 libs/spandsp/tests/tsb85_tests.sh delete mode 100644 libs/spandsp/tests/udptl.c delete mode 100644 libs/spandsp/tests/udptl.h delete mode 100644 libs/spandsp/tests/v17_tests.c delete mode 100755 libs/spandsp/tests/v17_tests.sh delete mode 100644 libs/spandsp/tests/v18_tests.c delete mode 100644 libs/spandsp/tests/v22bis_tests.c delete mode 100644 libs/spandsp/tests/v27ter_tests.c delete mode 100755 libs/spandsp/tests/v27ter_tests.sh delete mode 100644 libs/spandsp/tests/v29_tests.c delete mode 100755 libs/spandsp/tests/v29_tests.sh delete mode 100644 libs/spandsp/tests/v42_tests.c delete mode 100644 libs/spandsp/tests/v42bis_tests.c delete mode 100755 libs/spandsp/tests/v42bis_tests.sh delete mode 100644 libs/spandsp/tests/v8_tests.c delete mode 100644 libs/spandsp/tests/vector_float_tests.c delete mode 100644 libs/spandsp/tests/vector_int_tests.c delete mode 100755 libs/spandsp/unpack_g722_data.sh delete mode 100755 libs/spandsp/unpack_g726_data.sh delete mode 100755 libs/spandsp/unpack_gsm0610_data.sh delete mode 100755 libs/spandsp/unpack_v56ter_data.sh delete mode 100644 libs/spandsp/wrapper.xsl delete mode 100644 libs/spandsp/yum-prepare.sh rename libs/{spandsp/src => win32/libtiff}/libtiff.2017.vcxproj (100%) create mode 100644 libs/win32/spandsp/libspandsp.2017.vcxproj rename libs/{spandsp/src/msvc => win32/spandsp}/make_at_dictionary.2017.vcxproj (91%) rename libs/{spandsp/src/msvc => win32/spandsp}/make_cielab_luts.2017.vcxproj (92%) rename libs/{spandsp/src/msvc => win32/spandsp}/make_math_fixed_tables.2017.vcxproj (91%) rename libs/{spandsp/src/msvc => win32/spandsp}/make_modem_filter.2017.vcxproj (60%) rename libs/{spandsp/src/msvc => win32/spandsp}/make_t43_gray_code_tables.2017.vcxproj (91%) create mode 100644 w32/download_spandsp.props create mode 100644 w32/spandsp-version.props create mode 100644 w32/spandsp.props diff --git a/.drone.yml b/.drone.yml index f5cdd6d93c..486c2f8402 100644 --- a/.drone.yml +++ b/.drone.yml @@ -14,7 +14,7 @@ steps: image: signalwire/freeswitch-public-base pull: true commands: - - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp-dev - echo "applications/mod_test" >> modules.conf - echo 'codecs/mod_openh264' >> modules.conf - sed -i '/applications\\/mod_http_cache/s/^#//g' modules.conf @@ -28,7 +28,7 @@ steps: image: signalwire/freeswitch-public-base pull: true commands: - - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp-dev - echo '#!/bin/bash\nmake -j`nproc --all` |& tee ./unit-tests-build-result.txt\nexitstatus=$${PIPESTATUS[0]}\necho $$exitstatus > ./build-status.txt\n' > build.sh - chmod +x build.sh - ./build.sh @@ -37,7 +37,7 @@ steps: image: signalwire/freeswitch-public-base pull: true commands: - - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp-dev - make install || true - cd tests/unit - ./run-tests.sh @@ -83,7 +83,7 @@ steps: image: signalwire/freeswitch-public-base:stretch pull: true commands: - - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp-dev - cp build/modules.conf.most modules.conf #Enable/Uncomment mods - echo 'codecs/mod_openh264' >> modules.conf @@ -113,7 +113,7 @@ steps: image: signalwire/freeswitch-public-base:stretch pull: true commands: - - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp-dev - mkdir -p scan-build - echo '#!/bin/bash\nscan-build-4.0 -o ./scan-build/ make -j`nproc --all` |& tee ./scan-build-result.txt\nexitstatus=$${PIPESTATUS[0]}\necho $$exitstatus > ./scan-build-status.txt\n' > scan.sh - chmod +x scan.sh @@ -144,6 +144,6 @@ trigger: --- kind: signature -hmac: 9f536d54b3df4db408a9e23a412185d0c95e66d22d15ba7ff00c7cfc85bff3ab +hmac: c48137f0dee8c2825711979e2c490367a2467a92866d3dfa11cf340a113dbf53 ... diff --git a/.gitignore b/.gitignore index eef21da305..7ab54e9acf 100644 --- a/.gitignore +++ b/.gitignore @@ -142,7 +142,6 @@ Release/ /libs/libcodec2/unittest/Makefile /libs/libcodec2/unittest/Makefile.in /libs/mpg123-1.13.2/ -/libs/spandsp/src/cielab_luts.h /scripts/fsxs /scripts/gentls_cert diff --git a/Freeswitch.2017.sln b/Freeswitch.2017.sln index adad7bc73e..b708f4e9ca 100644 --- a/Freeswitch.2017.sln +++ b/Freeswitch.2017.sln @@ -342,9 +342,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_easyroute", "src\mod\ap EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_lcr", "src\mod\applications\mod_lcr\mod_lcr.2017.vcxproj", "{1A3793D1-05D1-4B57-9B0F-5AF3E79DC439}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "libs\spandsp\src\libtiff.2017.vcxproj", "{401A40CD-5DB4-4E34-AC68-FA99E9FAC014}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "libs\win32\libtiff\libtiff.2017.vcxproj", "{401A40CD-5DB4-4E34-AC68-FA99E9FAC014}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\spandsp\src\libspandsp.2017.vcxproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libs\win32\spandsp\libspandsp.2017.vcxproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspeex", "libs\win32\speex\libspeex.2017.vcxproj", "{E972C52F-9E85-4D65-B19C-031E511E9DB4}" EndProject @@ -358,9 +358,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skinny", "src\mod\endpo EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_rtmp", "src\mod\endpoints\mod_rtmp\mod_rtmp.2017.vcxproj", "{48414740-C693-4968-9846-EE058020C64F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "libs\spandsp\src\msvc\make_at_dictionary.2017.vcxproj", "{DEE932AB-5911-4700-9EEB-8C7090A0A330}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "libs\win32\spandsp\make_at_dictionary.2017.vcxproj", "{DEE932AB-5911-4700-9EEB-8C7090A0A330}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\spandsp\src\msvc\make_modem_filter.2017.vcxproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "libs\win32\spandsp\make_modem_filter.2017.vcxproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_skel", "src\mod\applications\mod_skel\mod_skel.2017.vcxproj", "{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}" EndProject @@ -484,11 +484,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltok", "libs\win32\xmlrpc EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup.2017", "w32\Setup\Setup.2017.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_math_fixed_tables", "libs\spandsp\src\msvc\make_math_fixed_tables.2017.vcxproj", "{2386B892-35F5-46CF-A0F0-10394D2FBF9B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_math_fixed_tables", "libs\win32\spandsp\make_math_fixed_tables.2017.vcxproj", "{2386B892-35F5-46CF-A0F0-10394D2FBF9B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcbt", "libs\win32\libcbt\libcbt.2017.vcxproj", "{77BC1DD2-C9A1-44D7-BFFA-1320370CACB9}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_cielab_luts", "libs\spandsp\src\msvc\make_cielab_luts.2017.vcxproj", "{85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_cielab_luts", "libs\win32\spandsp\make_cielab_luts.2017.vcxproj", "{85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "opus", "opus", "{ED2CA8B5-8E91-4296-A120-02BB0B674652}" EndProject @@ -504,7 +504,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus.silk_float", "libs\win EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_opus", "src\mod\codecs\mod_opus\mod_opus.2017.vcxproj", "{64E99CCA-3C6F-4AEB-9FA3-CFAC711257BB}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_t43_gray_code_tables", "libs\spandsp\src\msvc\make_t43_gray_code_tables.2017.vcxproj", "{EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_t43_gray_code_tables", "libs\win32\spandsp\make_t43_gray_code_tables.2017.vcxproj", "{EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winFailToBan", "src\mod\languages\mod_managed\managed\examples\winFailToBan\winFailToBan.csproj", "{5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}" EndProject diff --git a/Makefile.am b/Makefile.am index 566ada5a41..297c33b498 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,7 +130,7 @@ CORE_CFLAGS += -I$(switch_srcdir)/libs/libyuv/include CORE_CFLAGS += -DSWITCH_HAVE_YUV endif CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/crypto/include -Ilibs/srtp/crypto/include -CORE_CFLAGS += -I$(switch_builddir)/libs/spandsp/src -I$(switch_srcdir)/libs/spandsp/src +CORE_CFLAGS += $(SPANDSP_CFLAGS) if ENABLE_LIBVPX CORE_CFLAGS += -DSWITCH_HAVE_VPX endif @@ -184,13 +184,10 @@ endif ## ## libfreeswitch ## -noinst_LTLIBRARIES = libfreeswitch_spandsp.la +noinst_LTLIBRARIES = if ENABLE_LIBYUV noinst_LTLIBRARIES += libfreeswitch_libyuv.la endif -libfreeswitch_spandsp_la_SOURCES = libs/spandsp/src/plc.c libs/spandsp/src/alloc.c libs/spandsp/src/bit_operations.c -libfreeswitch_spandsp_la_CFLAGS = -Ilibs/spandsp/src $(CORE_CFLAGS) $(AM_CFLAGS) -CORE_LIBS+=libfreeswitch_spandsp.la if ENABLE_LIBYUV libfreeswitch_libyuv_la_SOURCES = \ @@ -251,7 +248,7 @@ endif lib_LTLIBRARIES = libfreeswitch.la libfreeswitch_la_CFLAGS = $(CORE_CFLAGS) $(SQLITE_CFLAGS) $(GUMBO_CFLAGS) $(FVAD_CFLAGS) $(FREETYPE_CFLAGS) $(CURL_CFLAGS) $(PCRE_CFLAGS) $(SPEEX_CFLAGS) $(LIBEDIT_CFLAGS) $(openssl_CFLAGS) $(AM_CFLAGS) $(TPL_CFLAGS) libfreeswitch_la_LDFLAGS = -version-info 1:0:0 $(AM_LDFLAGS) $(PLATFORM_CORE_LDFLAGS) -no-undefined -libfreeswitch_la_LIBADD = $(CORE_LIBS) $(APR_LIBS) $(SQLITE_LIBS) $(GUMBO_LIBS) $(FVAD_LIBS) $(FREETYPE_LIBS) $(CURL_LIBS) $(PCRE_LIBS) $(SPEEX_LIBS) $(LIBEDIT_LIBS) $(openssl_LIBS) $(PLATFORM_CORE_LIBS) $(TPL_LIBS) +libfreeswitch_la_LIBADD = $(CORE_LIBS) $(APR_LIBS) $(SQLITE_LIBS) $(GUMBO_LIBS) $(FVAD_LIBS) $(FREETYPE_LIBS) $(CURL_LIBS) $(PCRE_LIBS) $(SPEEX_LIBS) $(LIBEDIT_LIBS) $(openssl_LIBS) $(PLATFORM_CORE_LIBS) $(TPL_LIBS) $(SPANDSP_LIBS) libfreeswitch_la_DEPENDENCIES = $(BUILT_SOURCES) if HAVE_PNG @@ -713,9 +710,7 @@ core-install: core_install clean_core: clean-libLTLIBRARIES rm -f $(libfreeswitch_la_OBJECTS) - rm -f $(libfreeswitch_spandsp_la_OBJECTS) rm -f `echo $(libfreeswitch_la_OBJECTS) | sed -e's|.lo|.o|g'` - rm -f `echo $(libfreeswitch_spandsp_la_OBJECTS) | sed -e's|.lo|.o|g'` install_core: install-libLTLIBRARIES @@ -780,12 +775,6 @@ iks-reconf: cd libs/iksemel && sh ./configure.gnu $(MY_DEFAULT_ARGS) $(MAKE) mod_dingaling-clean -spandsp-reconf: - cd libs/spandsp && $(MAKE) clean || echo - cd libs/spandsp && autoreconf -fi - cd libs/spandsp && sh ./configure.gnu $(MY_DEFAULT_ARGS) - cd libs/spandsp && $(MAKE) - cluecon: @clear @echo Thank you for updating. This is going to take a while so relax. diff --git a/bootstrap.sh b/bootstrap.sh index 79d3f0d17e..6d8256aab1 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -8,7 +8,7 @@ BGJOB=false VERBOSE=false BASEDIR=`pwd`; LIBDIR=${BASEDIR}/libs; -SUBDIRS="apr libzrtp iksemel libdingaling srtp freetdm spandsp unimrcp fs"; +SUBDIRS="apr libzrtp iksemel libdingaling srtp freetdm unimrcp fs"; while getopts 'jhd:v' o; do case "$o" in diff --git a/configure.ac b/configure.ac index 23b741ea61..03058582ad 100644 --- a/configure.ac +++ b/configure.ac @@ -714,6 +714,11 @@ PKG_CHECK_MODULES([MARIADB], [libmariadb >= 3.0.9],[ ]) ]) +PKG_CHECK_MODULES([SPANDSP], [spandsp >= 1.99],[ + AM_CONDITIONAL([HAVE_SPANDSP],[true])],[ + AC_MSG_ERROR([no usable spandsp; please install spandsp devel package or equivalent]) +]) + PKG_CHECK_MODULES([SOFIA_SIP], [sofia-sip-ua >= 1.12.12],[ AM_CONDITIONAL([HAVE_SOFIA_SIP],[true])],[ AC_MSG_ERROR([no usable sofia-sip; please install sofia-sip-ua devel package or equivalent]) @@ -2111,7 +2116,6 @@ AC_CONFIG_SUBDIRS([libs/iksemel]) AC_CONFIG_SUBDIRS([libs/libdingaling]) AC_CONFIG_SUBDIRS([libs/freetdm]) AC_CONFIG_SUBDIRS([libs/unimrcp]) -AC_CONFIG_SUBDIRS([libs/spandsp]) if test "x${enable_zrtp}" = "xyes"; then AC_CONFIG_SUBDIRS([libs/libzrtp]) fi diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index 267bcd69ba..a5ac109d3a 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -333,6 +333,7 @@ Build-Depends: # used by many modules libcurl4-openssl-dev | libcurl4-gnutls-dev | libcurl-dev, bison, zlib1g-dev, libsofia-sip-ua-dev (>= 1.12.12), + libspandsp-dev (>= 1.99), # module build-depends $(debian_wrap "${mod_build_depends}") Standards-Version: 3.9.3 diff --git a/debian/copyright b/debian/copyright index eba56ce503..6745df1f35 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1310,45 +1310,6 @@ Files: libs/js/nsprpub/pr/tests/tmocon.c Copyright: 1998-2004 Netscape Communications Corporation License: MPL-1.1 or GPL-2+ -Files: libs/spandsp/* -Copyright: 2001-2012, Steve Underwood - 2006 Michael Jerris - 1991-1997 Silicon Graphics, Inc. - 1990-1997 Sam Leffler - 1993 CMU - 2004, Horizon Wimba, Inc. - 1990, 1995 Frank D. Cringle. -License: LGPL-2.1 - -Files: libs/spandsp/tests/* - libs/spandsp/spandsp-sim/g1050.c - libs/spandsp/spandsp-sim/line_model.c - libs/spandsp/spandsp-sim/make_line_models.c - libs/spandsp/spandsp-sim/spandsp-sim.h - libs/spandsp/spandsp-sim/test_utils.c - libs/spandsp/src/image_translate.c - libs/spandsp/src/make_at_dictionary.c - libs/spandsp/src/make_cielab_luts.c - libs/spandsp/src/make_math_fixed_tables.c - libs/spandsp/src/make_modem_filter.c - libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c - libs/spandsp/test-data/itu/fax/generate_dithered_tif.c - libs/spandsp/test-data/itu/fax/generate_sized_pages.c - libs/spandsp/test-data/itu/fax/generate_striped_pages.c -Copyright: 2001-2012, Steve Underwood -License: GPL-2 - -Files: libs/spandsp/tests/ademco_contactid_tests.c - libs/spandsp/tests/regression_tests.sh - libs/spandsp/tests/timezone_tests.c - libs/spandsp/tests/tsb85_extra_tests.sh - libs/spandsp/tests/tsb85_tests.c - libs/spandsp/tests/tsb85_tests.sh - libs/spandsp/tests/v42bis_tests.sh - libs/spandsp/tests/fax_tests.sh -Copyright: 2001-2012, Steve Underwood -License: LGPL-2.1 - Files: src/mod/applications/mod_cluechoo/sl.h Copyright: 1993 Toyoda Masashi License: FIXME @@ -1441,11 +1402,6 @@ Files: libs/libsndfile/src/G72x/* Copyright: Abandoned, Sun Microsystems, Inc. License: public-domain -Files: libs/spandsp/src/spandsp/fast_convert.h -Copyright: 2001-2004 Erik de Castro Lopo - 2009 Steve Underwood -License: LGPL-2.1 - Files: libs/libsndfile/* libs/win32/libsndfile/* Copyright: 1999-2009 Erik de Castro Lopo diff --git a/debian/license-reconcile.yml b/debian/license-reconcile.yml index c7add7837b..9cd5742d3f 100644 --- a/debian/license-reconcile.yml +++ b/debian/license-reconcile.yml @@ -162,15 +162,6 @@ Rules: Matches: the\sLicense\sat\shttp://www.mozilla.org/MPL/ Matches: GNU\sGeneral\sPublic\sLicense\sVersion\s2\sor\slater License: MPL-1.1 or GPL-2+ - - - Glob: libs/spandsp/tests/g726_tests.c - Matches: Copyright\s(C)\s2006\sSteve\sUnderwood - Matches: specification.\sThese\sare\scopyright\smaterial,\sand\sso\scannot\sbe\sdistributed\swith\sthis\stest\ssoftware. - Copyright: 2006 Steve Underwood - - - Glob: libs/spandsp/*/g722.[ch] - Matches: Copyright\s\(c\)\sCMU\s+1993 - Copyright: 1993 CMU - Glob: libs/libwebsockets/win32port/zlib/inftrees.c Matches: Copyright\s1995-2010\sMark\sAdler\s.; diff --git a/freeswitch.spec b/freeswitch.spec index 17eebfbf3f..e8bb6d64cf 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -153,6 +153,7 @@ BuildRequires: libtool >= 1.5.17 BuildRequires: ncurses-devel BuildRequires: openssl-devel >= 1.0.1e BuildRequires: sofia-sip-devel >= 1.12.12 +BuildRequires: spandsp-devel >= 1.99 BuildRequires: pcre-devel BuildRequires: speex-devel BuildRequires: sqlite-devel diff --git a/libs/.gitignore b/libs/.gitignore index 7e8bd3ce8a..392aaffdbd 100644 --- a/libs/.gitignore +++ b/libs/.gitignore @@ -486,70 +486,6 @@ opal /sounds/ /soundtouch/ /soundtouch-*/ -/spandsp/config-h.in -/spandsp/doc/doxygen -/spandsp/doc/Makefile -/spandsp/doc/Makefile.in -/spandsp/Makefile -/spandsp/Makefile.in -/spandsp/m4/libtool.m4 -/spandsp/m4/ltoptions.m4 -/spandsp/m4/ltsugar.m4 -/spandsp/m4/ltversion.m4 -/spandsp/m4/lt~obsolete.m4 -/spandsp/spandsp-sim/Makefile -/spandsp/spandsp-sim/Makefile.in -/spandsp/src/at_interpreter_dictionary.h -/spandsp/src/config.h -/spandsp/src/make_at_dictionary -/spandsp/src/Makefile -/spandsp/src/Makefile.in -/spandsp/src/make_math_fixed_tables -/spandsp/src/make_modem_filter -/spandsp/src/make_t43_gray_code_tables -/spandsp/src/math_fixed_tables.h -/spandsp/src/msvc/All/BuildLog make_at_dictionary.htm -/spandsp/src/msvc/All/BuildLog make_modem_filter.htm -/spandsp/src/spandsp.h -/spandsp/src/stamp-h1 -/spandsp/src/t43_gray_code_tables.h -/spandsp/src/v17_v32bis_rx_fixed_rrc.h -/spandsp/src/v17_v32bis_rx_floating_rrc.h -/spandsp/src/v17_v32bis_tx_fixed_rrc.h -/spandsp/src/v17_v32bis_tx_floating_rrc.h -/spandsp/src/v22bis_rx_1200_fixed_rrc.h -/spandsp/src/v22bis_rx_1200_floating_rrc.h -/spandsp/src/v22bis_rx_2400_fixed_rrc.h -/spandsp/src/v22bis_rx_2400_floating_rrc.h -/spandsp/src/v22bis_tx_fixed_rrc.h -/spandsp/src/v22bis_tx_floating_rrc.h -/spandsp/src/v27ter_rx_2400_fixed_rrc.h -/spandsp/src/v27ter_rx_2400_floating_rrc.h -/spandsp/src/v27ter_rx_4800_fixed_rrc.h -/spandsp/src/v27ter_rx_4800_floating_rrc.h -/spandsp/src/v27ter_tx_2400_fixed_rrc.h -/spandsp/src/v27ter_tx_2400_floating_rrc.h -/spandsp/src/v27ter_tx_4800_fixed_rrc.h -/spandsp/src/v27ter_tx_4800_floating_rrc.h -/spandsp/src/v29rx_fixed_rrc.h -/spandsp/src/v29rx_floating_rrc.h -/spandsp/src/v29tx_fixed_rrc.h -/spandsp/src/v29tx_floating_rrc.h -/spandsp/test-data/etsi/fax/Makefile -/spandsp/test-data/etsi/fax/Makefile.in -/spandsp/test-data/etsi/Makefile -/spandsp/test-data/etsi/Makefile.in -/spandsp/test-data/itu/fax/Makefile -/spandsp/test-data/itu/fax/Makefile.in -/spandsp/test-data/itu/Makefile -/spandsp/test-data/itu/Makefile.in -/spandsp/test-data/local/Makefile -/spandsp/test-data/local/Makefile.in -/spandsp/test-data/Makefile -/spandsp/test-data/Makefile.in -/spandsp/tests/Makefile -/spandsp/tests/Makefile.in -/spandsp/src/make_cielab_luts /sphinxbase-*/ /srtp/aes_tables /srtp/config_in.h @@ -819,7 +755,6 @@ broadvoice/config/compile ilbc/config/compile libg722_1/config/compile pcre/compile -spandsp/config/compile srtp/build/compile unimrcp/build/compile /pcre-*/ @@ -837,7 +772,6 @@ iksemel/configure libdingaling/configure libyuv/Makefile libyuv/convert -spandsp/configure srtp/configure tiff-4.0.2/configure unimrcp/configure @@ -863,3 +797,6 @@ signalwire-client-c-*/ signalwire-client-c-* mariadb-connector-c-*/ mariadb-connector-c-* +/spandsp*/ +/spandsp* +win32/spandsp/spandsp.h \ No newline at end of file diff --git a/libs/spandsp/.gitignore b/libs/spandsp/.gitignore deleted file mode 100644 index 9d3e352ee3..0000000000 --- a/libs/spandsp/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -src/v17_v32bis_rx_rrc.h -src/v17_v32bis_tx_rrc.h -src/v22bis_rx_1200_rrc.h -src/v22bis_rx_2400_rrc.h -src/v22bis_tx_rrc.h -src/v27ter_rx_2400_rrc.h -src/v27ter_rx_4800_rrc.h -src/v27ter_tx_2400_rrc.h -src/v27ter_tx_4800_rrc.h -src/v29rx_rrc.h -src/v29tx_rrc.h -INSTALL -test-data/itu/tiff-fx/Makefile -test-data/itu/tiff-fx/Makefile.in diff --git a/libs/spandsp/.update b/libs/spandsp/.update deleted file mode 100644 index 59c2e311b5..0000000000 --- a/libs/spandsp/.update +++ /dev/null @@ -1 +0,0 @@ -Tue Jul 22 07:25:58 CDT 2014 diff --git a/libs/spandsp/AUTHORS b/libs/spandsp/AUTHORS deleted file mode 100644 index 0fbb495099..0000000000 --- a/libs/spandsp/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Steve Underwood diff --git a/libs/spandsp/COPYING b/libs/spandsp/COPYING deleted file mode 100644 index 65263af281..0000000000 --- a/libs/spandsp/COPYING +++ /dev/null @@ -1,853 +0,0 @@ -The spandsp library is licenced under LGPL 2.1. The test suite, and some of -the supporting code, are licenced under GPL 2. The full text of both licences -may be found below. - - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - - - - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/libs/spandsp/ChangeLog b/libs/spandsp/ChangeLog deleted file mode 100644 index 99700a274d..0000000000 --- a/libs/spandsp/ChangeLog +++ /dev/null @@ -1,47 +0,0 @@ -07.08.29 - 0.0.4 - Steve Underwood - - - -06.05.23 - 0.0.3 - Steve Underwood - - T.38 now implemented, though it needs further polishing. - - G.726 and G.722 now implemented. - -04.08.29 - 0.0.2 - Steve Underwood - - T.4 no longer uses libtiff for compresion and decompression on the line side - (it is still used to handle the TIFF files). Spandsp no longer depends on - accessing the "internals" of libtiff. New 1D and 2D compression and - decompression code now handles the line side. This should be more robust than - using libtiff, and handles the fudging of bad scan lines rather better. - - T.30 line turn-around timing corrected. - - T.30 DCS header contents corrected. - - T.30 provision for V.17 added, as an option. - - T.30 now has a statistics interface, for applications to find details about - image transfers. - - T.30 processing now correctly closes TIFF files are they have been sent. - - FAX header line insertion is now supported for transmitted FAXes. - - asynchronous serial processing now has a V.14 compatible rate adaption option. - - V.8 modem negotiation module added. - - OKI ADPCM now supports Dialogic compatible operation at 6k samples/second, as - well as 8k samples/second, using its own sample rate converter. - - message queuing added to ease things like T.31 handling - - incomplete skeleton (still rather nasty, to be honest) T.31 processing. - - incomplete skeleton of V.22bis added. There is probably quite a bit to do - to get this complete and robust. It probably requires the T.31 processing - be expanded to something more like V.250, so it doesn't just handle FAX. - - Incomplete V.17 added (there could be an IBM patent related to the TCM part of - V.17, but I think it has expired. Don't distribute binaries of spandsp built - with V.17 enabled until this is resolved - and the modem is completed, of - course :-) ). The current version transmits OK. It receives OK with the - long training sequence, but the symbol and carrier syncing isn't good enough - for robust receiving with the short training sequence. - - A basic BER tester has been added. - - The faster modems now have proper shutdown procedures, whether one is defined in - the spec. or not. - - The modems (except simple FSK) now have APIs to access performance information. - - A common GUI (using FLTK) added for the modem tests. - - A bit more documentation added. - - Some API inconsistencies cleaned up. - - The usual bundle of assorted buglet fixes and polishing. - -04.04.29 - 0.0.1k - Steve Underwood - - The first version which gives solid faxing for a large number of people. - diff --git a/libs/spandsp/DueDiligence b/libs/spandsp/DueDiligence deleted file mode 100644 index 3cedc8806d..0000000000 --- a/libs/spandsp/DueDiligence +++ /dev/null @@ -1,55 +0,0 @@ -Intellectual Property Due Diligence ------------------------------------ - -Modems and voice coding are heavily patented areas. Implementing these without -serious consideration of IP issues would be foolish. This document describes -the basis on which the software has been implemented. - - -A check of the intellectual property information at the ITU web site shows a -number of patent claims against the current standards implemented by spandsp. -It is important to realise, however, that some of these patents have long -since expired (group III fax dates back to the 1970s). Also, many are -related to recent additions to the FAX standard, such as colour FAX handling, -which few people ever use. - -The V.14 rate adaption standard seems free of patent encumberance. - -One patent is listed as relevant to the V.17 standard. It is a patent from -IBM, but the ITU database does not specify its nature. I believe it is -related to the trellis coding used, and I think it has expired. I do not -know for sure. The techniques used in the implementation should be free of -patent encumberance. Most of the implementation is similar to the V.29 -modem. The key addition the trellis code processing. The trellis encoding -is trivial. The decoding uses Viterbi techniques, which are quite old. - -The V.21 standard dates from the 1950s. The V.23 standard is also very old. -There is no possibility that any patents related to it are still in force. -However, the implementation also needs to be free of patented techniques. -The implementation only uses very mature numerical oscillator and quadrature -correlation techniques, so there should be no patent issues. - -Only one patent is listed as relevant to the V.29 standard. This dates from -the 1970s, and must have expired. The modem has been implemented using only -very mature techniques, none of which can be less than 20 years old. There -seem no possibility, therefore, that any patents are still in force related -to the techniques used. - -Some aspect of the V.8 standard seems to have patents associated with it, -according to the ITU patent database. I am unclear what these are. V.8 is a -very simple standard. There seems to be nothing innovative about it. - -Many patents are listed as relevant to the T.30 standard. However, they all -appear to relate to newer features, such as colour FAX, added in recent years. -The current implementation only covers the original features from the late -1970s, where there appear to be patent issues. - -The T.4 standard defines the image compression and decompression techniques -used for group 3 FAXes. The spandsp implementation is based on code derived -from freely available implementations of T.4. These have existed for a number -of years without IP issues. The standard is old enough for any patents to have -expired, anyway. - -V.42bis compression uses the LZW algorithm. This is the same algorithm used in -GIF files. Unisys patented this algorithm. However, the Unisys patent has now -expired. diff --git a/libs/spandsp/Makefile.am b/libs/spandsp/Makefile.am deleted file mode 100644 index 6902c867c5..0000000000 --- a/libs/spandsp/Makefile.am +++ /dev/null @@ -1,91 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -ACLOCAL_AMFLAGS = -I m4 - -AM_CFLAGS = $(COMP_VENDOR_CFLAGS) -AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) - -noinst_SCRIPTS = spandsp.spec - -MAINTAINERCLEANFILES = Makefile.in - -EXTRA_DIST = autogen.sh \ - DueDiligence \ - debian/changelog \ - debian/compat \ - debian/control \ - debian/copyright \ - debian/libspandsp6.install \ - debian/libspandsp-dev.install \ - debian/libspandsp-doc.install \ - debian/rules \ - debian/watch \ - README.testdata \ - spandsp.spec \ - spandsp/fax-tests.dtd \ - spandsp/fax-tests.xml \ - spandsp/global-tones.xml \ - spandsp/tones.dtd \ - spandsp/tsb85.xml \ - unpack_g722_data.sh \ - unpack_g726_data.sh \ - unpack_gsm0610_data.sh \ - unpack_v56ter_data.sh \ - wrapper.xsl \ - yum-prepare.sh - -if COND_DOC - MAYBE_DOC=doc -endif -if COND_TESTS - MAYBE_TESTS=spandsp-sim test-data tests -endif -SUBDIRS = src $(MAYBE_DOC) $(MAYBE_TESTS) - -DIST_SUBDIRS = src doc test-data spandsp-sim tests - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = spandsp.pc - -faq: faq.xml - cd faq ; xsltproc ../wrapper.xsl ../faq.xml - -rpm: rpm-build - -rpm-build: - $(MAKE) -$(MAKEFLAGS) bump.rpm.release - $(MAKE) -$(MAKEFLAGS) dist - rm -rf rpm/BUILD/* - rm -f rpm/RPMS/*/* - rm -f rpm/SOURCES/* - rm -f rpm/SPECS/* - rm -f rpm/SRPMS/* - rpmbuild -ta --sign @PACKAGE@-@VERSION@.tar.gz - -bump.rpm.release: spandsp.spec - VERSION="x"; \ - test -f $(srcdir)/rpm.release && . $(srcdir)/rpm.release; \ - NEXT_RELEASE=0; \ - test "$$VERSION" = "@VERSION@" && NEXT_RELEASE="$$RELEASE"; \ - RELEASE=`expr $$NEXT_RELEASE + 1`; \ - echo "VERSION=@VERSION@" >$(srcdir)/rpm.release; \ - echo "RELEASE=$$RELEASE" >>$(srcdir)/rpm.release; \ - sed 's/^Release: .*/Release: '$$RELEASE'/' \ - spandsp.spec.new; \ - mv spandsp.spec.new spandsp.spec diff --git a/libs/spandsp/NEWS b/libs/spandsp/NEWS deleted file mode 100644 index 0d09503644..0000000000 --- a/libs/spandsp/NEWS +++ /dev/null @@ -1 +0,0 @@ -No news is good news! \ No newline at end of file diff --git a/libs/spandsp/README b/libs/spandsp/README deleted file mode 100644 index 3e900525e8..0000000000 --- a/libs/spandsp/README +++ /dev/null @@ -1,35 +0,0 @@ -spandsp 0.0.6 - A DSP library for telephony -------------------------------------------- - -SpanDSP is a library of DSP functions for telephony, in the 8000 sample per -second world of E1s, T1s, and higher order PCM channels. It contains low level -functions, such as basic filters. It also contains higher level functions, such -as cadenced supervisory tone detection, and a complete software FAX machine. -The software has been designed to avoid intellectual property issues, using -mature techniques where all relevant patents have expired. See the file -DueDiligence for important information about these intellectual property issues. - -The library is licenced under the LGPL 2.1 licence. The test suite, and some support -programs are licenced under the GPL 2 licence. The full text of these licences can -be found in the file COPYING. - -Dependencies ------------- - -spandsp depends on various other packages for various tasks. Most of these -dependencies relate to building the test suite. - -libtiff (and libtiff-devel on most Linux distributions) is required to -build the spandsp library. - -libaudiofile (and libaudiofile-devel) is required to build the test suite -fftw (and fftw-devel) is required to build the test suite. Version 2 or 3 of -FFTW may be used. Spandsp adapts to the differences between them. - -fltk (and fltk-devel), Fl_Cartesian and Fl_Audio_Meter are required to build -the test suite with GUI interfaces for some of the tests. The tests will build -without these packages, but the GUI features will not be available. -Fl_Cartesian and Fl_Audio_Meter can be downloaded from -http://www.soft-switch.org/downloads. - -Steve Underwood diff --git a/libs/spandsp/README.testdata b/libs/spandsp/README.testdata deleted file mode 100644 index c0d2959ef9..0000000000 --- a/libs/spandsp/README.testdata +++ /dev/null @@ -1,53 +0,0 @@ -Setting up test data for the supplied suite of test programs. -------------------------------------------------------------- - -Some of the tests in the test suite for this package require test data files. These test -data files fall into four categories: - - - Some data files, such as those for some of the FAX tests, are generated by programs - in the package. - - - Some are freely distributable data files, from various sources. These are supplied - with the package. - - - Some are test data files from a standards body. These are the copyright material of - the standards body, and so cannot be distributed with this package. However, most of - these files can currently be downloaded at no charge from the standards body's web - site. This file describes which files are needed, and how they may be processed to - produce the right files in the right places for the tests. - - - The two industry standard sources of test data for DTMF decoders are Bellcore/Telcordia - and Mitel. Neither of these is either free, or supplied in a form directly usable - with the test suite. These data sources are expected by several tests, and not just - the DTMF decoder tests. Sad to say, you are on your own when trying to source data - for these tests. - -For the G.722 tests, obtain the file T-REC-G.722-198703-I!AppII!ZPF-E.zip from the ITU web site, -and place it in this directory. Then run - -./unpack_g722_data.sh - -For the G.726 tests, obtain the file T-REC-G.726-199103-I!AppII!SOFT-ZST-E.zip from the ITU web -site, and place it in this directory. Then run - -./unpack_g726_data.sh - -For the GSM 06.10 tests, obtain the file en_300961v080101p0.zip from the ETSI web site, -and place it in this directory. If you are able to run .exe (i.e. MS DOS or Windows) -files you can simply run - -./unpack_gsm0610_data.sh - -If you are unable to run .exe files on the machine you are using (e.e. you are not using Cygwin, -Mingw, Wine, FreeDOS or something of that sort) you will need to find a machine which will. First, -run - -./unpack_gsm0610_data.sh --no-exe - -This will leave 6 .EXE files in the etsitetss/gsm0610 directory. Take these to a machine which -can run .EXE files, and execute all of them. This should result in a number of files which end -with .COD, INP and .OUT. Copy these to the etsitests/gsm0610 directory, and run - -./unpack_gsm0610_data.sh --no-exe-continue - -The remainder of the extraction and repacking of files should then take place. diff --git a/libs/spandsp/autogen.sh b/libs/spandsp/autogen.sh deleted file mode 100755 index c3cc88b04a..0000000000 --- a/libs/spandsp/autogen.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env sh -# -# SpanDSP - a series of DSP components for telephony -# -# autogen script -# -# 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 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. - -UNAME=`uname` - -if [ "x$UNAME" = "xFreeBSD" ]; then - echo "" - echo "" - echo "******************************************" - echo "*** NOTICE ***" - echo "******************************************" - echo " " - echo "FreeBSD is buggy. Please use this " - echo "workaround if you want to bootstrap " - echo "on FreeBSD. " - echo " " - echo "cd /usr/local/share/aclocal19 " - echo "ln -s ../aclocal/libtool15.m4 . " - echo "ln -s ../aclocal/ltdl15.m4 . " - echo " " - echo "******************************************" - echo "" -fi - -debug () -{ - # Outputs debug statments if DEBUG var is set - if [ ! -z "$DEBUG" ]; then - echo "DEBUG: $1" - fi -} - -version_compare() -{ - # Checks a command is found and the version is high enough - PROGRAM=$1 - MAJOR=$2 - MINOR=$3 - MICRO=$4 - test -z "$MAJOR" && MAJOR=0 - test -z "$MINOR" && MINOR=0 - test -z "$MICRO" && MICRO=0 - - debug "Checking $PROGRAM >= $MAJOR.$MINOR.$MICRO" - - WHICH_PATH=`whereis which | cut -f2 -d' '` - COMMAND=`$WHICH_PATH $PROGRAM` - if [ -z $COMMAND ]; then - echo "$PROGRAM-$MAJOR.$MINOR.$MICRO is required and was not found." - return 1 - else - debug "Found $COMMAND" - fi - - INS_VER=`$COMMAND --version | head -1 | sed 's/[^0-9]*//' | cut -d' ' -f1` - INS_MAJOR=`echo $INS_VER | cut -d. -f1 | sed s/[a-zA-Z\-].*//g` - INS_MINOR=`echo $INS_VER | cut -d. -f2 | sed s/[a-zA-Z\-].*//g` - INS_MICRO=`echo $INS_VER | cut -d. -f3 | sed s/[a-zA-Z\-].*//g` - test -z "$INS_MAJOR" && INS_MAJOR=0 - test -z "$INS_MINOR" && INS_MINOR=0 - test -z "$INS_MICRO" && INS_MICRO=0 - debug "Installed version: $INS_VER" - - if [ "$INS_MAJOR" -gt "$MAJOR" ]; then - debug "MAJOR: $INS_MAJOR > $MAJOR" - return 0 - elif [ "$INS_MAJOR" -eq "$MAJOR" ]; then - debug "MAJOR: $INS_MAJOR = $MAJOR" - if [ "$INS_MINOR" -gt "$MINOR" ]; then - debug "MINOR: $INS_MINOR > $MINOR" - return 0 - elif [ "$INS_MINOR" -eq "$MINOR" ]; then - if [ "$INS_MICRO" -ge "$MICRO" ]; then - debug "MICRO: $INS_MICRO >= $MICRO" - return 0 - else - debug "MICRO: $INS_MICRO < $MICRO" - fi - else - debug "MINOR: $INS_MINOR < $MINOR" - fi - else - debug "MAJOR: $INS_MAJOR < $MAJOR" - fi - - echo "You have the wrong version of $PROGRAM. The minimum required version is $MAJOR.$MINOR.$MICRO" - echo " and the version installed is $INS_MAJOR.$INS_MINOR.$INS_MICRO ($COMMAND)." - return 1 -} - -# Check for required version and die if unhappy - -mkdir config - -if [ "x$UNAME" = "xFreeBSD" ]; then -version_compare libtoolize 1 5 16 || exit 1 -version_compare automake19 1 9 5 || exit 1 -version_compare autoconf259 2 59 || exit 1 -else -version_compare libtoolize 1 5 16 || exit 1 -version_compare automake 1 9 5 || exit 1 -version_compare autoconf 2 59 || exit 1 -fi - -autoreconf -fi - -#chmod ug+x debian/rules - -if [ "x$UNAME" = "xNetBSD" ]; then -echo "" -echo "Please remember to run gmake instead of make on NetBSD" -echo "" -fi diff --git a/libs/spandsp/config/.empty b/libs/spandsp/config/.empty deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/spandsp/configure.ac b/libs/spandsp/configure.ac deleted file mode 100644 index 92354bd246..0000000000 --- a/libs/spandsp/configure.ac +++ /dev/null @@ -1,646 +0,0 @@ -# -# SpanDSP - a series of DSP components for telephony -# -# configure.ac - Process this file with autoconf to produce configure -# -# 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. - -# @start 1 - -AC_PREREQ([2.59]) -AC_INIT([spandsp], [1.99.0]) - -CFLAGS="$CFLAGS $CONFIGURE_CFLAGS" -CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS" -LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS" - -SPANDSP_LT_CURRENT=3 -SPANDSP_LT_REVISION=0 -SPANDSP_LT_AGE=0 - -m4_include(m4/ax_compiler_vendor.m4) -m4_include(m4/ax_check_real_file.m4) -m4_include(m4/ax_fixed_point_machine.m4) -m4_include(m4/ax_misaligned_access_fails.m4) -m4_include(m4/ax_c99_features.m4) -m4_include(m4/ax_check_export_capability.m4) -m4_include(m4/ax_check_arm_neon.m4) -m4_include(m4/ax_func_aligned_alloc.m4) -m4_include(m4/ac_func_memmove.m4) - -AC_CONFIG_SRCDIR([src/tone_generate.c]) -AC_CONFIG_AUX_DIR([config]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADERS([src/config.h:config-h.in]) -AM_INIT_AUTOMAKE([1.9.5]) - -AC_CANONICAL_HOST -#AC_CANONICAL_BUILD -AC_PROG_CC -AC_PROG_CXX -AC_PROG_GCC_TRADITIONAL -AC_PROG_LIBTOOL -AC_LANG([C]) - -AX_COMPILER_VENDOR - -if test "${build}" != "${host}" -then - # If we are doing a Canadian Cross, in which the host and build systems - # are not the same, we set reasonable default values for the tools. - - CC_FOR_BUILD=${CC_FOR_BUILD-gcc} - CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)" - CC=${CC-${host_alias}-gcc} - CFLAGS=${CFLAGS-"-g -O2"} - CXX=${CXX-${host_alias}-c++} - CXXFLAGS=${CXXFLAGS-"-g -O2"} -else - # Set reasonable default values for some tools even if not Canadian. - # Of course, these are different reasonable default values, originally - # specified directly in the Makefile. - # We don't export, so that autoconf can do its job. - # Note that all these settings are above the fragment inclusion point - # in Makefile.in, so can still be overridden by fragments. - # This is all going to change when we autoconfiscate... - CC_FOR_BUILD="\$(CC)" - CPPFLAGS_FOR_BUILD="\$(CPPFLAGS)" - AC_PROG_CC - - # We must set the default linker to the linker used by gcc for the correct - # operation of libtool. If LD is not defined and we are using gcc, try to - # set the LD default to the ld used by gcc. - if test -z "$LD" - then - if test "$GCC" = yes - then - case $build in - *-*-mingw*) - gcc_prog_ld=`$CC -print-prog-name=ld 2>&1 | tr -d '\015'` ;; - *) - gcc_prog_ld=`$CC -print-prog-name=ld 2>&1` ;; - esac - case $gcc_prog_ld in - # Accept absolute paths. - [[\\/]* | [A-Za-z]:[\\/]*)] - LD="$gcc_prog_ld" ;; - esac - fi - fi - - CXX=${CXX-"c++"} - CFLAGS=${CFLAGS-"-g -O2"} - CXXFLAGS=${CXXFLAGS-"-g -O2"} -fi - -AC_DEFUN([REMOVE_FROM_VAR],[ - new_val="" - removed=0 - for i in $$1; do - if test "x$i" != "x$2"; then - new_val="$new_val $i" - else - removed=1 - fi - done - if test $removed = "1"; then - echo " removed \"$2\" from $1" - $1=$new_val - fi -]) - -AC_C_CONST -AC_C_INLINE -AC_C_VOLATILE - -AC_CHECK_TYPES(long long) -AC_CHECK_TYPES(long double) - -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(mmx, [ --enable-mmx Enable MMX support]) -AC_ARG_ENABLE(sse, [ --enable-sse Enable SSE support]) -AC_ARG_ENABLE(sse2, [ --enable-sse2 Enable SSE2 support]) -AC_ARG_ENABLE(sse3, [ --enable-sse3 Enable SSE3 support]) -AC_ARG_ENABLE(ssse3, [ --enable-ssse3 Enable SSSE3 support]) -AC_ARG_ENABLE(sse4_1, [ --enable-sse4-1 Enable SSE4.1 support]) -AC_ARG_ENABLE(sse4_2, [ --enable-sse4-2 Enable SSE4.2 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]) -AC_ARG_ENABLE(v32bis, [ --enable-v32bis Enable V.32bis support]) -AC_ARG_ENABLE(v34, [ --enable-v34 Enable V.34 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"]) - -AC_FUNC_ERROR_AT_LINE -AC_FUNC_VPRINTF -AC_FUNC_MEMCMP -AC_FUNC_MEMMOVE - -AC_FUNC_SELECT_ARGTYPES - -AX_C99_FUNC_LRINT -AX_C99_FUNC_LRINTF -AX_C99_FUNC_LLRINT -AX_C99_FUNC_LLRINTF - -if test "x$ac_cv_c99_lrint" = "xno" ; then - if test "x$ac_cv_c99_lrintf" = "xno" ; then - AC_MSG_WARN([[*** Missing C99 standard functions lrint() and lrintf().]]) - AC_MSG_WARN([[*** This may cause benign compiler warnings on some systems (ie Solaris).]]) - fi -fi - -AX_C99_FLEXIBLE_ARRAY - -AX_FUNC_ALIGNED_ALLOC -AC_CHECK_FUNCS([memalign]) -AC_CHECK_FUNCS([posix_memalign]) -AC_CHECK_FUNCS([memmove]) -AC_CHECK_FUNCS([memset]) -AC_CHECK_FUNCS([select]) -AC_CHECK_FUNCS([strcasecmp]) -AC_CHECK_FUNCS([strchr]) -AC_CHECK_FUNCS([strdup]) -AC_CHECK_FUNCS([strerror]) -AC_CHECK_FUNCS([strstr]) -AC_CHECK_FUNCS([strtol]) -AC_CHECK_FUNCS([gettimeofday]) -AC_CHECK_FUNCS([drand48]) - -AC_HEADER_STDC -AC_HEADER_SYS_WAIT -AC_HEADER_TIME - -# Check for header files. -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]) -AC_CHECK_HEADERS([strings.h]) -AC_CHECK_HEADERS([malloc.h]) -AC_CHECK_HEADERS([math.h], [INSERT_MATH_HEADER="#include "]) -AC_CHECK_HEADERS([float.h]) -AC_CHECK_HEADERS([fcntl.h]) -AC_CHECK_HEADERS([sys/time.h]) -AC_CHECK_HEADERS([sys/select.h]) -AC_CHECK_HEADERS([sys/ioctl.h]) -AC_CHECK_HEADERS([sys/fcntl.h]) -AC_CHECK_HEADERS([sndfile.h]) -AC_CHECK_HEADERS([fenv.h]) -AC_CHECK_HEADERS([fftw3.h], , [AC_CHECK_HEADERS([fftw.h])]) -AC_CHECK_HEADERS([pcap.h]) -AC_CHECK_HEADERS([pthread.h]) - -case "$host" in - *dragonfly*) - ;; - *freebsd*) - ;; - *netbsd*) - ;; - *) - AC_CHECK_HEADERS([tgmath.h], [INSERT_TGMATH_HEADER="#include "]) - ;; -esac - -if test "${build}" = "${host}" -then - AC_CHECK_HEADERS([X11/X.h]) -fi - -# Determine XML2 include path -AC_MSG_CHECKING(for libxml/xmlmemory.h) - -# Can we include headers using system include dirs? -AC_TRY_COMPILE([#include ], [int a = 1;], - XML2_INCLUDE=" ", - XML2_INCLUDE= -) - -# Hunt through several possible directories to find the includes for libxml2 -if test "x$XML2_INCLUDE" = "x"; then - old_CPPFLAGS="$CPPFLAGS" - for i in $xml2_include_dir /usr/include /usr/local/include /usr/include/libxml2 /usr/local/include/libxml2 ; do - CPPFLAGS="$old_CPPFLAGS -I$i" - AC_TRY_COMPILE([#include ], [int a = 1;], - XML2_INCLUDE="-I$i", - XML2_INCLUDE= - ) - if test "x$XML2_INCLUDE" != "x"; then - break; - fi - done - CPPFLAGS="$old_CPPFLAGS $XML2_INCLUDE" -fi - -AC_CHECK_HEADERS([libxml/xmlmemory.h]) -AC_CHECK_HEADERS([libxml/parser.h]) -AC_CHECK_HEADERS([libxml/xinclude.h]) - -AC_LANG([C++]) -AC_CHECK_HEADERS([FL/Fl.H]) -AC_CHECK_HEADERS([FL/Fl_Overlay_Window.H]) -AC_CHECK_HEADERS([FL/Fl_Light_Button.H]) -AC_CHECK_HEADERS([FL/fl_draw.H]) -AC_CHECK_HEADERS([FL/Fl_Cartesian.H]) -AC_CHECK_HEADERS([FL/Fl_Audio_Meter.H]) - -AC_LANG([C]) - -if test "${build}" = "${host}" -then - case "${host}" in - x86_64-*) - # X86_64 Linux machines may have both 64 bit and 32 bit libraries. We need to choose the right set - AX_CHECK_REAL_FILE([${prefix}/lib64], libdir='${exec_prefix}/lib64') - AX_CHECK_REAL_FILE([/usr/X11R6/lib64], [TESTLIBS="$TESTLIBS -L/usr/X11R6/lib64"], AC_CHECK_FILE([/usr/X11R6/lib], [TESTLIBS="$TESTLIBS -L/usr/X11R6/lib"])) - # The very oldest AMD 64 bit chips support SSE2, SSE and MMX - enable_sse2="yes" - ;; - esac -fi - -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.])) -AC_SEARCH_LIBS([cosf], [m], AC_DEFINE([HAVE_COSF], [1], [Define to 1 if you have the cosf() function.])) -AC_SEARCH_LIBS([tanf], [m], AC_DEFINE([HAVE_TANF], [1], [Define to 1 if you have the tanf() function.])) -AC_SEARCH_LIBS([asinf], [m], AC_DEFINE([HAVE_ASINF], [1], [Define to 1 if you have the asinf() function.])) -AC_SEARCH_LIBS([acosf], [m], AC_DEFINE([HAVE_ACOSF], [1], [Define to 1 if you have the acosf() function.])) -AC_SEARCH_LIBS([atanf], [m], AC_DEFINE([HAVE_ATANF], [1], [Define to 1 if you have the atanf() function.])) -AC_SEARCH_LIBS([atan2f], [m], AC_DEFINE([HAVE_ATAN2F], [1], [Define to 1 if you have the atan2f() function.])) -AC_SEARCH_LIBS([ceilf], [m], AC_DEFINE([HAVE_CEILF], [1], [Define to 1 if you have the ceilf() function.])) -AC_SEARCH_LIBS([floorf], [m], AC_DEFINE([HAVE_FLOORF], [1], [Define to 1 if you have the floorf() function.])) -AC_SEARCH_LIBS([powf], [m], AC_DEFINE([HAVE_POWF], [1], [Define to 1 if you have the powf() function.])) -AC_SEARCH_LIBS([expf], [m], AC_DEFINE([HAVE_EXPF], [1], [Define to 1 if you have the expf() function.])) -AC_SEARCH_LIBS([logf], [m], AC_DEFINE([HAVE_LOGF], [1], [Define to 1 if you have the logf() function.])) -AC_SEARCH_LIBS([log10f], [m], AC_DEFINE([HAVE_LOG10F], [1], [Define to 1 if you have the log10f() function.])) - -AC_SEARCH_LIBS([open_memstream], [m], AC_DEFINE([HAVE_OPEN_MEMSTREAM], [1], [Define to 1 if you have the open_memstream() function.])) - -if test -n "$enable_tests" ; then - AC_CHECK_PROG([HAVE_SOX], [sox], yes) - if test "x$HAVE_SOX" != "xyes" ; then - AC_MSG_ERROR("Cannot make tests without sox installed") - fi - AC_CHECK_PROG([HAVE_PBMTOG3], [pbmtog3], yes) - if test "x$HAVE_PBMTOG3" != "xyes" ; then - AC_MSG_ERROR("Cannot make tests without pbmtog3 installed (does your system require a netpbm-progs package?)") - fi - AC_CHECK_PROG([HAVE_FAX2TIFF], [fax2tiff], yes) - if test "x$HAVE_FAX2TIFF" != "xyes" ; then - AC_MSG_ERROR("Cannot make tests without fax2tiff installed (does your system require a libtiff-tools package?)") - fi - AC_LANG([C]) - # Checks for libraries. - AC_CHECK_LIB([sndfile], [sf_open], SIMLIBS="$SIMLIBS -lsndfile", AC_MSG_ERROR("Cannot make tests without libsndfile (does your system require a libsndfile-devel package?)")) - AC_CHECK_LIB([fftw3], [fftw_plan_dft_1d], SIMLIBS="$SIMLIBS -lfftw3", [AC_CHECK_LIB([fftw], [fftw_create_plan], SIMLIBS="$SIMLIBS -lfftw", AC_MSG_ERROR("Cannot make tests without FFTW 2 or 3 (does your system require an fftw?-devel package?)"))]) - AC_CHECK_LIB([xml2], [xmlParseFile], TESTLIBS="$TESTLIBS -lxml2", AC_MSG_ERROR("Cannot make tests without libxml2 (does your system require a libxml2-devel package?)")) - AC_CHECK_LIB([pcap], [pcap_open_offline], TESTLIBS="$TESTLIBS -lpcap", [AC_CHECK_LIB([wpcap], [pcap_open_offline], TESTLIBS="$TESTLIBS -lwpcap", AC_MSG_ERROR("Cannot make tests without libpcap (does your system require an libpcap-devel package?)"))]) - AC_CHECK_LIB([pthread], [pthread_attr_init], TESTLIBS="$TESTLIBS -lpthread") - AC_CHECK_LIB([dl], [dlopen], TESTLIBS="$TESTLIBS -ldl") - AC_CHECK_LIB([Xft], [XftFontOpen], TESTLIBS="$TESTLIBS -lXft",, $TESTLIBS) - AC_CHECK_LIB([Xext], [XextCreateExtension], TESTLIBS="$TESTLIBS -lXext",, $TESTLIBS) - AC_CHECK_LIB([X11], [XOpenDisplay], TESTLIBS="$TESTLIBS -lX11",, $TESTLIBS) - AC_LANG([C++]) - AC_CHECK_LIB([fltk], [main], TESTLIBS="$TESTLIBS -lfltk -lsupc++",, $TESTLIBS) - AC_CHECK_LIB([fltk_cartesian], [main], TESTLIBS="-lfltk_cartesian $TESTLIBS",, $TESTLIBS) - AC_CHECK_LIB([fltk_audio_meter], [main], TESTLIBS="-lfltk_audio_meter $TESTLIBS",, $TESTLIBS) - AC_LANG([C]) -fi - -AX_CHECK_EXPORT_CAPABILITY([$host], - [AC_DEFINE([SPANDSP_USE_EXPORT_CAPABILITY], [1], [Use the library symbol export capability of the compiler]) - SPANDSP_USE_EXPORT_CAPABILITY="#define SPANDSP_USE_EXPORT_CAPABILITY 1"], - [SPANDSP_USE_EXPORT_CAPABILITY="#undef SPANDSP_USE_EXPORT_CAPABILITY"]) - -saved_CFLAGS="$CFLAGS" -AC_CACHE_CHECK([whether compiler supports -Wunused-but-set-variable], [ac_cv_gcc_unused_but_set_variable], [ - # 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" - -case "${ax_cv_c_compiler_vendor}" in -gnu) - COMP_VENDOR_CFLAGS="-std=gnu99 -ffast-math -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes $COMP_VENDOR_CFLAGS" - if test x"$ac_cv_gcc_unused_but_set_variable" = xyes ; then - COMP_VENDOR_CFLAGS="-Wunused-but-set-variable $COMP_VENDOR_CFLAGS" - fi - AX_CHECK_ARM_NEON([$host], - [AC_DEFINE([SPANDSP_USE_ARM_NEON], [1], [Use the ARM NEON instruction set])]) - 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 - if test "$enable_sse4_2" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse4.2 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse4_1" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse4.1 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_ssse3" = "yes" ; then - COMP_VENDOR_CFLAGS="-mssse3 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse3" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse3 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse2" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse2 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse $COMP_VENDOR_CFLAGS" - fi - if test "$enable_mmx" = "yes" ; then - COMP_VENDOR_CFLAGS="-mmmx $COMP_VENDOR_CFLAGS" - fi - case $host_os in - cygwin*) - COMP_VENDOR_LDFLAGS="-no-undefined" - ;; - mingw*) - COMP_VENDOR_LDFLAGS="-no-undefined -lws2_32" - ;; - *) - COMP_VENDOR_LDFLAGS= - ;; - esac - ;; -sun) - COMP_VENDOR_CFLAGS="-xc99=all -mt -xCC -errwarn=%all -xvpara $COMP_VENDOR_CFLAGS" - if test "$enable_sse3" = "yes" ; then - COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse2" = "yes" ; then - COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse" = "yes" ; then - COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS" - fi - if test "$enable_mmx" = "yes" ; then - COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS" - fi - COMP_VENDOR_LDFLAGS= - REMOVE_FROM_VAR(CFLAGS, -Xc) - ;; -intel) - COMP_VENDOR_CFLAGS="-std=c99 -D_POSIX_C_SOURCE=2 -D_GNU_SOURCE=1 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes $COMP_VENDOR_CFLAGS" - 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 - if test "$enable_sse4_2" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse4.2 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse4_1" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse4.1 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_ssse3" = "yes" ; then - COMP_VENDOR_CFLAGS="-mssse3 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse3" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse3 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse2" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse2 $COMP_VENDOR_CFLAGS" - fi - if test "$enable_sse" = "yes" ; then - COMP_VENDOR_CFLAGS="-msse $COMP_VENDOR_CFLAGS" - fi - if test "$enable_mmx" = "yes" ; then - COMP_VENDOR_CFLAGS="-mmmx $COMP_VENDOR_CFLAGS" - fi - COMP_VENDOR_LDFLAGS= - ;; -clang*) - COMP_VENDOR_CFLAGS="-D_XOPEN_SOURCE=700 -std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes $COMP_VENDOR_CFLAGS" - if test x"$ac_cv_gcc_unused_but_set_variable" = xyes ; then - COMP_VENDOR_CFLAGS="-Wunused-but-set-variable $COMP_VENDOR_CFLAGS" - fi - COMP_VENDOR_LDFLAGS= - ;; -*) - COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes $COMP_VENDOR_CFLAGS" - if test x"$ac_cv_gcc_unused_but_set_variable" = xyes ; then - COMP_VENDOR_CFLAGS="-Wunused-but-set-variable $COMP_VENDOR_CFLAGS" - fi - COMP_VENDOR_LDFLAGS= - ;; -esac - -COMP_VENDOR_CFLAGS="-DNDEBUG $COMP_VENDOR_CFLAGS" - -if test "$enable_fixed_point" = "yes" ; then - AC_DEFINE([SPANDSP_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) - SPANDSP_USE_FIXED_POINT="#define SPANDSP_USE_FIXED_POINT 1" -else - AX_FIXED_POINT_MACHINE([$host], - [AC_DEFINE([SPANDSP_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) - SPANDSP_USE_FIXED_POINT="#define SPANDSP_USE_FIXED_POINT 1"], - [SPANDSP_USE_FIXED_POINT="#undef SPANDSP_USE_FIXED_POINT"]) -fi -AX_MISALIGNED_ACCESS_FAILS([$host], - [AC_DEFINE([SPANDSP_MISALIGNED_ACCESS_FAILS], [1], [Do not expect a misaligned memory access to work correctly]) - SPANDSP_MISALIGNED_ACCESS_FAILS="#define SPANDSP_MISALIGNED_ACCESS_FAILS 1"], - [SPANDSP_MISALIGNED_ACCESS_FAILS="#undef SPANDSP_MISALIGNED_ACCESS_FAILS"]) - -case "${host}" in -armv7[bl] | armv7-*) - if test "$enable_neon" = "yes" ; then - AC_DEFINE([SPANDSP_USE_ARM_NEON], [1], [Use the NEON instruction set (ARMV7 only).]) - 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_sse4_2="yes" - fi - if test "$enable_sse4_2" = "yes" ; then - AC_DEFINE([SPANDSP_USE_SSE4_2], [1], [Use the SSE4.2 instruction set (i386 and x86_64 only).]) - enable_sse4_1="yes" - fi - if test "$enable_sse4_1" = "yes" ; then - AC_DEFINE([SPANDSP_USE_SSE4_1], [1], [Use the SSE4.1 instruction set (i386 and x86_64 only).]) - enable_ssse3="yes" - fi - if test "$enable_ssse3" = "yes" ; then - AC_DEFINE([SPANDSP_USE_SSSE3], [1], [Use the SSSE3 instruction set (i386 and x86_64 only).]) - enable_sse3="yes" - fi - if test "$enable_sse3" = "yes" ; then - AC_DEFINE([SPANDSP_USE_SSE3], [1], [Use the SSE3 instruction set (i386 and x86_64 only).]) - enable_sse2="yes" - fi - if test "$enable_sse2" = "yes" ; then - AC_DEFINE([SPANDSP_USE_SSE2], [1], [Use the SSE2 instruction set (i386 and x86_64 only).]) - enable_sse="yes" - fi - if test "$enable_sse" = "yes" ; then - AC_DEFINE([SPANDSP_USE_SSE], [1], [Use the SSE instruction set (i386 and x86_64 only).]) - enable_mmx="yes" - fi - if test "$enable_mmx" = "yes" ; then - AC_DEFINE([SPANDSP_USE_MMX], [1], [Use the MMX instruction set (i386 and x86_64 only).]) - fi - ;; -esac - -case "$host" in - *bsd*) - CFLAGS="$CFLAGS -I/usr/local/include" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - ;; -esac - -if test "$enable_builtin_tiff" = "yes" ; then - abs_tiffdir="`cd ../tiff-4.0.2/ && pwd`" - save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -I$abs_tiffdir/libtiff" - AC_CHECK_HEADERS([tiffio.h]) - AC_CHECK_HEADERS([tif_dir.h], [], [], [#include -]) - CFLAGS="$save_CFLAGS" - COMP_VENDOR_CFLAGS="-I$abs_tiffdir/libtiff $COMP_VENDOR_CFLAGS" - COMP_VENDOR_LDFLAGS="-L$abs_tiffdir/libtiff $COMP_VENDOR_LDFLAGS" - TIFF_LIBS="$abs_tiffdir/libtiff/libtiff.la" - AC_DEFINE([HAVE_LIBTIFF], [1], [Define to 1 if you have the `tiff' library (-ltiff).]) -else - AC_CHECK_HEADERS([tiffio.h]) - 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], [ - if test "$ac_cv_header_tif_dir_h" = "yes" ; then - AC_DEFINE([SPANDSP_SUPPORT_TIFF_FX], [1], [Support TIFF/FX in TIFF file handling]) - SPANDSP_SUPPORT_TIFF_FX="#define SPANDSP_SUPPORT_TIFF_FX 1" - else - SPANDSP_SUPPORT_TIFF_FX="#undef SPANDSP_SUPPORT_TIFF_FX" - fi -], [SPANDSP_SUPPORT_TIFF_FX="#undef SPANDSP_SUPPORT_TIFF_FX"], -lm) - -AC_CHECK_HEADERS([jpeglib.h]) -AC_CHECK_LIB([jpeg], [jpeg_start_compress], [JPEG_LIBS="-ljpeg"], AC_MSG_ERROR("Cannot build without libtiff (does your system require a libjpeg-devel or libjpeg-turbo-devel package?)")) - -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_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) -AC_SUBST(CC_FOR_BUILD) -AC_SUBST(CPPFLAGS_FOR_BUILD) -AC_SUBST(COMP_VENDOR_CFLAGS) -AC_SUBST(COMP_VENDOR_LDFLAGS) -AC_SUBST(SIMLIBS) -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_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 - doc/doxygen - src/Makefile - src/spandsp.h - spandsp-sim/Makefile - test-data/Makefile - test-data/etsi/Makefile - test-data/etsi/fax/Makefile - test-data/itu/Makefile - test-data/itu/fax/Makefile - test-data/itu/tiff-fx/Makefile - test-data/local/Makefile - tests/Makefile - spandsp.pc - spandsp.spec]) - -AC_OUTPUT - -# @end 1 diff --git a/libs/spandsp/configure.gnu b/libs/spandsp/configure.gnu deleted file mode 100755 index c78238de46..0000000000 --- a/libs/spandsp/configure.gnu +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh -srcpath=$(dirname $0 2>/dev/null ) || srcpath="." -$srcpath/configure "$@" --disable-shared --with-pic - diff --git a/libs/spandsp/debian/changelog b/libs/spandsp/debian/changelog deleted file mode 100644 index 7ace464002..0000000000 --- a/libs/spandsp/debian/changelog +++ /dev/null @@ -1,119 +0,0 @@ -spandsp (0.0.6~pre7-1) unstable; urgency=low - - [ Steve Underwood ] - * New upstream release. - * Fixed upstream file name for get-orig-source. - * Updates to 64bit archs support - * Removal of obsoleted files - - -- Steve Underwood Sat, 14 Mar 2009 09:23:36 +0100 - -spandsp (0.0.5~pre2-1) unstable; urgency=low - - [ Massimo Cetra ] - * New upstream release. - * Fixed upstream file name for get-orig-source. - * Updates to 64bit archs support - * Removal of obsoleted files - - -- Massimo Cetra Mon, 5 May 2008 09:23:36 +0100 - -spandsp (0.0.4~pre3-1) unstable; urgency=low - - [ Santiago Ruano Rincón ] - * Added Conflicts: libspandsp2 - * Fixed URL in debian/rules - - [ Tzafrir Cohen ] - * New upstream release. - * Fixed upstream file name for get-orig-source. - * standards version updated to 3.7.2 . - - -- Tzafrir Cohen Mon, 18 Jun 2007 09:53:06 +0300 - -spandsp (0.0.4~pre1-1) experimental; urgency=low - - * New upstream release. - - -- Santiago Ruano Rincón Fri, 11 May 2007 15:24:41 -0500 - -spandsp (0.0.3pre27-2) experimental; urgency=low - - * Conflict with libspandsp1 due to /usr/share/spandsp/global-tones.xml - - -- Kilian Krause Thu, 4 Jan 2007 00:29:10 +0100 - -spandsp (0.0.3pre27-1) experimental; urgency=low - - * New upstream release. - * Bump library name due to API incompatibility with 0.0.2 versions. - - -- Kilian Krause Wed, 3 Jan 2007 21:31:17 +0100 - -spandsp (0.0.3pre26-1) experimental; urgency=low - - * New upstream release - - New version of spandsp available (Closes: #339293) - - Remove src/spandsp/mmx.h is not GPL and has no license attached (Closes: - #357813) - * Lintian: outdated-autotools-helper-file - Build-Depends: autotools-dev - * Add debian/watch - - -- Mark Purcell Sat, 9 Dec 2006 14:00:57 +0000 - -spandsp (0.0.2pre26-1) unstable; urgency=low - - * New upstream release. - * Added get-orig-source target. - * Removed unneeded and buggy nommx.dpatch (Closes: #376249, #377374) - - -- Tzafrir Cohen Tue, 1 Aug 2006 06:27:47 +0100 - -spandsp (0.0.2pre25-1) unstable; urgency=low - - * New upstream version. - * debian/copyright: Source's URL in copyright file updated to the new author' site. - * Added -doc package, with the API documentation. - * Fixed package name to follow new upstream's version. - - -- Kilian Krause Sat, 18 Feb 2006 22:10:21 +0100 - -spandsp (0.0.2pre17-1) unstable; urgency=low - - * New upstream version. - - -- Kilian Krause Mon, 9 May 2005 21:56:53 +0200 - -spandsp (0.0.2pre10-3) unstable; urgency=low - - * debian/control: fixed overrides. again. (Back to the old optional) - - -- Kilian Krause Mon, 21 Mar 2005 10:39:30 +0100 - -spandsp (0.0.2pre10-2) unstable; urgency=low - - * debian/control: fixed overrides. - * debian/patches/mmx.dpatch: Added compilation on non-i386 and non-amd64. - - -- Kilian Krause Sun, 20 Mar 2005 23:32:48 +0100 - -spandsp (0.0.2pre10-1) unstable; urgency=low - - * New upstream release. - * Debian VoIP Team takes this package from Simon. Thanks! - * debian/rules: fixed how config.[sub,guess] files are linked from - autotools-dev and cleaned. - - -- Kilian Krause Sat, 22 Jan 2005 13:44:28 +0100 - -spandsp (0.0.2-2) unstable; urgency=low - - * Corrected build dependencies. - - -- Simon Richter Mon, 3 Jan 2005 13:33:33 +0100 - -spandsp (0.0.2-1) unstable; urgency=low - - * Initial Release (Closes: #262032). - - -- Simon Richter Sun, 2 Jan 2005 15:22:58 +0100 diff --git a/libs/spandsp/debian/compat b/libs/spandsp/debian/compat deleted file mode 100644 index b8626c4cff..0000000000 --- a/libs/spandsp/debian/compat +++ /dev/null @@ -1 +0,0 @@ -4 diff --git a/libs/spandsp/debian/control b/libs/spandsp/debian/control deleted file mode 100644 index 3f08fbf86a..0000000000 --- a/libs/spandsp/debian/control +++ /dev/null @@ -1,42 +0,0 @@ -Source: spandsp -Section: libs -Priority: optional -Maintainer: Debian VoIP Team -Uploaders: Jose Carlos Garcia Sogo , Kilian Krause , Santiago Garcia Mantinan , Mark Purcell , Tzafrir Cohen , Santiago Ruano Rincón -Build-Depends: debhelper (>= 4.0.0), libtiff4-dev, libjpeg62-dev, dpatch, doxygen, autotools-dev, xsltproc -Standards-Version: 3.7.2 -XS-Vcs-Svn: svn://svn.debian.org/pkg-voip/ -XS-Vcs-Browser: http://svn.debian.org/wsvn/pkg-voip/ - -Package: libspandsp6 -Architecture: any -Depends: ${shlibs:Depends} -Conflicts: libspandsp0, libspandsp1, libspandsp2 -Description: Telephony signal processing library - This is a low-level signal processing library that modulate and demodulate - signals commonly used in telephony, such as the "noise" generated by a - fax modem or DTMF touchpad. - . - This package contains the shared library. - -Package: libspandsp-dev -Section: libdevel -Architecture: any -Depends: libspandsp6 (= ${Source-Version}), libtiff4-dev, libjpeg62-dev -Description: Telephony signal processing library - This is a low-level signal processing library that modulate and demodulate - signals commonly used in telephony, such as the "noise" generated by a - fax modem or DTMF touchpad. - . - This package contains the static library and development headers. - . - Homepage: http://www.soft-switch.org/ - -Package: libspandsp-doc -Section: doc -Architecture: all -Description: Documentation for the spandsp signal processing library - This package contains the online API in HTML for the libspandsp, a low - level signal processing library that modulate and demodulate siignals - commonly used in telephony, such as the "noise" generated by a fax - modem or DTMF touchpad. diff --git a/libs/spandsp/debian/copyright b/libs/spandsp/debian/copyright deleted file mode 100644 index 2342a78b6b..0000000000 --- a/libs/spandsp/debian/copyright +++ /dev/null @@ -1,25 +0,0 @@ -This package was debianized by Simon Richter on -Sun, 2 Jan 2005 15:22:58 +0100. - -It was downloaded from http://soft-switch.org/downloads/spandsp/ - -Copyright: Steve Underwood - -License: - - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 dated June, 1991. - - This package 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 package; if not, write to the Free Software Foundation, Inc., - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - - -On Debian systems, the complete text of the GNU General -Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/libs/spandsp/debian/libspandsp-dev.install b/libs/spandsp/debian/libspandsp-dev.install deleted file mode 100644 index 2732ed1992..0000000000 --- a/libs/spandsp/debian/libspandsp-dev.install +++ /dev/null @@ -1,4 +0,0 @@ -debian/tmp/usr/include -debian/tmp/usr/lib/libspandsp.so -debian/tmp/usr/lib/libspandsp.la -debian/tmp/usr/lib/libspandsp.a diff --git a/libs/spandsp/debian/libspandsp-doc.install b/libs/spandsp/debian/libspandsp-doc.install deleted file mode 100644 index 0381c92d5e..0000000000 --- a/libs/spandsp/debian/libspandsp-doc.install +++ /dev/null @@ -1 +0,0 @@ -doc/api/html usr/share/doc/libspandsp-doc/api/ diff --git a/libs/spandsp/debian/libspandsp6.install b/libs/spandsp/debian/libspandsp6.install deleted file mode 100644 index 20a3484e40..0000000000 --- a/libs/spandsp/debian/libspandsp6.install +++ /dev/null @@ -1,2 +0,0 @@ -debian/tmp/usr/lib*/libspandsp.so.2.* -debian/tmp/usr/lib*/libspandsp.so.2 diff --git a/libs/spandsp/debian/rules b/libs/spandsp/debian/rules deleted file mode 100755 index beee3de43d..0000000000 --- a/libs/spandsp/debian/rules +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/make -f - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) -DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) - -DEBVERSION:=$(shell head -n 1 debian/changelog \ - | sed -e 's/^[^(]*(\([^)]*\)).*/\1/') -ORIGTARVER:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//')# -e 's/.dfsg$$//' -e 's/~//') - -UPVERSION:=$(shell echo $(ORIGTARVER) | tr -d '~') - -FILENAME := spandsp_$(ORIGTARVER).orig.tar.gz -FULLNAME := spandsp-$(UPVERSION) -URL := http://soft-switch.org/downloads/spandsp/spandsp-$(UPVERSION).tgz - -CFLAGS = -Wall -g - -ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 -else - CFLAGS += -O2 -endif - -include /usr/share/dpatch/dpatch.make - - -autotools: patch-stamp - ln -s /usr/share/misc/config.sub config.sub - ln -s /usr/share/misc/config.guess config.guess - touch autotools - -config.status: autotools configure - dh_testdir - CFLAGS="$(CFLAGS)" ./configure \ - --host=$(DEB_HOST_GNU_TYPE) \ - --build=$(DEB_BUILD_GNU_TYPE) \ - --prefix=/usr \ - --mandir=\$${prefix}/share/man \ - --infodir=\$${prefix}/share/info \ - --enable-doc - -build: build-stamp - -build-stamp: config.status - dh_testdir - $(MAKE) - touch build-stamp - -clean: clean-patched unpatch -clean-patched: - dh_testdir - dh_testroot - rm -f build-stamp autotools - -$(MAKE) distclean - - -$(RM) -f config.sub - -$(RM) -f config.guess - - dh_clean - -install: build-stamp - dh_testdir - dh_testroot - dh_clean -k - $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp - -binary-indep: build-stamp install - dh_testdir -i - dh_testroot -i - dh_installchangelogs -i ChangeLog - dh_installdocs -i DueDiligence - dh_install -i - dh_compress -i - dh_fixperms -i - dh_installdeb -i - dh_gencontrol -i - dh_md5sums -i - dh_builddeb -i - -binary-arch: build-stamp install - dh_testdir -a - dh_testroot -a - dh_installchangelogs -a ChangeLog - dh_installdocs -a DueDiligence - dh_install -a - dh_strip -a - dh_compress -a - dh_fixperms -a - dh_makeshlibs -a - dh_installdeb -a - dh_shlibdeps -a - dh_gencontrol -a - dh_md5sums -a - dh_builddeb -a - -get-orig-source: - -@@dh_testdir - @@[ -d ../tarballs/. ]||mkdir -p ../tarballs - @@echo Downloading $(FILENAME) from $(URL) ... - @@wget -N -nv -T10 -t3 -O ../tarballs/$(FILENAME) $(URL) - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install patch unpatch diff --git a/libs/spandsp/debian/watch b/libs/spandsp/debian/watch deleted file mode 100644 index 36f79f19d1..0000000000 --- a/libs/spandsp/debian/watch +++ /dev/null @@ -1,7 +0,0 @@ -# See uscan(1) for format - -# Compulsory line, this is a version 3 file -version=3 - -# -http://soft-switch.org/downloads/spandsp/ spandsp-(.*)\.tgz debian svn-upgrade diff --git a/libs/spandsp/doc/Makefile.am b/libs/spandsp/doc/Makefile.am deleted file mode 100644 index b85883f4f7..0000000000 --- a/libs/spandsp/doc/Makefile.am +++ /dev/null @@ -1,38 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -MAINTAINERCLEANFILES = Makefile.in - -EXTRA_DIST = css.css \ - doxygen.in \ - t38-gateway.dia \ - t38-terminal.dia \ - t38_manual.xml \ - wrapper.xsl \ - t38_manual/css.css - -all: doxydocs t38_manual/index.html - -doxydocs: - doxygen doxygen - -t38_manual/index.html: t38_manual.xml - cd t38_manual ; xsltproc ../wrapper.xsl ../t38_manual.xml - -clean: - cd t38_manual ; rm *.html ; cd ../api ; rm -rf html diff --git a/libs/spandsp/doc/css.css b/libs/spandsp/doc/css.css deleted file mode 100644 index 2f07200bdc..0000000000 --- a/libs/spandsp/doc/css.css +++ /dev/null @@ -1,564 +0,0 @@ -body { - background-image: url("../images/weave.jpg"); - font-family: Verdana, Arial, Helvetica, Sans-serif; - color: black; - margin-right: 20px; - margin-left: 20px; -} - -h1 { - text-align: center; -} - -h2 { - font-family: Verdana, Arial, Helvetica, Sans-serif; - border-color: #c00000; - color : black; - margin-top: 0.8em; - border-style: solid; - border-width: 0px 0px 3px 0.5em; - line-height : 130%; -} - -h3 { - font-family: Verdana, Arial, Helvetica, Sans-serif; - border-color: #f02020; - color : black; - border-width: 0px 0px 2px 0.5em; - border-style: solid; - margin-right: 20%; - line-height : 130%; -} -caption { - font-weight: bold -} -a.qindex {} -a.qindexRef {} -a.el { - text-decoration: none; - font-weight: bold -} -a.elRef { - font-weight: bold -} -a.code { - text-decoration: none; - font-weight: normal; - color: #4444ee -} -a.codeRef { - font-weight: normal; - color: #4444ee -} -a:hover { - text-decoration: none; - background-color: #f2f2ff -} -dl.el { - margin-left: -1cm -} -div.fragment { - width: 100%; - border: none; - background-color: #eeeeee -} -div.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px -} - -td { - font-family: Verdana, Arial, Helvetica, Sans-serif; - font-weight: bold; -} - -.navheader { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #B2B2ff; - font-weight: bold; -} - -.navfooter { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #B2B2ff; - font-weight: bold; -} - -table.menu { - background-color: #000066; - font-weight: bold; - text-align: center; - width: 100%; -} - -tr.menu { - background-color: #ccffff; - font-weight: bold; - text-align: center; -} -td.menu { - background-color: #f2e0d0; - font-weight: bold; - text-align: center; -} - -td.md { - background-color: #f2f2ff; - font-weight: bold; -} -td.mdname1 { - background-color: #f2f2ff; - font-weight: bold; - color: #602020; -} -td.mdname { - background-color: #f2f2ff; - font-weight: bold; - color: #602020; - width: 600px; -} -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold -} -div.groupText { - margin-left: 16px; - font-style: italic; - font-size: smaller -} -td.indexkey { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} -td.indexvalue { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} -span.keyword { - color: #008000 -} -span.keywordtype { - color: #604020 -} -span.keywordflow { - color: #e08000 -} -span.comment { - color: #800000 -} -span.preprocessor { - color: #806020 -} -span.stringliteral { - color: #002080 -} -span.charliteral { - color: #008080 -} -em { - color: #990000; - background-color: transparent; -} -h1,h2,h3,h4,h5,h6,p,center,td,th,ul,dl,div { - font-family: Geneva, Arial, Helvetica, sans-serif; -} -body,td { - font-size: 90%; -} -h1 { - text-align: center; - font-size: 160%; -} -h2 { - font-size: 120%; -} -h3 { - font-size: 100%; -} -caption { - font-weight: bold -} -div.qindex { - width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; -} -div.nav { - width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; -} -div.navtab { - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; -} -td.navtab { - font-size: 70%; -} -a.qindex { - text-decoration: none; - font-weight: bold; - color: #1a419d; -} -a.qindex:visited { - text-decoration: none; - font-weight: bold; - color: #1a419d -} -a.qindex:hover { - text-decoration: none; - background-color: #ddddff; -} -a.qindexHL { - text-decoration: none; - font-weight: bold; - background-color: #6666cc; - color: #ffffff; - border: 1px double #9295C2; -} -a.qindexHL:hover { - text-decoration: none; - background-color: #6666cc; - color: #ffffff; -} -a.qindexHL:visited { - text-decoration: none; - background-color: #6666cc; - color: #ffffff -} -a.el { - text-decoration: none; - font-weight: bold -} -a.elRef { - font-weight: bold -} -a.code:link { - text-decoration: none; - font-weight: normal; - color: #0000FF -} -a.code:visited { - text-decoration: none; - font-weight: normal; - color: #0000FF -} -a.codeRef:link { - font-weight: normal; - color: #0000FF -} -a.codeRef:visited { - font-weight: normal; - color: #0000FF -} -a:hover { - text-decoration: none; - background-color: #f2f2ff -} -dl.el { - margin-left: -1cm -} -.fragment { - font-family: Fixed, monospace; - font-size: 95%; -} -pre.fragment { - border: 1px solid #CCCCCC; - background-color: #f5f5f5; - margin-top: 4px; - margin-bottom: 4px; - margin-left: 2px; - margin-right: 8px; - padding-left: 6px; - padding-right: 6px; - padding-top: 4px; - padding-bottom: 4px; -} -div.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px -} -td.md { - background-color: #F4F4FB; - font-weight: bold; -} -td.mdPrefix { - background-color: #F4F4FB; - color: #606060; - font-size: 80%; -} -td.mdname1 { - background-color: #F4F4FB; - font-weight: bold; - color: #602020; -} -td.mdname { - background-color: #F4F4FB; - font-weight: bold; - color: #602020; - width: 600px; -} -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold; -} -div.groupText { - margin-left: 16px; - font-style: italic; - font-size: 90% -} -td.indexkey { - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -td.indexvalue { - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -tr.memlist { - background-color: #f0f0f0; -} -p.formulaDsp { - text-align: center; -} -img.formulaDsp { -} -img.formulaInl { - vertical-align: middle; -} -span.keyword { - color: #008000 -} -span.keywordtype { - color: #604020 -} -span.keywordflow { - color: #e08000 -} -span.comment { - color: #800000 -} -span.preprocessor { - color: #806020 -} -span.stringliteral { - color: #002080 -} -span.charliteral { - color: #008080 -} -.mdTable { - border: 1px solid #868686; - background-color: #F4F4FB; -} -.mdRow { - padding: 8px 10px; -} -.mdescLeft { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} -.mdescRight { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} -.memItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplParams { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - color: #606060; - background-color: #FAFAFA; - font-size: 80%; -} -.search { - color: #003399; - font-weight: bold; -} -form.search { - margin-bottom: 0px; - margin-top: 0px; -} -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #eeeeff; -} -td.tiny { - font-size: 75%; -} -a { - color: #252e78; -} -a:visited { - color: #3d2185; -} -.dirtab { - padding: 4px; - border-collapse: collapse; - border: 1px solid #b0b0b0; -} -th.dirtab { - background: #eeeeff; - font-weight: bold; -} -hr { - height: 1px; - border: none; - border-top: 1px solid black; -} diff --git a/libs/spandsp/doc/doxygen.in b/libs/spandsp/doc/doxygen.in deleted file mode 100644 index 38af500c1a..0000000000 --- a/libs/spandsp/doc/doxygen.in +++ /dev/null @@ -1,1184 +0,0 @@ -# Doxyfile 1.4.4 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = @PACKAGE@ - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = @VERSION@ - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = api - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, -# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, -# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, -# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, -# Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. - -JAVADOC_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources -# only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the progam writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = .. - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm - -FILE_PATTERNS = *.c \ - *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = NO - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 2 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = css.css - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = YES - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = SPAN_DECLARE(x)=x - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that a graph may be further truncated if the graph's -# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH -# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), -# the graph is not depth-constrained. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/libs/spandsp/doc/t38-gateway.dia b/libs/spandsp/doc/t38-gateway.dia deleted file mode 100644 index 1c2bd7060ab8200a250105c269134a3c87ed4d1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3015 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 diff --git a/libs/spandsp/doc/t38_manual.xml b/libs/spandsp/doc/t38_manual.xml deleted file mode 100644 index e49afcdbd8..0000000000 --- a/libs/spandsp/doc/t38_manual.xml +++ /dev/null @@ -1,290 +0,0 @@ - - - - - 2007-11-14 - T.38 protocol (FoIP) support - User manual - documentation in progress - - - Steve - Underwood - - -
- steveu@coppice.org -
- - 2007 - Steve Underwood - - - - This document can be freely redistributed according to the - terms of the GNU General Public License. - - -
- - - - -The T.38 real-time FAX over IP (FoIP) protocol - -There are two ITU recommendations which address sending FAXes over IP networks. T.37 specifies a method of encapsulating FAX images in e-mails, and transporting them to the recipient (an e-mail box, or another FAX machine) in a store-and-forward manner. T.38 specifies a protocol for transmitting a FAX across an IP network in real time. This document discusses the implementation of the T.38, real time, FAX over IP (FoIP) protocol. - -FAXing between two PSTN FAX machines provides the illusion of real-time communication, with confirmed delivery. This is, of course, no more than an illusion. The sender has no idea what is receiving the FAX. It might be a FAX mailbox, where the FAX might only be retrieved much later, or might never be retrieved at all. It might be a FAX machine which is out of paper, and is storing the FAX in memory. If nobody adds paper before the FAX machine is switched off, the FAX might never be printed. With increasing amounts of FAX spam, many people don't ever bother to collect FAXes from the FAX machine in their office. Still, with all these reasons why the real-time confirmed delivery nature of FAXing is an illusion, large numbers of people still insist on using direct FAXing. - -The FAX protocols - in particular T.30 - were designed for the PSTN. The PSTN is very different from a packet network like the Internet. It offers very strict timing; latency is rock steady throughout a call; and latency is seldom very high. The lack of these features in packet networks tends to spoil the quality of voice over IP, compared to voice over the PSTN. However, it can totally destroy modem data, like that used for FAX. Jitter and packet loss can cause modem reception to fail, and excessive delays can cause timers designed for a low latency environment to expire. T.38 tries to mitigate these factors, and can greatly improve the reliability of FAXing across the internet. It can also send FAXes using less bandwidth than using VoIP protocols. There are limits to what can be achieved on a congested network, though, and T.38 can never offer the reliability of a store and forward protocol, like T.37. Sadly, the average office worker's love affair with real-time FAX ensures a bright future for the T.38 protocol, even though the T.37 protocol makes far more sense. - -The T.38 protocol primarily operates between: - -Internet-aware FAX terminals, which connect directly to an IP network. -FAX gateways, which allow traditional PSTN FAX terminals to communicate via the Internet. -A combination of these. - -T.38 is the only standardised protocol which exists for real-time FoIP. Reliably transporting a FAX between PSTN FAX terminals, through an IP network, requires use of the T.38 protocol at FAX gateways. VoIP connections are not robust for modem use, including FAX modem use. Most use low bit rate codecs, which cannot convey the modem signals accurately. Even when high bit rate codecs, such as G.711, are used, VoIP connections suffer dropouts and timing adjustments, which modems cannot tolerate. In a LAN environment the dropout rate may be very low, but the timing adjustments which occur in VoIP connections still make modem operation unreliable. T.38 FAX gateways deal with the delays, timing jitter, and packet loss experienced in packet networks, and isolate the PSTN FAX terminals from these as far as possible. In addition, by sending FAXes as image data, rather than digitised audio, the required bandwidth of the IP network might be reduced. However, the redundant transmission needed to make T.38 work acceptably over an unreliable network tends to offset much of the potential bandwidth gain. - -The original T.38 specification provides for operation up to 14,400bps, using a V.17 modem. The latest version of the T.38 specification adds features for FAXing at up to 33,600bps, using a V.34 modem. However, it appears most current T.38 implementations only support operation up to 14,400bps. - - - -The basics of a T.38 entity - -The T.38 protocol may be used to build an Internet-aware FAX terminal, for direct connection to the Internet. It may also be used to build gateways. A T.38 FAX gateway might be a gateway between the PSTN and the Internet. It might just be an a ATA box acting as a gateway between a directly connected traditional FAX machine and the Internet. The T.38 protocol merely defines what passes between two T.38 entities. Creating a robust entity, able to tolerate the widest possible variation in network delays, jitter and packet loss, requires considerably more than just implementing what is contained in the T.38 spec. Also, the protocol definition is somewhat loose, resulting is considerable variability in the way the protocol is implemented. Considerable flexibility is required in a T.38 entity's design, to tolerate these variations. - -T.38 currently works over one of the following transports: - -TCP, with TPKT message framing - the use of TPKT was originally specified in a vague way, and implementations without TPKT framing apparently exist. -UDPTL - A UDP based protocol used nowhere else. This is the most common transport for T.38. -RTP - Added quite late to the T.38 specification, and still not widely supported. - -TCP is the ideal way to communicate between two entities on an IP network, which do not have real-time constraints. The entities can talk as fast as they and the medium between them permit, with full error control. Internet-aware FAX devices would, therefore, usually use TCP as the transport for T.38. Gateways have only limited control of the timing of the FAX data passing through them. They have to operate in real-time, at a rate outside their control. Gateways, therefore, usually use UDPTL. The RTP option was only added to the T.38 specification in 2004, and is not yet widely supported. Over time it may become the preferred replacement for UDPTL, since most entities handle more than just FAX, and need to implement RTP anyway. - -A TCP stream is fully corrected by the TCP protocol itself. However, in the UDPTL or RTP modes of operation, T.38 is subject to possible packet loss. A high level of missing data would defeat the protocol, so some measure of FEC (forward error correction) must be used. The UDPTL specification defines two optional forms of FEC. Both consist of adding information from previous packets to new packets. In one form this repeated data is send as a direct copy of the original. In the other it is sent as parity information, which requires encoding and decoding. The specifications for RTP include definitions of suitable FEC and redundancy protocols (RFC2198 and RFC2733). The T.38 specification says these should be used for T.38 over RTP. - -Interestingly, even the latest revision of the T.38 specification does not provide properly for security in FAX transmission. SRTP is a standard way to achieve secure multi-media communication, and can be applied to T.38 over RTP without any specific wording on the subject in the T.38 specification. UDPTL might be seen as obsolete in the long term, and not worthy of enhancements to encrypt the data. However, no secure option for T.38 over TCP is defined. TPKT could be sent over TLS/TCP. TLS also has message framing features which would allow IFP packets to be sent directly over a TLS protected connection. However, there is no specified way to do this. - -Although redundant information in future packets is an important part of a solid T.38 implementation, it is not a complete solution to problem of lost packets. Sometimes the next packet occurs after a considerable delay (e.g. when allowing time for a fast modem to train). If a "start training" message is only received through the redundant information in a following packet, it usually arrives too late to be useful (at least for a gateway). Most T.38 implementations now follow a practice of sending several exact copies of key packets - generally the ones which start or end the stages of the T.30 protocol. Typically up to 4 identical copies of these packets are sent down the wire. The may be sent in a burst, as fast as possible, or they may be spaced in time by 10ms or 20ms. IP network congestion, and the resulting packet loss, can be very bursty. If all copies are sent together, they might all be lost. Even a small amount of spreading in time may significantly increase the likelihood of at least one copy reaching its destination. The price is some delay in delivery of the message, which might be problematic. Multiple copies of these packets add little to the overall volume of data transmitted, as only a small percentage of packets fall in this "key packet" category. Some T.38 implementations follow a less effective practice of sending multiple key packets, which have separate sequence numbers and are separately bundled with redundant information for transmission. They may also be spaced in time. Although this seems a less effective strategy, a T.38 entity must expect to receive packets streams of this kind, and tolerate them. - -Between the high priority key packets, and the low priority packets for the image data (the loss of which might just cause a streak on an image, or be corrected by ECM FAXing), lies the V.21 HDLC control messages. Some T.38 implementations dynamically adjust the amount of redundant information in packets, so these control messages are repeated through several packets, but the large image data packets are repeated less, or not at all. Used with care, this dynamic redundancy strategy can nicely balance data volume and reliability. - -A T.38 terminal has a lot more flexibility in how it can deal with problem data than a T.38 gateway. The terminal has no tight timing constraints governing how it behaves with regard to received data. It can wait a considerable period for delayed packets to arrive. The gateway is a man-in-the-middle, and must live with the timing constraints that imposes. This means a T.38 gateway has a rather more difficult design than a terminal. - - - -The core elements of a T.38 implementation - -There are many differences between the behaviour of a T.38 terminal and a T.38 gateway. However, some functions are common to both types of T.38 entity, particular in the IP network interface. - - -The T.38 Internet Fascimile Protocol (IFP) packetiser - -The T.38 specification defines an ASN.1 schema for the messages which pass between T.38 entities. These messages are called IFP (Internet Fascimile Protocol) messages. Their format is independent of the transport used to carry them. However, there are currently two slightly different versions of the ASN.1 schema. This is due to a typo in the original version of the T.38 specification. The protocol negotiation which occurs just before T.38 communication resolves which version will be used. Although the typo was corrected several years ago, it is still very more common to find implementations which only support the original buggy version. - - - -The UDPTL, RTP, TPKT packetiser - -A second level packetiser bundles the IFP packets for transmission. This functions in different ways, depending on the type of transport in use. For the unreliable transports (UDPTL and RTP) the packetiser adds forward error correction (FEC) information to the packets. This can greatly inprove the reliability of the T.38 protocol, at the expense of higher bandwidth. The amount of error correction information added to the packets is implementation dependant. - -For UDPTL, two forms of FEC are defined. One simply repeats older T.38 packets as FEC information in the current UDPTL packet. The other generates parity packets over a series of T.38 packets, and includes that parity information in the current UDPTL packet. The type of FEC to be used is negotiated just before T.38 communication begins. - -The RTP specifications (RFC3550, RFC3551, RFC2198, RFC2733) define common redundancy and FEC formats, to be used for any payload. Where T.38 packets are carried by RTP, the standard RTP FEC mechanisms are used. - -TPKT (RFC1006, RFC2126) encapsulation works over a TCP transport. TCP provides full error correction, though retries may slow it considerably. TPKT encapsulation merely provides the ability to delineate the start and end of the IFP packets in the structureless TCP stream. - - - - - -The elements of a T.38 terminal - - - - - - -The elements of a T.38 gateway - - - - -The HDLC decoder -If the HDLC decoder in a T.38 gateway worked in whole frames, it would introduce unacceptable latency. Instead, the HDLC decoder must work progressively through the HDLC frames, outputing its results octet by octet. The T.38 message stream does not contain HDLC preamble, though it usually contains an indication that preamble is in progress. It does not contain the CRC octets, but simply an indication of whether the CRC is good or bad. The HDLC decoder provides an indication when preamble is being received, and checks the CRC octets at the end of frames to provide the good or bad indication. The decoder makes the frames available, octet by octet, to the T.38 engine for status tracking and possible modification. Tracking and modification imposes a few octets delay, but the goal is to keep this to the minimum possible. Whether the frames are modified or unmodified, good or bad they are always passed on, to maintain the appropriate timing flow for the T.30 protocol. - -An interesting aspect of the timing flow of V.21 HDLC messages on the T.38 path relates to the size of the CRC. The usual practice for sending these frames is to send one octet in each message, with the messages spaced by the duration of one octet. They will normally be sent with the minimum possible delay. The CRC at the end of each frame is two octets long, and only an indication of good or bad is sent in the T.38 messages. It takes two octet times to know if the CRC is OK or not, typically causing the flow of T.38 messages to stutter by the duration of an octet. Since flow control within a frame is not possible when frames are replayed by a remote T.38 gateway, that gateway must allow for this inevitable stutter as it prepares to begin playout of the frame. - - - -T.30 message analysis and manipulation -The T.30 message analyser in a T.38 gateway performs the following functions: - -It passes NSS, NSF and NSC frames, but modifies their contents. A receiving FAX machine must be prevented from acting upon these messages in a manufacturer specific manner. The T.38 protocol is incapable of handling such manufacturer specific things. However, simply dropping these packets would upset the timing of the T.30 protocol. Instead, most T.38 implementations modify the country and manufacturer codes nesr the start of these messages, so the messages will be ignored by any receiver. They are typically set to 0x00, 0x55, 0xAA or 0xFF. Some implementations set them to the country and manufacturer code of the T.38 implementor. As long as they are set to something the receiver will not recognise, problems are avoided. To avoid removing useful information, the original country and manufacturer code bytes might be reinserted in a different part of the modified NSF message, provided space permits. -It tracks the contents of the DCS messages. During flow control of non-ECM data, the minimum row length must be preserved, so the current minimum must be found from the DCS messages. Similarly, the current encoding must be known to apply non-ECM flow control correctly. ECM data must be flow controlled in a completely different way than non-ECM data, so ECM mode information must be found from the DCS messages. -It may optionally modify the minimum row length in the DIS messages. Because flow control will be applied to non-ECM data, it can make sense to tell the sending FAX machine it has no need to impose a minimum row length, and let the emitting T.38 entity impose the minimum as part of its flow control operation. -It passes on the stripped and modified HDLC frames, with the minimum possible delay. This implies that is must analyse and modify the messages octet by octet. - - - - - -The HDLC rate adapting encoder -The HDLC data rate adapting encoder accepts a T.30 message stream as input. The V.21 HDLC messages generally arriving byte by byte, in separate T.38 messages. ECM HDLC messages usually arrive in larger chunks, but they are still generally fragmented. The rate adapter dynamically buffers the T.30 data, generates preamble, and adjusts its length if the incoming message data is falling behind. It may insert additional flag octets between frames, as a flow control mechanism. However, the HDLC protocol is synchronous, so the adapter cannot perform any flow control within a frame. It must, therefore, buffer enough octets of a frame to provide reasonable jitter tolerance, before it emits the first octet of that frame. If the arriving messages fall too far behind mid-frame, there will be corruption of the outgoing stream. In the case of ECM image data frames, the frames are fast enough, that buffering whole frames is quite proactical within the T.30 timing constraints. This ensures mid-frame underflow can never occur. - - - -TCF (training confirmation) and non-ECM image data rate adaption -Non-ECM image data rate adaption deals with exchanging TCF data, and non-ECM image data using T.4 1-D or 2-D compression. Non-ECM image data is typically padded with zero bits at the end of each pixel row. This is used to avoid rows arriving at the receiving FAX machine faster than the mechanical paper handling can process them. It is also used by sending FAX machines for flow control, when their paper handling falls behind. The minimum duration of a row is negotiated between the FAX machines, before image transfer commences. - -TCF data is a continuous stream of zero bits. It may, optionally, be preceeded by a continuous block of one bits. So, when transferring TCF data between the T.38 entities, flow control is simply a matter of repeating the last received bit when the late arrival of TCF data packets causes underflow at an emitting gateway. - -T.38 entities may negotiate to generate and check TCF data locally, and not exchange it. Generally, this is only used when TCP/TPKT is used as the transport for the T.38 messages. A TCF checker and a TCF generator are needed by a T.38 gateway supporting this option. - -Some T.38 entities are capable of negotiating the removal of end of row padding bits in the data passing between the T.38 entities. This may reduce the amount of data significantly, for some types of image. If negotiated, most or all surplus zero bits are stripped from the image bit stream, at the sending T.38 entity. If a T.38 gateway is receiving such stripped data, it may need to reimpose a minimum row time, by inserting zeros, as part of its non-ECM rate adaption process. By checking the contents of the DCS messages, it can determine what this minimum should be. - -Only two types of image compression are used for non-ECM transmission - T.4 1-D and 2-D. The end of line (EOL) marker for both these is 11 zero bits, followed by a one bit. In 2-D mode, an additional one or zero bit follows, which defines the mode of the next row. It turns out that the maximum number of valid consecutive zeros which could preceed the 11 zeros of an EOL is 3. In a valid image there are no longer runs of zeros than at an EOL, and the maximum there is 14. Therefore, if the padding stripper reduces all runs of zeros longer than 14 to just 14, it will strip most of the padding with very simple logic. Simple logic is a good thing in this case. It not only avoids the need to fully analyse the image data, it also minimises problems when there are bit errors in the image data stream. - -For image data sent without error correction (T.4 1-D or 2-D) there may be underflow at the outgoing gateway, if image data packets arrive too late. To deal with slow mechanical paper handling in FAX machines, the T.30 specification includes an end of pixel row padding scheme for non-error corrected image data. The receiving machine may request a minimum row duration. The sending machine is required to impose that minimum, but can arbitrarily make it much longer to meet its own paper handling needs, sending padding bits as appropriate. This mechanism provides a robust basis for flow control in a T.38 gateway. If the outgoing gateway only starts sending a pixel row when it has the entire row in its buffer, it can safely idle, sending padding bits, at any row end it needs to. Only the 6 EOL markers, which terminate an image, must be protected from this kind of flow control. Those markers are defined as being consecutive, with no zero bit padding separating them. - -When ECM is used (usually with T.6 image data) the image is packetised in HDLC frames. In this case rate adaption is handled in a similar manner to the V.21 HDLC packets. - - - - - -Testing an implementation of T.38 -The T.38 specification does not define any specific compliance tests which an implementation must pass. It is not supplied with any test vectors. Commetrex is a supplier of T.38 implementations, who have taken it upon themselves to define a set of tests, and create a lab for T.38 interoperability testing. This seems the closest thing to an industry standard for T.38 testing which exists at this time, and is much to their credit. - -Commetrex have defined 16 tests which an implementation T.38 undergoes in their lab. These are described on the Commetrex web site as: - - -Commetrex T.38 tests - - - - - - - - - - - -Test # -Direction -Transport -Image file -Error correction -Data rate mgt -Image encoding -Polling - - - - -1originateUDPccitt2p.tifredundancy 0method 2MRno - - -2originateUDP100page.tifredundancy 0method 2MRno - - -3originateTCPccitt2p.tifredundancy 0method 1MRno - - -4originateUDPccitt2p.tifredundancy 3method 2MRno - - -5originateTCPccitt2p.tifFEC 2 from 3 spanmethod 2MRno - - -6originateUDPdither1d.tifredundancy 3method 2MRno - - -7originateUDPccitt2p.tifredundancy 3method 2ECMno - - -8originate & poll to rxUDPccitt2p.tifredundancy 3method 2MRpolled rx - - -9answerUDPccitt2p.tifredundancy 0method 2MRno - - -10answerUDP100page.tifredundancy 0method 2MRno - - -11answerTCPccitt2p.tifredundancy 0method 1MRno - - -12answerUDPccitt2p.tifredundancy 3method 2MRno - - -13answerTCPccitt2p.tifFEC 2 from 3 spanmethod 2MRno - - -14answerUDPdither1d.tifredundancy 3method 2MRno - - -15answerUDPccitt2p.tifredundancy 3method 2ECMno - - -16answer & polled to txUDPccitt2p.tifredundancy 3method 2MRpolled tx - - - -
-The file dither1d.tif is a whole page of dense checkerboard pattern, which does not compress, and produces a kind of torture test page. It is about 2M bytes. 100page.tif is exactly what it says - a file with 100 pages of FAX images. The content of the pages does not seem to be specified by Commetrex. The ITU T.30 test images, repeated sufficiently, seems a good basis for this test. ccitt2p.tif appears to be page 2 of the ITU test images. The tests are heavily biased towards non-ECM operation with MR coding. No other coding appears to be used, and only 2 tests use error corrected (ECM) FAXing. -
- -Some of the Commetrex tests seem strange. Why is TCP transmission tested with FEC or redundancy? These things are only needed to overcome to lack of reliability in a UDP path. -
- - -Living with real world T.38 entities. - The T.38 specification leaves a number of grey areas, and many things can be implemented in several ways. It might, therefore, be expected that interoperability will not always run smoothly. Whilst some design decisions are reasonable subjects for discussion, it is quite common to find T.38 implementations doing things which are simply wrong. - - -Non-ECM data ending immediately after the six EOLs denoting the end of a page causes corruption -From the T.38 specification, a T.38 entity sending non-ECM image data should be able to end the image data, with t4-non-ecm-sig-end, at the last bit of the six consecutive EOLs which denote the end of a page. However, this offers poor compatibility with some implementations of T.38. They will drop their carrier signal prematurely, and the last few rows of the image will be corrupted at the receiver. This can happen regardless of whether the t4-non-ecm-sig-end is followed by a no-signal message, and regardless of the timing of that no-signal message. Padding with zero bytes for 40ms or more after the six EOLs seems to prevent this, and results in an image which exactly matches the one at the source. - - - -Expect mixups between non-ECM and ECM image modes. -The TCF data should always be sent as non-ECM image data, whether the images which follow it are sent as non-ECM or ECM data. However, some broken implementations of T.38 (e.g. Mediatrix) may send an hdlc-sig-end message to terminate the TCF data. To be as tolerant as possible, it is probably wise to accept hdlc-sig-end or t4-non-ecm-sig-end, regardless of which kind of data it is really terminating. - - - -Expect some very poor timing decisions in various designs. -The preamble for V.21 HDLC data is specified as being 1s+-15%. This should mean 850ms of preamble is within spec, and many modern FAX machines only send that much. A number of T.38 implementations choke on this. They require at least 1s between the v21-preamble message and the first HDLC data, for reliable operation. This is very poor design. Even if there is 1s between these events at the source, jitter on the network can make them arrive less than 1s apart. It appears the best a tolerant implementation can really do is impose a 1s minimum between sending these T.38 messages, and accept that things might still go wrong when there is some jitter. - -There is similar intolerance with the timing of the start of training messages for the fast image data modems. Most implementations do not impose a minimum which is above that permitted by the T.30 specification. Some do, however, make no allowance for network jitter reducing the interval at the receiver. You should expect the far end to be using TEP, when sizing the required delay between the start of training, and the first data. Also, for ECM data, make sure the delay allows for the specified minimum 200ms of preamble. - - - -Which kinds of error correction to use. -T.38 defines two kinds of error correction for UDPTL streams. One inserts redundant copies of older IFP packets in each UDPTL packet. The other uses a more complex parity FEC scheme, based on XOR'ed data inserted in each UDPTL packet. Although each UDPTL packet identifies the type of error correction it contains, the original T.38 spec. did not offer any form of negotiation about the type to be used. The SIP and MGCP SDP for T.38 now includes preferred error correction type information, so some measure of negotiation is possible before the flow of UDPTL packets begins. - -It appears all T.38 implementations are happy to receive packets with redundant secondary content. However, it seems not all implementations will actually recover anything when there are missing UDPTL packets. It appears not all T.38 implementations are happy to receive packets with parity FEC data. Unless the SDP data from the far end explicitly says they support the parity FEC scheme, it is better to send only redundant information. A good implementation should be prepared to accept either kind of data, even intermixed, regardless of anything in the SDP negotiation. In the real world, whatever you ask for in your SDP data, you will probably receive secondary IFP packet redundancy from the far end. It is the only thing most implementations support, and with real world packet loss it may perform just as well as the more complex parity FEC scheme. - -When the first few UDPTL packets are sent, there will be no historical information to send as redundant secondary IFP packets, or parity FEC data. When using the redundant secondary packet scheme this is handled transparently. Each UDPTL packet says the number of redundant secondary IFP packets it contains. This can simply be set to zero for the first UDPTL packet, one for the second, up to the amount of redundancy which has been configured. All implementations seem to work in this way. When parity FEC is being used, the startup arrangement is less clear. While some implementations simply insert zeros for the non-existant packets before the start, others send a few packets with redundant secondary IFP packets, until they are able to insert the required amount of FEC data. Dealing with intermixed types of error correction makes a receiving implementation of UDPTL messier and slower, but is necessary for compatibility. - - - -What really ends the data? -It should be correct to send some image data, and end with the image data signal end message. However, some T.38 implementations misbehave when this is all that is sent. Immediately following the signal end message with a no-signal indicator message seems to greatly improve compatibility with some T.38 implementations. - -T.38 defines hdlc-fcs-OK, hdlc-fcs-OK-sig-end, hdlc-sig-end, and no-signal messages. Always end periods of HDLC transmission with either a hdlc-fcs-OK, hdlc-sig-end, no-signal sequence or a hdlc-fcs-OK-sig-end, no-signal sequence. Do not send hdlc-sig-end after hdlc-fcs-OK-sig-end. A number of T.38 implementations choke on this sequence, even though it looks fairly harmless. - - - - -Normal use versus testing -The design of some T.38 implementations precludes some reasonable tests from succeeding, due to design features which may have been implemented for sane reasons. This means each test failure needs to be investigated in detail, to see if it represents something genuinely bad in an implementation of T.38. For example, the 2M byte torture test page in the Commetrex test suite will not successfully pass through some T.38 implementations, because of a timeout they impose. For example, some ATAs based on Audiocodes silicon have been seen to stop any continuous period of modem transmission after about 90s. This appears to be a backstop timeout, to prevent troublesome implementations jamming the gateway. Legitimate pages just don't take that long, and the timeout is reasonable. However, the 2M byte test page takes up to 20 minutes to transmit, and will always fail on these boxes. - - - - - -
diff --git a/libs/spandsp/doc/t38_manual/css.css b/libs/spandsp/doc/t38_manual/css.css deleted file mode 100644 index 2f07200bdc..0000000000 --- a/libs/spandsp/doc/t38_manual/css.css +++ /dev/null @@ -1,564 +0,0 @@ -body { - background-image: url("../images/weave.jpg"); - font-family: Verdana, Arial, Helvetica, Sans-serif; - color: black; - margin-right: 20px; - margin-left: 20px; -} - -h1 { - text-align: center; -} - -h2 { - font-family: Verdana, Arial, Helvetica, Sans-serif; - border-color: #c00000; - color : black; - margin-top: 0.8em; - border-style: solid; - border-width: 0px 0px 3px 0.5em; - line-height : 130%; -} - -h3 { - font-family: Verdana, Arial, Helvetica, Sans-serif; - border-color: #f02020; - color : black; - border-width: 0px 0px 2px 0.5em; - border-style: solid; - margin-right: 20%; - line-height : 130%; -} -caption { - font-weight: bold -} -a.qindex {} -a.qindexRef {} -a.el { - text-decoration: none; - font-weight: bold -} -a.elRef { - font-weight: bold -} -a.code { - text-decoration: none; - font-weight: normal; - color: #4444ee -} -a.codeRef { - font-weight: normal; - color: #4444ee -} -a:hover { - text-decoration: none; - background-color: #f2f2ff -} -dl.el { - margin-left: -1cm -} -div.fragment { - width: 100%; - border: none; - background-color: #eeeeee -} -div.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px -} - -td { - font-family: Verdana, Arial, Helvetica, Sans-serif; - font-weight: bold; -} - -.navheader { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #B2B2ff; - font-weight: bold; -} - -.navfooter { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #B2B2ff; - font-weight: bold; -} - -table.menu { - background-color: #000066; - font-weight: bold; - text-align: center; - width: 100%; -} - -tr.menu { - background-color: #ccffff; - font-weight: bold; - text-align: center; -} -td.menu { - background-color: #f2e0d0; - font-weight: bold; - text-align: center; -} - -td.md { - background-color: #f2f2ff; - font-weight: bold; -} -td.mdname1 { - background-color: #f2f2ff; - font-weight: bold; - color: #602020; -} -td.mdname { - background-color: #f2f2ff; - font-weight: bold; - color: #602020; - width: 600px; -} -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold -} -div.groupText { - margin-left: 16px; - font-style: italic; - font-size: smaller -} -td.indexkey { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} -td.indexvalue { - font-family: Verdana, Arial, Helvetica, Sans-serif; - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} -span.keyword { - color: #008000 -} -span.keywordtype { - color: #604020 -} -span.keywordflow { - color: #e08000 -} -span.comment { - color: #800000 -} -span.preprocessor { - color: #806020 -} -span.stringliteral { - color: #002080 -} -span.charliteral { - color: #008080 -} -em { - color: #990000; - background-color: transparent; -} -h1,h2,h3,h4,h5,h6,p,center,td,th,ul,dl,div { - font-family: Geneva, Arial, Helvetica, sans-serif; -} -body,td { - font-size: 90%; -} -h1 { - text-align: center; - font-size: 160%; -} -h2 { - font-size: 120%; -} -h3 { - font-size: 100%; -} -caption { - font-weight: bold -} -div.qindex { - width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; -} -div.nav { - width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; -} -div.navtab { - background-color: #eeeeff; - border: 1px solid #b0b0b0; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; -} -td.navtab { - font-size: 70%; -} -a.qindex { - text-decoration: none; - font-weight: bold; - color: #1a419d; -} -a.qindex:visited { - text-decoration: none; - font-weight: bold; - color: #1a419d -} -a.qindex:hover { - text-decoration: none; - background-color: #ddddff; -} -a.qindexHL { - text-decoration: none; - font-weight: bold; - background-color: #6666cc; - color: #ffffff; - border: 1px double #9295C2; -} -a.qindexHL:hover { - text-decoration: none; - background-color: #6666cc; - color: #ffffff; -} -a.qindexHL:visited { - text-decoration: none; - background-color: #6666cc; - color: #ffffff -} -a.el { - text-decoration: none; - font-weight: bold -} -a.elRef { - font-weight: bold -} -a.code:link { - text-decoration: none; - font-weight: normal; - color: #0000FF -} -a.code:visited { - text-decoration: none; - font-weight: normal; - color: #0000FF -} -a.codeRef:link { - font-weight: normal; - color: #0000FF -} -a.codeRef:visited { - font-weight: normal; - color: #0000FF -} -a:hover { - text-decoration: none; - background-color: #f2f2ff -} -dl.el { - margin-left: -1cm -} -.fragment { - font-family: Fixed, monospace; - font-size: 95%; -} -pre.fragment { - border: 1px solid #CCCCCC; - background-color: #f5f5f5; - margin-top: 4px; - margin-bottom: 4px; - margin-left: 2px; - margin-right: 8px; - padding-left: 6px; - padding-right: 6px; - padding-top: 4px; - padding-bottom: 4px; -} -div.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px -} -td.md { - background-color: #F4F4FB; - font-weight: bold; -} -td.mdPrefix { - background-color: #F4F4FB; - color: #606060; - font-size: 80%; -} -td.mdname1 { - background-color: #F4F4FB; - font-weight: bold; - color: #602020; -} -td.mdname { - background-color: #F4F4FB; - font-weight: bold; - color: #602020; - width: 600px; -} -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold; -} -div.groupText { - margin-left: 16px; - font-style: italic; - font-size: 90% -} -td.indexkey { - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -td.indexvalue { - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -tr.memlist { - background-color: #f0f0f0; -} -p.formulaDsp { - text-align: center; -} -img.formulaDsp { -} -img.formulaInl { - vertical-align: middle; -} -span.keyword { - color: #008000 -} -span.keywordtype { - color: #604020 -} -span.keywordflow { - color: #e08000 -} -span.comment { - color: #800000 -} -span.preprocessor { - color: #806020 -} -span.stringliteral { - color: #002080 -} -span.charliteral { - color: #008080 -} -.mdTable { - border: 1px solid #868686; - background-color: #F4F4FB; -} -.mdRow { - padding: 8px 10px; -} -.mdescLeft { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} -.mdescRight { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} -.memItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; -} -.memTemplParams { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - color: #606060; - background-color: #FAFAFA; - font-size: 80%; -} -.search { - color: #003399; - font-weight: bold; -} -form.search { - margin-bottom: 0px; - margin-top: 0px; -} -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #eeeeff; -} -td.tiny { - font-size: 75%; -} -a { - color: #252e78; -} -a:visited { - color: #3d2185; -} -.dirtab { - padding: 4px; - border-collapse: collapse; - border: 1px solid #b0b0b0; -} -th.dirtab { - background: #eeeeff; - font-weight: bold; -} -hr { - height: 1px; - border: none; - border-top: 1px solid black; -} diff --git a/libs/spandsp/doc/wrapper.xsl b/libs/spandsp/doc/wrapper.xsl deleted file mode 100644 index 89e314d781..0000000000 --- a/libs/spandsp/doc/wrapper.xsl +++ /dev/null @@ -1,5 +0,0 @@ - - - css.css - \ No newline at end of file diff --git a/libs/spandsp/m4/ac_func_memmove.m4 b/libs/spandsp/m4/ac_func_memmove.m4 deleted file mode 100644 index f2301a07db..0000000000 --- a/libs/spandsp/m4/ac_func_memmove.m4 +++ /dev/null @@ -1,27 +0,0 @@ -AC_DEFUN([AC_FUNC_MEMMOVE], -[AC_CHECK_FUNCS(memmove) -AC_MSG_CHECKING(for working memmove) -AC_CACHE_VAL(ac_cv_have_working_memmove, -[AC_TRY_RUN( -[#include - -int main(void) -{ - char buf[10]; - strcpy (buf, "01234567"); - memmove (buf, buf + 2, 3); - if (strcmp (buf, "23434567")) - exit (1); - strcpy (buf, "01234567"); - memmove (buf + 2, buf, 3); - if (strcmp (buf, "01012567")) - exit (1); - exit (0); -}], ac_cv_have_working_memmove=yes, ac_cv_have_working_memmove=no, ac_cv_have_working_memmove=cross)]) -AC_MSG_RESULT([$ac_cv_have_working_memmove]) -if test x$ac_cv_have_working_memmove != "xyes"; then - AC_LIBOBJ(memmove) - AC_MSG_WARN([Replacing missing/broken memmove.]) - AC_DEFINE(PREFER_PORTABLE_MEMMOVE, 1, "enable replacement memmove if system memmove is broken or missing") -fi]) - diff --git a/libs/spandsp/m4/ax_c99_features.m4 b/libs/spandsp/m4/ax_c99_features.m4 deleted file mode 100644 index 52ab00b543..0000000000 --- a/libs/spandsp/m4/ax_c99_features.m4 +++ /dev/null @@ -1,181 +0,0 @@ -# @synopsis AX_C99_FLEXIBLE_ARRAY -# -# Does the compiler support the 1999 ISO C Standard "struct hack". -# @version 1.1 Mar 15 2004 -# @author Erik de Castro Lopo -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. - -AC_DEFUN([AX_C99_FLEXIBLE_ARRAY], -[AC_CACHE_CHECK(if have C99 struct flexible array support, - ac_cv_c99_flexible_array, - -# Initialize to unknown -ac_cv_c99_flexible_array=no - -AC_TRY_LINK([[ - #include - - typedef struct { - int k; - char buffer [] ; - } MY_STRUCT ; - ]], - [ MY_STRUCT *p = calloc (1, sizeof (MY_STRUCT) + 42); ], - ac_cv_c99_flexible_array=yes, - ac_cv_c99_flexible_array=no - ))] -) # AX_C99_FLEXIBLE_ARRAY - -# @synopsis AX_C99_FUNC_LRINT -# -# Check whether C99's lrint function is available. -# @version 1.3 Feb 12 2002 -# @author Erik de Castro Lopo -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. -# -AC_DEFUN([AX_C99_FUNC_LRINT], -[AC_CACHE_CHECK(for lrint, - ac_cv_c99_lrint, -[ -lrint_save_LIBS=$LIBS -LIBS="-lm" -AC_TRY_LINK([ -#define _ISOC9X_SOURCE 1 -#define _ISOC99_SOURCE 1 -#define __USE_ISOC99 1 -#define __USE_ISOC9X 1 - -#include -], if (!lrint(3.14159)) lrint(2.7183);, ac_cv_c99_lrint=yes, ac_cv_c99_lrint=no) - -LIBS=$lrint_save_LIBS - -]) - -if test "$ac_cv_c99_lrint" = yes; then - AC_DEFINE(HAVE_LRINT, 1, - [Define if you have C99's lrint function.]) -fi -])# AX_C99_FUNC_LRINT - -# @synopsis AX_C99_FUNC_LRINTF -# -# Check whether C99's lrintf function is available. -# @version 1.3 Feb 12 2002 -# @author Erik de Castro Lopo -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. -# -AC_DEFUN([AX_C99_FUNC_LRINTF], -[AC_CACHE_CHECK(for lrintf, - ac_cv_c99_lrintf, -[ -lrintf_save_LIBS=$LIBS -LIBS="-lm" -AC_TRY_LINK([ -#define _ISOC9X_SOURCE 1 -#define _ISOC99_SOURCE 1 -#define __USE_ISOC99 1 -#define __USE_ISOC9X 1 - -#include -], if (!lrintf(3.14159)) lrintf(2.7183);, ac_cv_c99_lrintf=yes, ac_cv_c99_lrintf=no) - -LIBS=$lrintf_save_LIBS - -]) - -if test "$ac_cv_c99_lrintf" = yes; then - AC_DEFINE(HAVE_LRINTF, 1, - [Define if you have C99's lrintf function.]) -fi -])# AX_C99_FUNC_LRINTF - -# @synopsis AX_C99_FUNC_LLRINT -# -# Check whether C99's llrint function is available. -# @version 1.1 Sep 30 2002 -# @author Erik de Castro Lopo -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. -# -AC_DEFUN([AX_C99_FUNC_LLRINT], -[AC_CACHE_CHECK(for llrint, - ac_cv_c99_llrint, -[ -llrint_save_LIBS=$LIBS -LIBS="-lm" -AC_TRY_LINK([ -#define ISOC9X_SOURCE 1 -#define _ISOC99_SOURCE 1 -#define __USE_ISOC99 1 -#define __USE_ISOC9X 1 - -#include -], long long int x ; x = llrint(3.14159) ;, ac_cv_c99_llrint=yes, ac_cv_c99_llrint=no) - -LIBS=$llrint_save_LIBS - -]) - -if test "$ac_cv_c99_llrint" = yes; then - AC_DEFINE(HAVE_LLRINT, 1, - [Define if you have C99's llrint function.]) -fi -])# AX_C99_FUNC_LLRINT - - -# @synopsis AX_C99_FUNC_LLRINTF -# -# Check whether C99's llrintf function is available. -# @version 1.1 Sep 30 2002 -# @author Erik de Castro Lopo -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. -# -AC_DEFUN([AX_C99_FUNC_LLRINTF], -[AC_CACHE_CHECK(for llrintf, - ac_cv_c99_llrintf, -[ -llrintf_save_LIBS=$LIBS -LIBS="-lm" -AC_TRY_LINK([ -#define _ISOC9X_SOURCE 1 -#define _ISOC99_SOURCE 1 -#define __USE_ISOC99 1 -#define __USE_ISOC9X 1 - -#include -], long long int x ; x = llrintf(3.14159) ;, ac_cv_c99_llrintf=yes, ac_cv_c99_llrintf=no) - -LIBS=$llrintf_save_LIBS - -]) - -if test "$ac_cv_c99_llrintf" = yes; then - AC_DEFINE(HAVE_LLRINTF, 1, - [Define if you have C99's llrintf function.]) -fi -])# AX_C99_FUNC_LLRINTF diff --git a/libs/spandsp/m4/ax_check_arm_neon.m4 b/libs/spandsp/m4/ax_check_arm_neon.m4 deleted file mode 100644 index 834b2e963f..0000000000 --- a/libs/spandsp/m4/ax_check_arm_neon.m4 +++ /dev/null @@ -1,59 +0,0 @@ -# @synopsis AX_CHECK_ARM_NEON -# -# Does the machine support the ARM NEON instruction set? -# @version 1.01 Feb 11 2013 -# @author Steve Underwood -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. - -AC_DEFUN([AX_CHECK_ARM_NEON], -[AC_CACHE_CHECK([if $1 supports the ARM NEON instructions set], - ac_cv_symbol_arm_neon, - -[# Initialize to unknown -ac_cv_symbol_arm_neon="no" - -case "${ax_cv_c_compiler_vendor}" in -gnu) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -mfpu=neon -mfloat-abi=hard" - AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [ - #include - #include - - int32x4_t testfunc(int16_t *a, int16_t *b) - { - return vmull_s16(vld1_s16(a), vld1_s16(b)); - } - ], - [ - volatile int32x4_t z; - int16_t x[[8]]; - int16_t y[[8]]; - z = testfunc(x, y); - ] - )], - - [AC_MSG_RESULT([yes]) - COMP_VENDOR_CFLAGS="-mfpu=neon $COMP_VENDOR_CFLAGS" - COMP_VENDOR_CXXFLAGS="-mfpu=neon $COMP_VENDOR_CXXFLAGS" - ac_cv_symbol_arm_neon="yes"], - - [AC_MSG_RESULT([no])], - - dnl Assume "no" if cross-compiling - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - -esac]) -AS_IF([test AS_VAR_GET(ac_cv_symbol_arm_neon) = yes], [$2], [$3])[]dnl -]) # AX_CHECK_ARM_NEON - diff --git a/libs/spandsp/m4/ax_check_export_capability.m4 b/libs/spandsp/m4/ax_check_export_capability.m4 deleted file mode 100644 index 952bb32139..0000000000 --- a/libs/spandsp/m4/ax_check_export_capability.m4 +++ /dev/null @@ -1,61 +0,0 @@ -# @synopsis AX_CHECK_EXPORT_CAPABILITY -# -# Does the compiler support the exporting of library symbols? -# @version 1.0 Jan 31 2009 -# @author Steve Underwood -# -# Permission to use, copy, modify, distribute, and sell this file for any -# purpose is hereby granted without fee, provided that the above copyright -# and this permission notice appear in all copies. No representations are -# made about the suitability of this software for any purpose. It is -# provided "as is" without express or implied warranty. - -AC_DEFUN([AX_CHECK_EXPORT_CAPABILITY], -[AC_CACHE_CHECK([if $1 supports library symbol export], - ac_cv_symbol_export_capability, - -[# Initialize to unknown -ac_cv_symbol_export_capability="no" - -case "${ax_cv_c_compiler_vendor}" in -gnu) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -fvisibility=hidden" - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [int foo __attribute__ ((visibility("default")));], - [;] - )], - - [AC_MSG_RESULT([yes]) - COMP_VENDOR_CFLAGS="-fvisibility=hidden -DHAVE_VISIBILITY=1 $COMP_VENDOR_CFLAGS" - COMP_VENDOR_CXXFLAGS="-fvisibility=hidden -DHAVE_VISIBILITY=1 $COMP_VENDOR_CXXFLAGS" - ac_cv_symbol_export_capability="yes"], - - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - -sun) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -xldscope=hidden" - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [int foo __attribute__ ((visibility("default")));], - [;] - )], - - [AC_MSG_RESULT([yes]) - COMP_VENDOR_CFLAGS="-xldscope=hidden -DHAVE_VISIBILITY=1 $COMP_VENDOR_CFLAGS" - COMP_VENDOR_CXXFLAGS="-xldscope=hidden -DHAVE_VISIBILITY=1 $COMP_VENDOR_CXXFLAGS" - ac_cv_symbol_export_capability="yes"], - - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - -esac]) -AS_IF([test AS_VAR_GET(ac_cv_symbol_export_capability) = yes], [$2], [$3])[]dnl -]) # AX_CHECK_EXPORT_CAPABILITY diff --git a/libs/spandsp/m4/ax_check_real_file.m4 b/libs/spandsp/m4/ax_check_real_file.m4 deleted file mode 100644 index 44fffa7515..0000000000 --- a/libs/spandsp/m4/ax_check_real_file.m4 +++ /dev/null @@ -1,27 +0,0 @@ -# AX_CHECK_REAL_FILE(FILE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# ------------------------------------------------------------------ -# -# Check for the existence of FILE, and make sure it is a real file or -# directory, and not a symbolic link. -# -AC_DEFUN([AX_CHECK_REAL_FILE], -[AC_DIAGNOSE([cross], - [cannot check for file existence when cross compiling])dnl -AS_VAR_PUSHDEF([ac_RealFile], [ac_cv_real_file_$1])dnl -AC_CACHE_CHECK([for $1], ac_RealFile, -[test "$cross_compiling" = yes && - AC_MSG_ERROR([cannot check for file existence when cross compiling]) -if test -r "$1" -then - if test -h "$1" - then - AS_VAR_SET(ac_RealFile, no) - else - AS_VAR_SET(ac_RealFile, yes) - fi -else - AS_VAR_SET(ac_RealFile, no) -fi]) -AS_IF([test AS_VAR_GET(ac_RealFile) = yes], [$2], [$3])[]dnl -AS_VAR_POPDEF([ac_RealFile])dnl -])# AX_CHECK_REAL_FILE diff --git a/libs/spandsp/m4/ax_compiler_vendor.m4 b/libs/spandsp/m4/ax_compiler_vendor.m4 deleted file mode 100644 index a9fc1d4c49..0000000000 --- a/libs/spandsp/m4/ax_compiler_vendor.m4 +++ /dev/null @@ -1,65 +0,0 @@ -# =========================================================================== -# http://autoconf-archive.cryp.to/ax_compiler_vendor.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_COMPILER_VENDOR -# -# DESCRIPTION -# -# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, -# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, -# watcom, etc. The vendor is returned in the cache variable -# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. -# -# LAST MODIFICATION -# -# 2008-04-12 -# -# COPYLEFT -# -# Copyright (c) 2008 Steven G. Johnson -# Copyright (c) 2008 Matteo Frigo -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# 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, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Macro Archive. When you make and -# distribute a modified version of the Autoconf Macro, you may extend this -# special exception to the GPL to apply to your modified version as well. - -AC_DEFUN([AX_COMPILER_VENDOR], -[ -AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, - [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown - # note: don't check for gcc first since some other compilers define __GNUC__ - for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ clang:__clang__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do - vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ -#if !($vencpp) - thisisanerror; -#endif -])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break]) - done - ]) -]) diff --git a/libs/spandsp/m4/ax_fixed_point_machine.m4 b/libs/spandsp/m4/ax_fixed_point_machine.m4 deleted file mode 100644 index d9309986c1..0000000000 --- a/libs/spandsp/m4/ax_fixed_point_machine.m4 +++ /dev/null @@ -1,35 +0,0 @@ -# AX_FIXED_POINT_MACHINE(MACHINE, [ACTION-IF-FIXED-POINT], [ACTION-IF-NOT-FIXED-POINT]) -# ------------------------------------------------------------------------------------- -# -# Check if a specified machine type is a fixed point only machine. That is, if it lacks -# fast floating point support. -# -# This is a simple lookup amongst machines known to the current autotools. So far we deal -# with the embedded ARM, Blackfin, MIPS, TI DSP and XScale processors as things which lack -# fast hardware floating point. -# -# Other candidates would be the small embedded Power PCs. -# -AC_DEFUN([AX_FIXED_POINT_MACHINE], -[AS_VAR_PUSHDEF([ac_FixedPoint], [ac_cv_fixed_point_machine_$1])dnl -AC_CACHE_CHECK([if $1 is fixed point only], ac_FixedPoint, -[case $1 in - arc \ - | arm | arm[bl]e | arme[bl] | armv[2345] | armv[345][bl] \ - | arm-* | arm[bl]e-* | arme[bl]-* | armv[345]-* \ - | bfin | bfin-* \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | tic54x | c54x* | tic55x | c55x* | tic6x | c6x* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | xscale | xscalee[bl] \ - | xscale-* | xscalee[bl]-* ) - AS_VAR_SET(ac_FixedPoint, yes) - ;; - *) - AS_VAR_SET(ac_FixedPoint, no) - ;; -esac]) -AS_IF([test AS_VAR_GET(ac_FixedPoint) = yes], [$2], [$3])[]dnl -AS_VAR_POPDEF([ac_FixedPoint])dnl -])# AX_FIXED_POINT_MACHINE diff --git a/libs/spandsp/m4/ax_func_aligned_alloc.m4 b/libs/spandsp/m4/ax_func_aligned_alloc.m4 deleted file mode 100644 index 1a236e1541..0000000000 --- a/libs/spandsp/m4/ax_func_aligned_alloc.m4 +++ /dev/null @@ -1,25 +0,0 @@ -# AX_FUNC_ALIGNED_ALLOC -# --------------------- -# -# Check for the function aligned_alloc() -# -AC_DEFUN([AX_FUNC_ALIGNED_ALLOC],[ -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -Werror" - AC_CACHE_CHECK([checking for aligned_alloc], - [ax_cv_func_aligned_alloc], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([ - #define _ISOC11_SOURCE - #include - ], - [ - aligned_alloc(0,0); - ])], - [ax_cv_func_aligned_alloc=yes], - [ax_cv_func_aligned_alloc=no])]) - - if test "x${ax_cv_func_aligned_alloc}" = "xyes" ; then - AC_DEFINE([HAVE_ALIGNED_ALLOC], [1], [Define to 1 if you have the aligned_alloc() function.]) - fi -CFLAGS="$saved_CFLAGS" -])# AX_ALIGNED_ALLOC diff --git a/libs/spandsp/m4/ax_misaligned_access_fails.m4 b/libs/spandsp/m4/ax_misaligned_access_fails.m4 deleted file mode 100644 index 6239e6d36e..0000000000 --- a/libs/spandsp/m4/ax_misaligned_access_fails.m4 +++ /dev/null @@ -1,33 +0,0 @@ -# AX_MISALIGNED_ACCESS_FAILS(MACHINE, [ACTION-IF-MISALIGNED-FAILS], [ACTION-IF-MISALIGNED-OK]) -# ------------------------------------------------------------------------------------- -# -# Check if a specified machine type cannot handle misaligned data. That is, multi-byte data -# types which are not properly aligned in memory fail. Many machines are happy to work with -# misaligned data, but slowing down a bit. Other machines just won't tolerate such data. -# -# This is a simple lookup amongst machines known to the current autotools. So far we only deal -# with the ARM and sparc. -# A lookup is used, as many of the devices which cannot handled misaligned access are embedded -# processors, for which the code normally be cross-compiled. -# -AC_DEFUN([AX_MISALIGNED_ACCESS_FAILS], -[AS_VAR_PUSHDEF([ac_MisalignedAccessFails], [ac_cv_misaligned_access_fails_$1])dnl -AC_CACHE_CHECK([if $1 fails on misaligned memory access], ac_MisalignedAccessFails, -[case $1 in - arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] \ - | bfin \ - | sparc \ - | xscale | xscalee[bl] \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | bfin-* \ - | sparc-* \ - | xscale-* | xscalee[bl]-* ) - AS_VAR_SET(ac_MisalignedAccessFails, yes) - ;; - *) - AS_VAR_SET(ac_MisalignedAccessFails, no) - ;; -esac]) -AS_IF([test AS_VAR_GET(ac_MisalignedAccessFails) = yes], [$2], [$3])[]dnl -AS_VAR_POPDEF([ac_MisalignedAccessFails])dnl -])# MISALIGNED_ACCESS_FAILS diff --git a/libs/spandsp/spandsp-sim/Makefile.am b/libs/spandsp/spandsp-sim/Makefile.am deleted file mode 100644 index 4eb86c4b49..0000000000 --- a/libs/spandsp/spandsp-sim/Makefile.am +++ /dev/null @@ -1,126 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -AM_CFLAGS = $(COMP_VENDOR_CFLAGS) -AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) - -LIBS += -L$(top_builddir)/src -lspandsp $(SIMLIBS) - -MAINTAINERCLEANFILES = Makefile.in - -EXTRA_DIST = libspandsp_sim.dsp \ - libspandsp_sim.2005.vcproj \ - libspandsp_sim.2008.vcproj \ - msvc/make_line_models.2008.vcproj \ - msvc/msvcproj.head \ - msvc/msvcproj.foot \ - msvc/vc8proj.head \ - msvc/vc8proj.foot \ - msvc/vc9proj.head \ - msvc/vc9proj.foot - -AM_CPPFLAGS = -I$(top_builddir) -I$(top_builddir)/src -DDATADIR="\"$(pkgdatadir)\"" - -noinst_PROGRAMS = make_line_models - -lib_LTLIBRARIES = libspandsp-sim.la - -libspandsp_sim_la_SOURCES = g1050.c \ - line_model.c \ - rfc2198_sim.c \ - test_utils.c - -nodist_libspandsp_sim_la_SOURCES = line_models.c - -libspandsp_sim_la_LDFLAGS = -version-info @SPANDSP_LT_CURRENT@:@SPANDSP_LT_REVISION@:@SPANDSP_LT_AGE@ $(COMP_VENDOR_LDFLAGS) - -nobase_include_HEADERS = spandsp/g1050.h \ - spandsp/line_model.h \ - spandsp/line_models.h \ - spandsp/rfc2198_sim.h \ - spandsp/test_utils.h \ - spandsp-sim.h - -make_line_models_SOURCES = make_line_models.c -make_line_models_LDADD = -L$(top_builddir)/src -lspandsp - -# We need to run make_line_models, so it generates the line_models.h file -# used by several of the test programs. - -line_models.lo: make_line_models$(EXEEXT) line_models.c - -line_models.$(OBJEXT): make_line_models$(EXEEXT) line_models.c - -line_models.c: make_line_models$(EXEEXT) - ./make_line_models$(EXEEXT) - -DSP = libspandsp_sim.dsp -VCPROJ8 = libspandsp_sim.2005.vcproj -VCPROJ9 = libspandsp_sim.2008.vcproj - -WIN32SOURCES = $(libspandsp_sim_la_SOURCES) -WIN32HEADERS = $(nobase_include_HEADERS) - -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) ) - -$(VCPROJ8): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am - echo "creating $(VCPROJ8)" - @(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ8); \ - for file in $(WIN32SOURCES); do \ - echo "" $(VCPROJOUT8); \ - done; \ - echo "
" $(VCPROJOUT8); \ - for file in $(WIN32HEADERS); do \ - echo "" $(VCPROJOUT8); \ - done; \ - cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT8) ) - -$(VCPROJ9): msvc/vc9proj.head msvc/vc9proj.foot Makefile.am - echo "creating $(VCPROJ9)" - @(cp $(srcdir)/msvc/vc9proj.head $(VCPROJ9); \ - for file in $(WIN32SOURCES); do \ - echo "" $(VCPROJOUT9); \ - done; \ - echo "" $(VCPROJOUT9); \ - for file in $(WIN32HEADERS); do \ - echo "" $(VCPROJOUT9); \ - done; \ - cat $(srcdir)/msvc/vc9proj.foot $(VCPROJOUT9) ) diff --git a/libs/spandsp/spandsp-sim/g1050.c b/libs/spandsp/spandsp-sim/g1050.c deleted file mode 100644 index ed7d8e900b..0000000000 --- a/libs/spandsp/spandsp-sim/g1050.c +++ /dev/null @@ -1,1336 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g1050.c - IP network modeling, as per G.1050/TIA-921. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#define GEN_CONST -#include -#endif -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif -#include "floating_fudge.h" - -#include "spandsp.h" -#include "spandsp/g1050.h" - -#define PACKET_LOSS_TIME -1 - -g1050_constants_t g1050_constants[1] = -{ - { - { - { /* Side A LAN */ - { - 0.004, /*! Probability of loss rate change low->high */ - 0.1 /*! Probability of loss rate change high->low */ - }, - { - { - 0.0, /*! Probability of an impulse */ - 0.0, - }, - { - 0.5, - 0.0 - } - }, - 1.0, /*! Impulse height, based on MTU and bit rate */ - 0.0, /*! Impulse decay coefficient */ - 0.001, /*! Probability of packet loss due to occupancy. */ - 0.15 /*! Probability of packet loss due to a multiple access collision. */ - }, - { /* Side A access link */ - { - 0.0002, /*! Probability of loss rate change low->high */ - 0.2 /*! Probability of loss rate change high->low */ - }, - { - { - 0.001, /*! Probability of an impulse */ - 0.0, - }, - { - 0.3, - 0.4 - } - }, - 40.0, /*! Impulse height, based on MTU and bit rate */ - 0.75, /*! Impulse decay coefficient */ - 0.0005, /*! Probability of packet loss due to occupancy. */ - 0.0 /*! Probability of packet loss due to a multiple access collision. */ - }, - { /* Side B access link */ - { - 0.0002, /*! Probability of loss rate change low->high */ - 0.2 /*! Probability of loss rate change high->low */ - }, - { - { - 0.001, /*! Probability of an impulse */ - 0.0, - }, - { - 0.3, - 0.4 - } - }, - 40.0, /*! Impulse height, based on MTU and bit rate */ - 0.75, /*! Impulse decay coefficient */ - 0.0005, /*! Probability of packet loss due to occupancy. */ - 0.0 /*! Probability of packet loss due to a multiple access collision. */ - }, - { /* Side B LAN */ - { - 0.004, /*! Probability of loss rate change low->high */ - 0.1 /*! Probability of loss rate change high->low */ - }, - { - { - 0.0, /*! Probability of an impulse */ - 0.0, - }, - { - 0.5, - 0.0 - } - }, - 1.0, /*! Impulse height, based on MTU and bit rate */ - 0.0, /*! Impulse decay coefficient */ - 0.001, /*! Probability of packet loss due to occupancy. */ - 0.15 /*! Probability of packet loss due to a multiple access collision. */ - } - } - } -}; - -g1050_channel_speeds_t g1050_speed_patterns[168] = -{ - { 4000000, 0, 128000, 768000, 0, 4000000, 0, 128000, 768000, 0, 0.360}, - { 4000000, 0, 128000, 768000, 0, 20000000, 0, 128000, 768000, 0, 0.720}, - { 4000000, 0, 128000, 768000, 0, 100000000, 0, 128000, 768000, 0, 0.360}, - { 20000000, 0, 128000, 768000, 0, 20000000, 0, 128000, 768000, 0, 0.360}, - { 20000000, 0, 128000, 768000, 0, 100000000, 0, 128000, 768000, 0, 0.360}, - {100000000, 0, 128000, 768000, 0, 100000000, 0, 128000, 768000, 0, 0.090}, - { 4000000, 0, 128000, 1536000, 0, 4000000, 0, 384000, 768000, 0, 0.720}, - { 4000000, 0, 128000, 1536000, 0, 20000000, 0, 384000, 768000, 0, 1.470}, - { 4000000, 0, 128000, 1536000, 0, 100000000, 0, 384000, 768000, 0, 0.840}, - { 20000000, 0, 128000, 1536000, 0, 20000000, 0, 384000, 768000, 0, 0.750}, - { 20000000, 0, 128000, 1536000, 0, 100000000, 0, 384000, 768000, 0, 0.855}, - {100000000, 0, 128000, 1536000, 0, 100000000, 0, 384000, 768000, 0, 0.240}, - { 4000000, 0, 128000, 3000000, 0, 4000000, 0, 384000, 768000, 0, 0.120}, - { 4000000, 0, 128000, 3000000, 0, 20000000, 0, 384000, 768000, 0, 0.420}, - { 4000000, 0, 128000, 3000000, 0, 100000000, 0, 384000, 768000, 0, 0.840}, - { 20000000, 0, 128000, 3000000, 0, 20000000, 0, 384000, 768000, 0, 0.300}, - { 20000000, 0, 128000, 3000000, 0, 100000000, 0, 384000, 768000, 0, 0.930}, - {100000000, 0, 128000, 3000000, 0, 100000000, 0, 384000, 768000, 0, 0.390}, - { 4000000, 0, 384000, 768000, 0, 4000000, 0, 128000, 1536000, 0, 0.720}, - { 4000000, 0, 384000, 768000, 0, 20000000, 0, 128000, 1536000, 0, 1.470}, - { 4000000, 0, 384000, 768000, 0, 100000000, 0, 128000, 1536000, 0, 0.840}, - { 20000000, 0, 384000, 768000, 0, 20000000, 0, 128000, 1536000, 0, 0.750}, - { 20000000, 0, 384000, 768000, 0, 100000000, 0, 128000, 1536000, 0, 0.855}, - {100000000, 0, 384000, 768000, 0, 100000000, 0, 128000, 1536000, 0, 0.240}, - { 4000000, 0, 384000, 1536000, 0, 4000000, 0, 384000, 1536000, 0, 1.440}, - { 4000000, 0, 384000, 1536000, 0, 20000000, 0, 384000, 1536000, 0, 3.000}, - { 4000000, 0, 384000, 1536000, 0, 100000000, 0, 384000, 1536000, 0, 1.920}, - { 20000000, 0, 384000, 1536000, 0, 20000000, 0, 384000, 1536000, 0, 1.563}, - { 20000000, 0, 384000, 1536000, 0, 100000000, 0, 384000, 1536000, 0, 2.000}, - {100000000, 0, 384000, 1536000, 0, 100000000, 0, 384000, 1536000, 0, 0.640}, - { 4000000, 0, 384000, 3000000, 0, 4000000, 0, 384000, 1536000, 0, 0.240}, - { 4000000, 0, 384000, 3000000, 0, 20000000, 0, 384000, 1536000, 0, 0.850}, - { 4000000, 0, 384000, 3000000, 0, 100000000, 0, 384000, 1536000, 0, 1.720}, - { 20000000, 0, 384000, 3000000, 0, 20000000, 0, 384000, 1536000, 0, 0.625}, - { 20000000, 0, 384000, 3000000, 0, 100000000, 0, 384000, 1536000, 0, 2.025}, - {100000000, 0, 384000, 3000000, 0, 100000000, 0, 384000, 1536000, 0, 1.040}, - { 4000000, 0, 384000, 768000, 0, 4000000, 0, 128000, 3000000, 0, 0.120}, - { 4000000, 0, 384000, 768000, 0, 20000000, 0, 128000, 3000000, 0, 0.420}, - { 4000000, 0, 384000, 768000, 0, 100000000, 0, 128000, 3000000, 0, 0.840}, - { 20000000, 0, 384000, 768000, 0, 20000000, 0, 128000, 3000000, 0, 0.300}, - { 20000000, 0, 384000, 768000, 0, 100000000, 0, 128000, 3000000, 0, 0.930}, - {100000000, 0, 384000, 768000, 0, 100000000, 0, 128000, 3000000, 0, 0.390}, - { 4000000, 0, 384000, 1536000, 0, 4000000, 0, 384000, 3000000, 0, 0.240}, - { 4000000, 0, 384000, 1536000, 0, 20000000, 0, 384000, 3000000, 0, 0.850}, - { 4000000, 0, 384000, 1536000, 0, 100000000, 0, 384000, 3000000, 0, 1.720}, - { 20000000, 0, 384000, 1536000, 0, 20000000, 0, 384000, 3000000, 0, 0.625}, - { 20000000, 0, 384000, 1536000, 0, 100000000, 0, 384000, 3000000, 0, 2.025}, - {100000000, 0, 384000, 1536000, 0, 100000000, 0, 384000, 3000000, 0, 1.040}, - { 4000000, 0, 384000, 3000000, 0, 4000000, 0, 384000, 3000000, 0, 0.040}, - { 4000000, 0, 384000, 3000000, 0, 20000000, 0, 384000, 3000000, 0, 0.200}, - { 4000000, 0, 384000, 3000000, 0, 100000000, 0, 384000, 3000000, 0, 0.520}, - { 20000000, 0, 384000, 3000000, 0, 20000000, 0, 384000, 3000000, 0, 0.250}, - { 20000000, 0, 384000, 3000000, 0, 100000000, 0, 384000, 3000000, 0, 1.300}, - {100000000, 0, 384000, 3000000, 0, 100000000, 0, 384000, 3000000, 0, 1.690}, - { 4000000, 0, 128000, 1536000, 0, 20000000, 0, 768000, 1536000, 0, 0.090}, - { 4000000, 0, 128000, 1536000, 0, 100000000, 0, 768000, 1536000, 0, 0.360}, - { 20000000, 0, 128000, 1536000, 0, 20000000, 0, 768000, 1536000, 0, 0.090}, - { 20000000, 0, 128000, 1536000, 0, 100000000, 0, 768000, 1536000, 0, 0.405}, - {100000000, 0, 128000, 1536000, 0, 100000000, 0, 768000, 1536000, 0, 0.180}, - { 4000000, 0, 128000, 7000000, 0, 20000000, 0, 768000, 768000, 0, 0.270}, - { 4000000, 0, 128000, 7000000, 0, 100000000, 0, 768000, 768000, 0, 1.080}, - { 20000000, 0, 128000, 7000000, 0, 20000000, 0, 768000, 768000, 0, 0.270}, - { 20000000, 0, 128000, 7000000, 0, 100000000, 0, 768000, 768000, 0, 1.215}, - {100000000, 0, 128000, 7000000, 0, 100000000, 0, 768000, 768000, 0, 0.540}, - { 4000000, 0, 128000, 13000000, 0, 20000000, 0, 768000, 13000000, 0, 0.030}, - { 4000000, 0, 128000, 13000000, 0, 100000000, 0, 768000, 13000000, 0, 0.120}, - { 20000000, 0, 128000, 13000000, 0, 20000000, 0, 768000, 13000000, 0, 0.030}, - { 20000000, 0, 128000, 13000000, 0, 100000000, 0, 768000, 13000000, 0, 0.135}, - {100000000, 0, 128000, 13000000, 0, 100000000, 0, 768000, 13000000, 0, 0.060}, - { 4000000, 0, 384000, 1536000, 0, 20000000, 0, 1536000, 1536000, 0, 0.180}, - { 4000000, 0, 384000, 1536000, 0, 100000000, 0, 1536000, 1536000, 0, 0.720}, - { 20000000, 0, 384000, 1536000, 0, 20000000, 0, 1536000, 1536000, 0, 0.188}, - { 20000000, 0, 384000, 1536000, 0, 100000000, 0, 1536000, 1536000, 0, 0.870}, - {100000000, 0, 384000, 1536000, 0, 100000000, 0, 1536000, 1536000, 0, 0.480}, - { 4000000, 0, 384000, 7000000, 0, 20000000, 0, 768000, 1536000, 0, 0.540}, - { 4000000, 0, 384000, 7000000, 0, 100000000, 0, 768000, 1536000, 0, 2.160}, - { 20000000, 0, 384000, 7000000, 0, 20000000, 0, 768000, 1536000, 0, 0.563}, - { 20000000, 0, 384000, 7000000, 0, 100000000, 0, 768000, 1536000, 0, 2.610}, - {100000000, 0, 384000, 7000000, 0, 100000000, 0, 768000, 1536000, 0, 1.440}, - { 4000000, 0, 384000, 13000000, 0, 20000000, 0, 1536000, 13000000, 0, 0.060}, - { 4000000, 0, 384000, 13000000, 0, 100000000, 0, 1536000, 13000000, 0, 0.240}, - { 20000000, 0, 384000, 13000000, 0, 20000000, 0, 1536000, 13000000, 0, 0.063}, - { 20000000, 0, 384000, 13000000, 0, 100000000, 0, 1536000, 13000000, 0, 0.290}, - {100000000, 0, 384000, 13000000, 0, 100000000, 0, 1536000, 13000000, 0, 0.160}, - { 4000000, 0, 384000, 1536000, 0, 20000000, 0, 1536000, 3000000, 0, 0.030}, - { 4000000, 0, 384000, 1536000, 0, 100000000, 0, 1536000, 3000000, 0, 0.120}, - { 20000000, 0, 384000, 1536000, 0, 20000000, 0, 1536000, 3000000, 0, 0.075}, - { 20000000, 0, 384000, 1536000, 0, 100000000, 0, 1536000, 3000000, 0, 0.495}, - {100000000, 0, 384000, 1536000, 0, 100000000, 0, 1536000, 3000000, 0, 0.780}, - { 4000000, 0, 384000, 7000000, 0, 20000000, 0, 768000, 3000000, 0, 0.090}, - { 4000000, 0, 384000, 7000000, 0, 100000000, 0, 768000, 3000000, 0, 0.360}, - { 20000000, 0, 384000, 7000000, 0, 20000000, 0, 768000, 3000000, 0, 0.225}, - { 20000000, 0, 384000, 7000000, 0, 100000000, 0, 768000, 3000000, 0, 1.485}, - {100000000, 0, 384000, 7000000, 0, 100000000, 0, 768000, 3000000, 0, 2.340}, - { 4000000, 0, 384000, 13000000, 0, 20000000, 0, 3000000, 13000000, 0, 0.010}, - { 4000000, 0, 384000, 13000000, 0, 100000000, 0, 3000000, 13000000, 0, 0.040}, - { 20000000, 0, 384000, 13000000, 0, 20000000, 0, 3000000, 13000000, 0, 0.025}, - { 20000000, 0, 384000, 13000000, 0, 100000000, 0, 3000000, 13000000, 0, 0.165}, - {100000000, 0, 384000, 13000000, 0, 100000000, 0, 3000000, 13000000, 0, 0.260}, - { 4000000, 0, 768000, 1536000, 0, 20000000, 0, 128000, 1536000, 0, 0.090}, - { 20000000, 0, 768000, 1536000, 0, 20000000, 0, 128000, 1536000, 0, 0.090}, - { 20000000, 0, 768000, 1536000, 0, 100000000, 0, 128000, 1536000, 0, 0.405}, - { 4000000, 0, 768000, 1536000, 0, 100000000, 0, 128000, 1536000, 0, 0.360}, - {100000000, 0, 768000, 1536000, 0, 100000000, 0, 128000, 1536000, 0, 0.180}, - { 4000000, 0, 1536000, 1536000, 0, 20000000, 0, 384000, 1536000, 0, 0.180}, - { 20000000, 0, 1536000, 1536000, 0, 20000000, 0, 384000, 1536000, 0, 0.188}, - { 20000000, 0, 1536000, 1536000, 0, 100000000, 0, 384000, 1536000, 0, 0.870}, - { 4000000, 0, 1536000, 1536000, 0, 100000000, 0, 384000, 1536000, 0, 0.720}, - {100000000, 0, 1536000, 1536000, 0, 100000000, 0, 384000, 1536000, 0, 0.480}, - { 4000000, 0, 1536000, 3000000, 0, 20000000, 0, 384000, 1536000, 0, 0.030}, - { 20000000, 0, 1536000, 3000000, 0, 20000000, 0, 384000, 1536000, 0, 0.075}, - { 20000000, 0, 1536000, 3000000, 0, 100000000, 0, 384000, 1536000, 0, 0.495}, - { 4000000, 0, 1536000, 3000000, 0, 100000000, 0, 384000, 1536000, 0, 0.120}, - {100000000, 0, 1536000, 3000000, 0, 100000000, 0, 384000, 1536000, 0, 0.780}, - { 4000000, 0, 768000, 768000, 0, 20000000, 0, 128000, 7000000, 0, 0.270}, - { 20000000, 0, 768000, 768000, 0, 20000000, 0, 128000, 7000000, 0, 0.270}, - { 20000000, 0, 768000, 768000, 0, 100000000, 0, 128000, 7000000, 0, 1.215}, - { 4000000, 0, 768000, 768000, 0, 100000000, 0, 128000, 7000000, 0, 1.080}, - {100000000, 0, 768000, 768000, 0, 100000000, 0, 128000, 7000000, 0, 0.540}, - { 4000000, 0, 768000, 1536000, 0, 20000000, 0, 384000, 7000000, 0, 0.540}, - { 20000000, 0, 768000, 1536000, 0, 20000000, 0, 384000, 7000000, 0, 0.563}, - { 20000000, 0, 768000, 1536000, 0, 100000000, 0, 384000, 7000000, 0, 2.610}, - { 4000000, 0, 768000, 1536000, 0, 100000000, 0, 384000, 7000000, 0, 2.160}, - {100000000, 0, 768000, 1536000, 0, 100000000, 0, 384000, 7000000, 0, 1.440}, - { 4000000, 0, 768000, 3000000, 0, 20000000, 0, 384000, 7000000, 0, 0.090}, - { 20000000, 0, 768000, 3000000, 0, 20000000, 0, 384000, 7000000, 0, 0.225}, - { 20000000, 0, 768000, 3000000, 0, 100000000, 0, 384000, 7000000, 0, 1.485}, - { 4000000, 0, 768000, 3000000, 0, 100000000, 0, 384000, 7000000, 0, 0.360}, - {100000000, 0, 768000, 3000000, 0, 100000000, 0, 384000, 7000000, 0, 2.340}, - { 4000000, 0, 768000, 13000000, 0, 20000000, 0, 128000, 13000000, 0, 0.030}, - { 20000000, 0, 768000, 13000000, 0, 20000000, 0, 128000, 13000000, 0, 0.030}, - { 20000000, 0, 768000, 13000000, 0, 100000000, 0, 128000, 13000000, 0, 0.135}, - { 4000000, 0, 768000, 13000000, 0, 100000000, 0, 128000, 13000000, 0, 0.120}, - {100000000, 0, 768000, 13000000, 0, 100000000, 0, 128000, 13000000, 0, 0.060}, - { 4000000, 0, 1536000, 13000000, 0, 20000000, 0, 384000, 13000000, 0, 0.060}, - { 20000000, 0, 1536000, 13000000, 0, 20000000, 0, 384000, 13000000, 0, 0.063}, - { 20000000, 0, 1536000, 13000000, 0, 100000000, 0, 384000, 13000000, 0, 0.290}, - { 4000000, 0, 1536000, 13000000, 0, 100000000, 0, 384000, 13000000, 0, 0.240}, - {100000000, 0, 1536000, 13000000, 0, 100000000, 0, 384000, 13000000, 0, 0.160}, - { 4000000, 0, 3000000, 13000000, 0, 20000000, 0, 384000, 13000000, 0, 0.010}, - { 20000000, 0, 3000000, 13000000, 0, 20000000, 0, 384000, 13000000, 0, 0.025}, - { 20000000, 0, 3000000, 13000000, 0, 100000000, 0, 384000, 13000000, 0, 0.165}, - { 4000000, 0, 3000000, 13000000, 0, 100000000, 0, 384000, 13000000, 0, 0.040}, - {100000000, 0, 3000000, 13000000, 0, 100000000, 0, 384000, 13000000, 0, 0.260}, - { 20000000, 0, 1536000, 1536000, 0, 20000000, 0, 1536000, 1536000, 0, 0.023}, - { 20000000, 0, 1536000, 1536000, 0, 100000000, 0, 1536000, 1536000, 0, 0.180}, - {100000000, 0, 1536000, 1536000, 0, 100000000, 0, 1536000, 1536000, 0, 0.360}, - { 20000000, 0, 1536000, 7000000, 0, 20000000, 0, 768000, 1536000, 0, 0.068}, - { 20000000, 0, 1536000, 7000000, 0, 100000000, 0, 768000, 1536000, 0, 0.540}, - {100000000, 0, 1536000, 7000000, 0, 100000000, 0, 768000, 1536000, 0, 1.080}, - { 20000000, 0, 1536000, 13000000, 0, 20000000, 0, 1536000, 13000000, 0, 0.015}, - { 20000000, 0, 1536000, 13000000, 0, 100000000, 0, 1536000, 13000000, 0, 0.120}, - {100000000, 0, 1536000, 13000000, 0, 100000000, 0, 1536000, 13000000, 0, 0.240}, - { 20000000, 0, 768000, 1536000, 0, 20000000, 0, 1536000, 7000000, 0, 0.068}, - { 20000000, 0, 768000, 1536000, 0, 100000000, 0, 1536000, 7000000, 0, 0.540}, - {100000000, 0, 768000, 1536000, 0, 100000000, 0, 1536000, 7000000, 0, 1.080}, - { 20000000, 0, 768000, 7000000, 0, 20000000, 0, 768000, 7000000, 0, 0.203}, - { 20000000, 0, 768000, 7000000, 0, 100000000, 0, 768000, 7000000, 0, 1.620}, - {100000000, 0, 768000, 7000000, 0, 100000000, 0, 768000, 7000000, 0, 3.240}, - { 20000000, 0, 768000, 13000000, 0, 20000000, 0, 7000000, 13000000, 0, 0.023}, - { 20000000, 0, 768000, 13000000, 0, 100000000, 0, 7000000, 13000000, 0, 0.180}, - {100000000, 0, 768000, 13000000, 0, 100000000, 0, 7000000, 13000000, 0, 0.360}, - { 20000000, 0, 7000000, 13000000, 0, 20000000, 0, 768000, 13000000, 0, 0.023}, - { 20000000, 0, 7000000, 13000000, 0, 100000000, 0, 768000, 13000000, 0, 0.180}, - {100000000, 0, 7000000, 13000000, 0, 100000000, 0, 768000, 13000000, 0, 0.360}, - { 20000000, 0, 13000000, 13000000, 0, 20000000, 0, 13000000, 13000000, 0, 0.003}, - { 20000000, 0, 13000000, 13000000, 0, 100000000, 0, 13000000, 13000000, 0, 0.020}, - {100000000, 0, 13000000, 13000000, 0, 100000000, 0, 13000000, 13000000, 0, 0.040} -}; - -g1050_model_t g1050_standard_models[9] = -{ - { /* Severity 0 - no impairment */ - { - 0, /*! Percentage likelihood of occurance in scenario A */ - 0, /*! Percentage likelihood of occurance in scenario B */ - 0, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 0.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.0, /*! Percentage occupancy */ - 512, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.0, /*! Basic delay of the regional backbone, in seconds */ - 0.0, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.0, /*! Percentage packet loss of the backbone */ - 0.0, /*! Maximum jitter of the backbone, in seconds */ - 0.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.0, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 0.0, /*! The interval between link failures, in seconds */ - 0.0, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 0.0, /*! Percentage occupancy */ - 512, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - } - }, - { /* Severity A */ - { - 50, /*! Percentage likelihood of occurance in scenario A */ - 5, /*! Percentage likelihood of occurance in scenario B */ - 5, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 1.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 0.0, /*! Percentage occupancy */ - 512, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.004, /*! Basic delay of the regional backbone, in seconds */ - 0.016, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.0, /*! Percentage packet loss of the backbone */ - 0.005, /*! Maximum jitter of the backbone, in seconds */ - 0.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.0, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 0.0, /*! The interval between link failures, in seconds */ - 0.0, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 0.0, /*! Percentage occupancy */ - 512, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 1.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity B */ - { - 30, /*! Percentage likelihood of occurance in scenario A */ - 25, /*! Percentage likelihood of occurance in scenario B */ - 5, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 2.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 1.0, /*! Percentage occupancy */ - 512, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.008, /*! Basic delay of the regional backbone, in seconds */ - 0.032, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.01, /*! Percentage packet loss of the backbone */ - 0.01, /*! Maximum jitter of the backbone, in seconds */ - 3600.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.002, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 3600.0, /*! The interval between link failures, in seconds */ - 0.064, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 1.0, /*! Percentage occupancy */ - 512, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 2.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity C */ - { - 15, /*! Percentage likelihood of occurance in scenario A */ - 30, /*! Percentage likelihood of occurance in scenario B */ - 10, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 3.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 2.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.016, /*! Basic delay of the regional backbone, in seconds */ - 0.064, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.02, /*! Percentage packet loss of the backbone */ - 0.016, /*! Maximum jitter of the backbone, in seconds */ - 1800.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.004, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 1800.0, /*! The interval between link failures, in seconds */ - 0.128, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 2.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 3.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity D */ - { - 5, /*! Percentage likelihood of occurance in scenario A */ - 25, /*! Percentage likelihood of occurance in scenario B */ - 15, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 5.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 4.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.032, /*! Basic delay of the regional backbone, in seconds */ - 0.128, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.04, /*! Percentage packet loss of the backbone */ - 0.04, /*! Maximum jitter of the backbone, in seconds */ - 900.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.008, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 900.0, /*! The interval between link failures, in seconds */ - 0.256, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 4.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 5.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity E */ - { - 0, /*! Percentage likelihood of occurance in scenario A */ - 10, /*! Percentage likelihood of occurance in scenario B */ - 20, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 8.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 8.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.064, /*! Basic delay of the regional backbone, in seconds */ - 0.196, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.1, /*! Percentage packet loss of the backbone */ - 0.07, /*! Maximum jitter of the backbone, in seconds */ - 480.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.016, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 480.0, /*! The interval between link failures, in seconds */ - 0.4, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 8.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 8.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity F */ - { - 0, /*! Percentage likelihood of occurance in scenario A */ - 0, /*! Percentage likelihood of occurance in scenario B */ - 25, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 12.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 15.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.128, /*! Basic delay of the regional backbone, in seconds */ - 0.256, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.2, /*! Percentage packet loss of the backbone */ - 0.1, /*! Maximum jitter of the backbone, in seconds */ - 240.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.032, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 240.0, /*! The interval between link failures, in seconds */ - 0.8, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 15.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 12.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity G */ - { - 0, /*! Percentage likelihood of occurance in scenario A */ - 0, /*! Percentage likelihood of occurance in scenario B */ - 15, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 16.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 30.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.256, /*! Basic delay of the regional backbone, in seconds */ - 0.512, /*! Basic delay of the intercontinental backbone, in seconds */ - 0.5, /*! Percentage packet loss of the backbone */ - 0.15, /*! Maximum jitter of the backbone, in seconds */ - 120.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.064, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 120.0, /*! The interval between link failures, in seconds */ - 1.6, /*! The duration of link failures, in seconds */ - 0.0, /*! Probability of packet loss in the backbone, in percent */ - 0.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 30.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 16.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - }, - { /* Severity H */ - { - 0, /*! Percentage likelihood of occurance in scenario A */ - 0, /*! Percentage likelihood of occurance in scenario B */ - 5, /*! Percentage likelihood of occurance in scenario C */ - }, - { - 20.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - }, - { - 50.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 0.512, /*! Basic delay of the regional backbone, in seconds */ - 0.768, /*! Basic delay of the intercontinental backbone, in seconds */ - 1.0, /*! Percentage packet loss of the backbone */ - 0.5, /*! Maximum jitter of the backbone, in seconds */ - 60.0, /*! Interval between the backbone route flapping between two paths, in seconds */ - 0.128, /*! The difference in backbone delay between the two routes we flap between, in seconds */ - 60.0, /*! The interval between link failures, in seconds */ - 3.0, /*! The duration of link failures, in seconds */ - 1.0, /*! Probability of packet loss in the backbone, in percent */ - 1.0 /*! Probability of a packet going out of sequence in the backbone. */ - }, - { - 50.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0 /*! Peak jitter */ - }, - { - 20.0, /*! Percentage occupancy */ - 1508, /*! MTU */ - 0.0015 /*! Peak jitter */ - } - } -}; - -#if defined(HAVE_DRAND48) -static __inline__ void q1050_rand_init(void) -{ - srand48(time(NULL)); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ double q1050_rand(void) -{ - return drand48(); -} -/*- End of function --------------------------------------------------------*/ -#else -static __inline__ void q1050_rand_init(void) -{ - srand(time(NULL)); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ double q1050_rand(void) -{ - return (double) rand()/(double) RAND_MAX; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ double scale_probability(double prob, double scale) -{ - /* Re-calculate probability based on a different time interval */ - return 1.0 - pow(1.0 - prob, scale); -} -/*- End of function --------------------------------------------------------*/ - -static void g1050_segment_init(g1050_segment_state_t *s, - int link_type, - g1050_segment_constants_t *constants, - g1050_segment_model_t *parms, - int bit_rate, - int multiple_access, - int qos_enabled, - int packet_size, - int packet_rate) -{ - double x; - double packet_interval; - - memset(s, 0, sizeof(*s)); - - packet_interval = 1000.0/packet_rate; - /* Some calculatons are common to both LAN and access links, and those that are not. */ - s->link_type = link_type; - s->prob_loss_rate_change[0] = scale_probability(constants->prob_loss_rate_change[0]*parms->percentage_occupancy, 1.0/packet_interval); - - s->serial_delay = packet_size*8.0/bit_rate; - if (link_type == G1050_LAN_LINK) - { - s->prob_loss_rate_change[1] = scale_probability(constants->prob_loss_rate_change[1], 1.0/packet_interval); - s->prob_impulse[0] = constants->prob_impulse[0][0]; - s->prob_impulse[1] = constants->prob_impulse[1][0]; - s->impulse_coeff = constants->impulse_coeff; - s->impulse_height = parms->mtu*(8.0/bit_rate)*(1.0 + parms->percentage_occupancy/constants->impulse_height); - } - else if (link_type == G1050_ACCESS_LINK) - { - s->prob_loss_rate_change[1] = scale_probability(constants->prob_loss_rate_change[1]/(1.0 + parms->percentage_occupancy), 1.0/packet_interval); - s->prob_impulse[0] = scale_probability(constants->prob_impulse[0][0] + (parms->percentage_occupancy/2000.0), 1.0/packet_interval); - s->prob_impulse[1] = scale_probability(constants->prob_impulse[1][0] + (constants->prob_impulse[1][1]*parms->percentage_occupancy/100.0), 1.0/packet_interval); - s->impulse_coeff = 1.0 - scale_probability(1.0 - constants->impulse_coeff, 1.0/packet_interval); - x = (1.0 - constants->impulse_coeff)/(1.0 - s->impulse_coeff); - s->impulse_height = x*parms->mtu*(8.0/bit_rate)*(1.0 + parms->percentage_occupancy/constants->impulse_height); - } - - /* The following are calculated the same way for LAN and access links */ - s->prob_packet_loss = constants->prob_packet_loss*parms->percentage_occupancy; - s->qos_enabled = qos_enabled; - s->multiple_access = multiple_access; - s->prob_packet_collision_loss = constants->prob_packet_collision_loss; - s->max_jitter = parms->max_jitter; - - /* The following is common state information to all links. */ - s->high_loss = false; - s->congestion_delay = 0.0; - s->last_arrival_time = 0.0; - - /* Count of packets lost in this segment. */ - s->lost_packets = 0; - s->lost_packets_2 = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void g1050_core_init(g1050_core_state_t *s, g1050_core_model_t *parms, int packet_rate) -{ - memset(s, 0, sizeof(*s)); - - /* Set up route flapping. */ - /* This is the length of the period of both the delayed duration and the non-delayed. */ - s->route_flap_interval = parms->route_flap_interval*G1050_TICKS_PER_SEC; - - /* How much additional delay is added or subtracted during route flaps. */ - s->route_flap_delta = parms->route_flap_delay; - - /* Current tick count. This is initialized so that we are part way into the first - CLEAN interval before the first change occurs. This is a random portion of the - period. When we reach the first flap, the flapping in both directions becomes - periodic. */ - s->route_flap_counter = s->route_flap_interval - 99 - floor(s->route_flap_interval*q1050_rand()); - s->link_failure_interval_ticks = parms->link_failure_interval*G1050_TICKS_PER_SEC; - - /* Link failures occur when the count reaches this number of ticks. */ - /* Duration of a failure. */ - s->link_failure_duration_ticks = floor((G1050_TICKS_PER_SEC*parms->link_failure_duration)); - /* How far into the first CLEAN interval we are. This is like the route flap initialzation. */ - s->link_failure_counter = s->link_failure_interval_ticks - 99 - floor(s->link_failure_interval_ticks*q1050_rand()); - s->link_recovery_counter = s->link_failure_duration_ticks; - - s->base_delay = parms->base_regional_delay; - s->max_jitter = parms->max_jitter; - s->prob_packet_loss = parms->prob_packet_loss/100.0; - s->prob_oos = parms->prob_oos/100.0; - s->last_arrival_time = 0.0; - s->delay_delta = 0; - - /* Count of packets lost in this segment. */ - s->lost_packets = 0; - s->lost_packets_2 = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void g1050_segment_model(g1050_segment_state_t *s, double delays[], int len) -{ - int i; - bool lose; - int was_high_loss; - double impulse; - double slice_delay; - - /* Compute delay and loss value for each time slice. */ - for (i = 0; i < len; i++) - { - lose = false; - /* Initialize delay to the serial delay plus some jitter. */ - slice_delay = s->serial_delay + s->max_jitter*q1050_rand(); - /* If no QoS, do congestion delay and packet loss analysis. */ - if (!s->qos_enabled) - { - /* To match the logic in G.1050 we need to record the current loss state, before - checking if we should change. */ - was_high_loss = s->high_loss; - /* Toggle between the low-loss and high-loss states, based on the transition probability. */ - if (q1050_rand() < s->prob_loss_rate_change[was_high_loss]) - s->high_loss = !s->high_loss; - impulse = 0.0; - if (q1050_rand() < s->prob_impulse[was_high_loss]) - { - impulse = s->impulse_height; - if (!was_high_loss || s->link_type == G1050_LAN_LINK) - impulse *= q1050_rand(); - } - - if (was_high_loss && q1050_rand() < s->prob_packet_loss) - lose = true; - /* Single pole LPF for the congestion delay impulses. */ - s->congestion_delay = s->congestion_delay*s->impulse_coeff + impulse*(1.0 - s->impulse_coeff); - slice_delay += s->congestion_delay; - } - /* If duplex mismatch on LAN, packet loss based on loss probability. */ - if (s->multiple_access && (q1050_rand() < s->prob_packet_collision_loss)) - lose = true; - /* Put computed delay into time slice array. */ - if (lose) - { - delays[i] = PACKET_LOSS_TIME; - s->lost_packets++; - } - else - { - delays[i] = slice_delay; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static void g1050_core_model(g1050_core_state_t *s, double delays[], int len) -{ - int32_t i; - bool lose; - double jitter_delay; - - for (i = 0; i < len; i++) - { - lose = false; - jitter_delay = s->base_delay + s->max_jitter*q1050_rand(); - /* Route flapping */ - if (--s->route_flap_counter <= 0) - { - /* Route changed */ - s->delay_delta = s->route_flap_delta - s->delay_delta; - s->route_flap_counter = s->route_flap_interval; - } - if (q1050_rand() < s->prob_packet_loss) - lose = true; - /* Link failures */ - if (--s->link_failure_counter <= 0) - { - /* We are in a link failure */ - lose = true; - if (--s->link_recovery_counter <= 0) - { - /* Leave failure state. */ - s->link_failure_counter = s->link_failure_interval_ticks; - s->link_recovery_counter = s->link_failure_duration_ticks; - lose = false; - } - } - if (lose) - { - delays[i] = PACKET_LOSS_TIME; - s->lost_packets++; - } - else - { - delays[i] = jitter_delay + s->delay_delta; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static int g1050_segment_delay(g1050_segment_state_t *s, - double base_time, - double arrival_times[], - double delays[], - int num_packets) -{ - int i; - int32_t departure_time; - int lost_packets; - - /* Add appropriate delays to the packets for the segments before the core. */ - lost_packets = 0; - for (i = 0; i < num_packets; i++) - { - /* Apply half a millisecond of rounding, as we working in millisecond steps. */ - departure_time = (arrival_times[i] + 0.0005 - base_time)*G1050_TICKS_PER_SEC; - if (arrival_times[i] == PACKET_LOSS_TIME) - { - /* Lost already */ - } - else if (delays[departure_time] == PACKET_LOSS_TIME) - { - arrival_times[i] = PACKET_LOSS_TIME; - lost_packets++; - } - else - { - arrival_times[i] += delays[departure_time]; - if (arrival_times[i] < s->last_arrival_time) - arrival_times[i] = s->last_arrival_time; - else - s->last_arrival_time = arrival_times[i]; - } - } - return lost_packets; -} -/*- End of function --------------------------------------------------------*/ - -static int g1050_segment_delay_preserve_order(g1050_segment_state_t *s, - double base_time, - double arrival_times_a[], - double arrival_times_b[], - double delays[], - int num_packets) -{ - int i; - int j; - int departure_time; - double last_arrival_time; - double last_arrival_time_temp; - int lost_packets; - - /* Add appropriate delays to the packets for the segments after the core. */ - last_arrival_time = 0.0; - last_arrival_time_temp = 0.0; - lost_packets = 0; - for (i = 0; i < num_packets; i++) - { - /* We need to preserve the order that came out of the core, so we - use an alternate array for the results. */ - /* Apply half a millisecond of rounding, as we working in millisecond steps. */ - departure_time = (arrival_times_a[i] + 0.0005 - base_time)*G1050_TICKS_PER_SEC; - if (arrival_times_a[i] == PACKET_LOSS_TIME) - { - /* Lost already */ - arrival_times_b[i] = PACKET_LOSS_TIME; - } - else if (delays[departure_time] == PACKET_LOSS_TIME) - { - arrival_times_b[i] = PACKET_LOSS_TIME; - lost_packets++; - } - else - { - arrival_times_b[i] = arrival_times_a[i] + delays[departure_time]; - if (arrival_times_a[i] < last_arrival_time) - { - /* If a legitimate out of sequence packet is detected, search - back a fixed amount of time to preserve order. */ - for (j = i - 1; j >= 0; j--) - { - if ((arrival_times_a[j] != PACKET_LOSS_TIME) - && - (arrival_times_b[j] != PACKET_LOSS_TIME)) - { - if ((arrival_times_a[i] - arrival_times_a[j]) > SEARCHBACK_PERIOD) - break; - if ((arrival_times_a[j] > arrival_times_a[i]) - && - (arrival_times_b[j] < arrival_times_b[i])) - { - arrival_times_b[j] = arrival_times_b[i]; - } - } - } - } - else - { - last_arrival_time = arrival_times_a[i]; - if (arrival_times_b[i] < last_arrival_time_temp) - arrival_times_b[i] = last_arrival_time_temp; - else - last_arrival_time_temp = arrival_times_b[i]; - } - } - } - return lost_packets; -} -/*- End of function --------------------------------------------------------*/ - -static int g1050_core_delay(g1050_core_state_t *s, - double base_time, - double arrival_times[], - double delays[], - int num_packets) -{ - int i; - int departure_time; - int lost_packets; - - /* This element does NOT preserve packet order. */ - lost_packets = 0; - for (i = 0; i < num_packets; i++) - { - /* Apply half a millisecond of rounding, as we working in millisecond steps. */ - departure_time = (arrival_times[i] + 0.0005 - base_time)*G1050_TICKS_PER_SEC; - if (arrival_times[i] == PACKET_LOSS_TIME) - { - /* Lost already */ - } - else if (delays[departure_time] == PACKET_LOSS_TIME) - { - arrival_times[i] = PACKET_LOSS_TIME; - lost_packets++; - } - else - { - /* Not lost. Compute arrival time. */ - arrival_times[i] += delays[departure_time]; - if (arrival_times[i] < s->last_arrival_time) - { - /* This packet is EARLIER than the last one. It is out of order! */ - /* Do we allow it to stay out of order? */ - if (q1050_rand() >= s->prob_oos) - arrival_times[i] = s->last_arrival_time; - } - else - { - /* Packet is in the correct order, relative to the last one. */ - s->last_arrival_time = arrival_times[i]; - } - } - } - return lost_packets; -} -/*- End of function --------------------------------------------------------*/ - -static void g1050_simulate_chunk(g1050_state_t *s) -{ - int i; - - s->base_time += 1.0; - - memmove(&s->segment[0].delays[0], &s->segment[0].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[0].delays[0])); - g1050_segment_model(&s->segment[0], &s->segment[0].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - - memmove(&s->segment[1].delays[0], &s->segment[1].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[1].delays[0])); - g1050_segment_model(&s->segment[1], &s->segment[1].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - - memmove(&s->core.delays[0], &s->core.delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->core.delays[0])); - g1050_core_model(&s->core, &s->core.delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - - memmove(&s->segment[2].delays[0], &s->segment[2].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[2].delays[0])); - g1050_segment_model(&s->segment[2], &s->segment[2].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - - memmove(&s->segment[3].delays[0], &s->segment[3].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[3].delays[0])); - g1050_segment_model(&s->segment[3], &s->segment[3].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - - memmove(&s->arrival_times_1[0], &s->arrival_times_1[s->packet_rate], 2*s->packet_rate*sizeof(s->arrival_times_1[0])); - memmove(&s->arrival_times_2[0], &s->arrival_times_2[s->packet_rate], 2*s->packet_rate*sizeof(s->arrival_times_2[0])); - for (i = 0; i < s->packet_rate; i++) - { - s->arrival_times_1[2*s->packet_rate + i] = s->base_time + 2.0 + (double) i/(double) s->packet_rate; - s->arrival_times_2[2*s->packet_rate + i] = 0.0; - } - - s->segment[0].lost_packets_2 += g1050_segment_delay(&s->segment[0], s->base_time, s->arrival_times_1, s->segment[0].delays, s->packet_rate); - s->segment[1].lost_packets_2 += g1050_segment_delay(&s->segment[1], s->base_time, s->arrival_times_1, s->segment[1].delays, s->packet_rate); - s->core.lost_packets_2 += g1050_core_delay(&s->core, s->base_time, s->arrival_times_1, s->core.delays, s->packet_rate); - s->segment[2].lost_packets_2 += g1050_segment_delay_preserve_order(&s->segment[2], s->base_time, s->arrival_times_1, s->arrival_times_2, s->segment[2].delays, s->packet_rate); - s->segment[3].lost_packets_2 += g1050_segment_delay_preserve_order(&s->segment[3], s->base_time, s->arrival_times_2, s->arrival_times_1, s->segment[3].delays, s->packet_rate); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(g1050_state_t *) g1050_init(int model, - int speed_pattern, - int packet_size, - int packet_rate) -{ - g1050_state_t *s; - g1050_constants_t *constants; - g1050_channel_speeds_t *sp; - g1050_model_t *mo; - int i; - - /* If the random generator has not been seeded it might give endless - zeroes - it depends on the platform. */ - for (i = 0; i < 10; i++) - { - if (q1050_rand() != 0.0) - break; - } - if (i >= 10) - q1050_rand_init(); - if ((s = (g1050_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - memset(s, 0, sizeof(*s)); - - constants = &g1050_constants[0]; - sp = &g1050_speed_patterns[speed_pattern - 1]; - mo = &g1050_standard_models[model]; - - memset(s, 0, sizeof(*s)); - - s->packet_rate = packet_rate; - s->packet_size = packet_size; - - g1050_segment_init(&s->segment[0], - G1050_LAN_LINK, - &constants->segment[0], - &mo->sidea_lan, - sp->sidea_lan_bit_rate, - sp->sidea_lan_multiple_access, - false, - packet_size, - packet_rate); - g1050_segment_init(&s->segment[1], - G1050_ACCESS_LINK, - &constants->segment[1], - &mo->sidea_access_link, - sp->sidea_access_link_bit_rate_ab, - false, - sp->sidea_access_link_qos_enabled, - packet_size, - packet_rate); - g1050_core_init(&s->core, &mo->core, packet_rate); - g1050_segment_init(&s->segment[2], - G1050_ACCESS_LINK, - &constants->segment[2], - &mo->sideb_access_link, - sp->sideb_access_link_bit_rate_ba, - false, - sp->sideb_access_link_qos_enabled, - packet_size, - packet_rate); - g1050_segment_init(&s->segment[3], - G1050_LAN_LINK, - &constants->segment[3], - &mo->sideb_lan, - sp->sideb_lan_bit_rate, - sp->sideb_lan_multiple_access, - false, - packet_size, - packet_rate); - - s->base_time = 0.0; - /* Start with enough of the future modelled to allow for the worst jitter. - After this we will always keep at least 2 seconds of the future modelled. */ - g1050_segment_model(&s->segment[0], s->segment[0].delays, 3*G1050_TICKS_PER_SEC); - g1050_segment_model(&s->segment[1], s->segment[1].delays, 3*G1050_TICKS_PER_SEC); - g1050_core_model(&s->core, s->core.delays, 3*G1050_TICKS_PER_SEC); - g1050_segment_model(&s->segment[2], s->segment[2].delays, 3*G1050_TICKS_PER_SEC); - g1050_segment_model(&s->segment[3], s->segment[3].delays, 3*G1050_TICKS_PER_SEC); - - /* Initialise the arrival times to the departure times */ - for (i = 0; i < 3*s->packet_rate; i++) - { - s->arrival_times_1[i] = s->base_time + (double) i/(double)s->packet_rate; - s->arrival_times_2[i] = 0.0; - } - - s->segment[0].lost_packets_2 += g1050_segment_delay(&s->segment[0], s->base_time, s->arrival_times_1, s->segment[0].delays, s->packet_rate); - s->segment[1].lost_packets_2 += g1050_segment_delay(&s->segment[1], s->base_time, s->arrival_times_1, s->segment[1].delays, s->packet_rate); - s->core.lost_packets_2 += g1050_core_delay(&s->core, s->base_time, s->arrival_times_1, s->core.delays, s->packet_rate); - s->segment[2].lost_packets_2 += g1050_segment_delay_preserve_order(&s->segment[2], s->base_time, s->arrival_times_1, s->arrival_times_2, s->segment[2].delays, s->packet_rate); - s->segment[3].lost_packets_2 += g1050_segment_delay_preserve_order(&s->segment[3], s->base_time, s->arrival_times_2, s->arrival_times_1, s->segment[3].delays, s->packet_rate); - - s->first = NULL; - s->last = NULL; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g1050_free(g1050_state_t *s) -{ - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) g1050_dump_parms(int model, int speed_pattern) -{ - g1050_channel_speeds_t *sp; - g1050_model_t *mo; - - sp = &g1050_speed_patterns[speed_pattern - 1]; - mo = &g1050_standard_models[model]; - - printf("Model %d%c\n", speed_pattern, 'A' + model - 1); - printf("LOO %.6f%% %.6f%% %.6f%%\n", mo->loo[0]*sp->loo/100.0, mo->loo[1]*sp->loo/100.0, mo->loo[2]*sp->loo/100.0); - printf("Side A LAN %dbps, %.3f%% occupancy, MTU %d, %s MA\n", sp->sidea_lan_bit_rate, mo->sidea_lan.percentage_occupancy, mo->sidea_lan.mtu, (sp->sidea_lan_multiple_access) ? "" : "no"); - printf("Side A access %dbps, %.3f%% occupancy, MTU %d, %s QoS\n", sp->sidea_access_link_bit_rate_ab, mo->sidea_access_link.percentage_occupancy, mo->sidea_access_link.mtu, (sp->sidea_access_link_qos_enabled) ? "" : "no"); - printf("Core delay %.4fs (%.4fs), peak jitter %.4fs, prob loss %.4f%%, prob OOS %.4f%%\n", mo->core.base_regional_delay, mo->core.base_intercontinental_delay, mo->core.max_jitter, mo->core.prob_packet_loss, mo->core.prob_oos); - printf(" Route flap interval %.4fs, delay change %.4fs\n", mo->core.route_flap_interval, mo->core.route_flap_delay); - printf(" Link failure interval %.4fs, duration %.4fs\n", mo->core.link_failure_interval, mo->core.link_failure_duration); - printf("Side B access %dbps, %.3f%% occupancy, MTU %d, %s QoS\n", sp->sideb_access_link_bit_rate_ba, mo->sideb_access_link.percentage_occupancy, mo->sideb_access_link.mtu, (sp->sideb_access_link_qos_enabled) ? "" : "no"); - printf("Side B LAN %dbps, %.3f%% occupancy, MTU %d, %s MA\n", sp->sideb_lan_bit_rate, mo->sideb_lan.percentage_occupancy, mo->sideb_lan.mtu, (sp->sideb_lan_multiple_access) ? "" : "no"); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g1050_put(g1050_state_t *s, const uint8_t buf[], int len, int seq_no, double departure_time) -{ - g1050_queue_element_t *element; - g1050_queue_element_t *e; - double arrival_time; - - while (departure_time >= s->base_time + 1.0) - g1050_simulate_chunk(s); - arrival_time = s->arrival_times_1[(int) ((departure_time - s->base_time)*(double) s->packet_rate + 0.5)]; - if (arrival_time < 0) - { - /* This packet is lost */ - return 0; - } - if ((element = (g1050_queue_element_t *) malloc(sizeof(*element) + len)) == NULL) - return -1; - element->next = NULL; - element->prev = NULL; - element->seq_no = seq_no; - element->departure_time = departure_time; - element->arrival_time = arrival_time; - element->len = len; - memcpy(element->pkt, buf, len); - /* Add it to the queue, in order */ - if (s->last == NULL) - { - /* The queue is empty */ - s->first = - s->last = element; - } - else - { - for (e = s->last; e; e = e->prev) - { - if (e->arrival_time <= arrival_time) - break; - } - if (e) - { - element->next = e->next; - element->prev = e; - e->next = element; - } - else - { - element->next = s->first; - s->first = element; - } - if (element->next) - element->next->prev = element; - else - s->last = element; - } - //printf(">> Seq %d, departs %f, arrives %f\n", seq_no, departure_time, arrival_time); - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g1050_get(g1050_state_t *s, uint8_t buf[], int max_len, double current_time, int *seq_no, double *departure_time, double *arrival_time) -{ - int len; - g1050_queue_element_t *element; - - element = s->first; - if (element == NULL) - { - if (seq_no) - *seq_no = -1; - if (departure_time) - *departure_time = -1; - if (arrival_time) - *arrival_time = -1; - return -1; - } - if (element->arrival_time > current_time) - { - if (seq_no) - *seq_no = element->seq_no; - if (departure_time) - *departure_time = element->departure_time; - if (arrival_time) - *arrival_time = element->arrival_time; - return -1; - } - /* Return the first packet in the queue */ - len = element->len; - memcpy(buf, element->pkt, len); - if (seq_no) - *seq_no = element->seq_no; - if (departure_time) - *departure_time = element->departure_time; - if (arrival_time) - *arrival_time = element->arrival_time; - //printf("<< Seq %d, arrives %f (%f)\n", element->seq_no, element->arrival_time, current_time); - - /* Remove it from the queue */ - if (s->first == s->last) - s->last = NULL; - s->first = element->next; - if (element->next) - element->next->prev = NULL; - free(element); - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) g1050_queue_dump(g1050_state_t *s) -{ - g1050_queue_element_t *e; - - printf("Queue scanned forewards\n"); - for (e = s->first; e; e = e->next) - printf("Seq %5d, arrival %10.4f, len %3d\n", e->seq_no, e->arrival_time, e->len); - printf("Queue scanned backwards\n"); - for (e = s->last; e; e = e->prev) - printf("Seq %5d, arrival %10.4f, len %3d\n", e->seq_no, e->arrival_time, e->len); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/libspandsp_sim.2005.vcproj b/libs/spandsp/spandsp-sim/libspandsp_sim.2005.vcproj deleted file mode 100644 index 2cceaf6683..0000000000 --- a/libs/spandsp/spandsp-sim/libspandsp_sim.2005.vcproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp-sim/libspandsp_sim.2008.vcproj b/libs/spandsp/spandsp-sim/libspandsp_sim.2008.vcproj deleted file mode 100644 index e91813e276..0000000000 --- a/libs/spandsp/spandsp-sim/libspandsp_sim.2008.vcproj +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp-sim/libspandsp_sim.dsp b/libs/spandsp/spandsp-sim/libspandsp_sim.dsp deleted file mode 100644 index dd4e1384d2..0000000000 --- a/libs/spandsp/spandsp-sim/libspandsp_sim.dsp +++ /dev/null @@ -1,143 +0,0 @@ -# Microsoft Developer Studio Project File - Name="spandsp" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=spandsp - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "spandsp.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "spandsp.mak" CFG="spandsp - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "spandsp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "spandsp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "spandsp - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /D "_WINDLL" /FR /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /map /debug /machine:I386 /out:"Release/libspandsp.dll" - -!ELSEIF "$(CFG)" == "spandsp - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /FR /FD /GZ /c -# SUBTRACT CPP /WX /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"Debug/libspandsp.dll" /pdbtype:sept -# SUBTRACT LINK32 /nodefaultlib - -!ENDIF - -# Begin Target - -# Name "spandsp - Win32 Release" -# Name "spandsp - Win32 Debug" -# Begin Group "Source Files" -# Begin Source File - -SOURCE=.\g1050.c -# End Source File -# Begin Source File - -SOURCE=.\line_model.c -# End Source File -# Begin Source File - -SOURCE=.\rfc2198_sim.c -# End Source File -# Begin Source File - -SOURCE=.\test_utils.c -# End Source File -# End Group -# Begin Group "Header Files" -# Begin Source File - -SOURCE=.\spandsp/g1050.h -# End Source File -# Begin Source File - -SOURCE=.\spandsp/line_model.h -# End Source File -# Begin Source File - -SOURCE=.\spandsp/line_models.h -# End Source File -# Begin Source File - -SOURCE=.\spandsp/rfc2198_sim.h -# End Source File -# Begin Source File - -SOURCE=.\spandsp/test_utils.h -# End Source File -# Begin Source File - -SOURCE=.\spandsp-sim.h -# End Source File -# End Group - -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/libs/spandsp/spandsp-sim/line_model.c b/libs/spandsp/spandsp-sim/line_model.c deleted file mode 100644 index 9da1f15495..0000000000 --- a/libs/spandsp/spandsp-sim/line_model.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * line_model.c - Model a telephone line. - * - * 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 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#define GEN_CONST -#include -#endif -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif -#include "floating_fudge.h" - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -#include "spandsp.h" -#include "spandsp-sim.h" -#include "spandsp/g168models.h" - -#if !defined(NULL) -#define NULL (void *) 0 -#endif - -static const float null_line_model[] = -{ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 -}; - -SPAN_DECLARE_DATA const float *line_models[] = -{ - null_line_model, /* 0 */ - proakis_line_model, - ad_1_edd_1_model, - ad_1_edd_2_model, - ad_1_edd_3_model, - ad_5_edd_1_model, /* 5 */ - ad_5_edd_2_model, - ad_5_edd_3_model, - ad_6_edd_1_model, - ad_6_edd_2_model, - ad_6_edd_3_model, /* 10 */ - ad_7_edd_1_model, - ad_7_edd_2_model, - ad_7_edd_3_model, - ad_8_edd_1_model, - ad_8_edd_2_model, /* 15 */ - ad_8_edd_3_model, - ad_9_edd_1_model, - ad_9_edd_2_model, - ad_9_edd_3_model -}; - -static float calc_near_line_filter(one_way_line_model_state_t *s, float v) -{ - float sum; - int j; - int p; - - /* Add the sample in the filter buffer */ - p = s->near_buf_ptr; - s->near_buf[p] = v; - if (++p == s->near_filter_len) - p = 0; - s->near_buf_ptr = p; - - /* Apply the filter */ - sum = 0.0f; - for (j = 0; j < s->near_filter_len; j++) - { - sum += s->near_filter[j]*s->near_buf[p]; - if (++p >= s->near_filter_len) - p = 0; - } - - /* Add noise */ - sum += awgn(&s->near_noise); - - return sum; -} -/*- End of function --------------------------------------------------------*/ - -static float calc_far_line_filter(one_way_line_model_state_t *s, float v) -{ - float sum; - int j; - int p; - - /* Add the sample in the filter buffer */ - p = s->far_buf_ptr; - s->far_buf[p] = v; - if (++p == s->far_filter_len) - p = 0; - s->far_buf_ptr = p; - - /* Apply the filter */ - sum = 0.0f; - for (j = 0; j < s->far_filter_len; j++) - { - sum += s->far_filter[j]*s->far_buf[p]; - if (++p >= s->far_filter_len) - p = 0; - } - - /* Add noise */ - sum += awgn(&s->far_noise); - - return sum; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) one_way_line_model(one_way_line_model_state_t *s, - int16_t output[], - const int16_t input[], - int samples) -{ - int i; - float in; - float out; - float out1; - int16_t amp[1]; - - /* The path being modelled is: - terminal - | < hybrid - | - | < noise and filtering - | - | < hybrid - CO - | - | < A-law distortion + bulk delay - | - CO - | < hybrid - | - | < noise and filtering - | - | < hybrid - terminal - */ - for (i = 0; i < samples; i++) - { - in = input[i]; - - /* Near end analogue section */ - - /* Line model filters & noise */ - out = calc_near_line_filter(s, in); - - /* Long distance digital section */ - - amp[0] = out; - codec_munge(s->munge, amp, 1); - out = amp[0]; - /* Introduce the bulk delay of the long distance link. */ - out1 = s->bulk_delay_buf[s->bulk_delay_ptr]; - s->bulk_delay_buf[s->bulk_delay_ptr] = out; - out = out1; - if (++s->bulk_delay_ptr >= s->bulk_delay) - s->bulk_delay_ptr = 0; - - /* Far end analogue section */ - - /* Line model filters & noise */ - out = calc_far_line_filter(s, out); - - if (s->mains_interference) - { - tone_gen(&s->mains_tone, amp, 1); - out += amp[0]; - } - output[i] = out + s->dc_offset; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc) -{ - s->dc_offset = dc; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level) -{ - tone_gen_descriptor_t mains_tone_desc; - - if (f) - { - tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, true); - tone_gen_init(&s->mains_tone, &mains_tone_desc); - } - s->mains_interference = f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) both_ways_line_model(both_ways_line_model_state_t *s, - int16_t output1[], - const int16_t input1[], - int16_t output2[], - const int16_t input2[], - int samples) -{ - int i; - float in1; - float in2; - float out1; - float out2; - float tmp1; - float tmp2; - int16_t amp[1]; - - /* The path being modelled is: - terminal - | < hybrid echo - | - | < noise and filtering - | - | < hybrid echo - CO - | - | < A-law distortion + bulk delay - | - CO - | < hybrid echo - | - | < noise and filtering - | - | < hybrid echo - terminal - */ - for (i = 0; i < samples; i++) - { - in1 = input1[i]; - in2 = input2[i]; - - /* Near end analogue sections */ - /* Echo from each terminal's CO hybrid */ - tmp1 = in1 + s->fout2*s->line1.near_co_hybrid_echo; - tmp2 = in2 + s->fout1*s->line2.near_co_hybrid_echo; - - /* Line model filters & noise */ - s->fout1 = calc_near_line_filter(&s->line1, tmp1); - s->fout2 = calc_near_line_filter(&s->line2, tmp2); - - /* Long distance digital section */ - - /* Introduce distortion due to A-law or u-law munging. */ - amp[0] = s->fout1; - codec_munge(s->line1.munge, amp, 1); - s->fout1 = amp[0]; - - amp[0] = s->fout2; - codec_munge(s->line2.munge, amp, 1); - s->fout2 = amp[0]; - - /* Introduce the bulk delay of the long distance digital link. */ - out1 = s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr]; - s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr] = s->fout1; - s->fout1 = out1; - if (++s->line1.bulk_delay_ptr >= s->line1.bulk_delay) - s->line1.bulk_delay_ptr = 0; - - out2 = s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr]; - s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr] = s->fout2; - s->fout2 = out2; - if (++s->line2.bulk_delay_ptr >= s->line2.bulk_delay) - s->line2.bulk_delay_ptr = 0; - - /* Far end analogue sections */ - - /* Echo from each terminal's own hybrid */ - out1 += in2*s->line1.far_cpe_hybrid_echo; - out2 += in1*s->line2.far_cpe_hybrid_echo; - - /* Line model filters & noise */ - out1 = calc_far_line_filter(&s->line1, out1); - out2 = calc_far_line_filter(&s->line2, out2); - - output1[i] = fsaturate(out1 + s->line1.dc_offset); - output2[i] = fsaturate(out2 + s->line2.dc_offset); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2) -{ - s->line1.dc_offset = dc1; - s->line2.dc_offset = dc2; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2) -{ - tone_gen_descriptor_t mains_tone_desc; - - if (f) - { - tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, true); - tone_gen_init(&s->line1.mains_tone, &mains_tone_desc); - tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, true); - tone_gen_init(&s->line2.mains_tone, &mains_tone_desc); - } - s->line1.mains_interference = f; - s->line2.mains_interference = f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, float noise, int codec, int rbs_pattern) -{ - one_way_line_model_state_t *s; - - if ((s = (one_way_line_model_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - memset(s, 0, sizeof(*s)); - - s->bulk_delay = 8; - s->bulk_delay_ptr = 0; - - s->munge = codec_munge_init(codec, rbs_pattern); - - s->near_filter = line_models[model]; - s->near_filter_len = 129; - - s->far_filter = line_models[model]; - s->far_filter_len = 129; - - /* Put half the noise in each analogue section */ - awgn_init_dbm0(&s->near_noise, 1234567, noise - 3.02f); - awgn_init_dbm0(&s->far_noise, 1234567, noise - 3.02f); - - s->dc_offset = 0.0f; - s->mains_interference = 0; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) one_way_line_model_free(one_way_line_model_state_t *s) -{ - codec_munge_free(s->munge); - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model1, - float noise1, - float echo_level_cpe1, - float echo_level_co1, - int model2, - float noise2, - float echo_level_cpe2, - float echo_level_co2, - int codec, - int rbs_pattern) -{ - both_ways_line_model_state_t *s; - - if ((s = (both_ways_line_model_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - memset(s, 0, sizeof(*s)); - - s->line1.munge = codec_munge_init(codec, rbs_pattern); - s->line2.munge = codec_munge_init(codec, rbs_pattern); - - s->line1.bulk_delay = 8; - s->line2.bulk_delay = 8; - - s->line1.bulk_delay_ptr = 0; - s->line2.bulk_delay_ptr = 0; - - s->line1.near_filter = line_models[model1]; - s->line1.near_filter_len = 129; - s->line2.near_filter = line_models[model2]; - s->line2.near_filter_len = 129; - - s->line1.far_filter = line_models[model1]; - s->line1.far_filter_len = 129; - s->line2.far_filter = line_models[model2]; - s->line2.far_filter_len = 129; - - /* Put half the noise in each analogue section */ - awgn_init_dbm0(&s->line1.near_noise, 1234567, noise1 - 3.02f); - awgn_init_dbm0(&s->line2.near_noise, 7654321, noise2 - 3.02f); - - awgn_init_dbm0(&s->line1.far_noise, 1234567, noise1 - 3.02f); - awgn_init_dbm0(&s->line2.far_noise, 7654321, noise2 - 3.02f); - - s->line1.dc_offset = 0.0f; - s->line2.dc_offset = 0.0f; - s->line1.mains_interference = 0; - s->line2.mains_interference = 0; - - /* Echos */ - s->line1.near_co_hybrid_echo = pow(10, echo_level_co1/20.0f); - s->line2.near_co_hybrid_echo = pow(10, echo_level_co2/20.0f); - s->line1.near_cpe_hybrid_echo = pow(10, echo_level_cpe1/20.0f); - s->line2.near_cpe_hybrid_echo = pow(10, echo_level_cpe2/20.0f); - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) both_ways_line_model_free(both_ways_line_model_state_t *s) -{ - codec_munge_free(s->line1.munge); - codec_munge_free(s->line2.munge); - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/make_line_models.c b/libs/spandsp/spandsp-sim/make_line_models.c deleted file mode 100644 index cac9d75cc1..0000000000 --- a/libs/spandsp/spandsp-sim/make_line_models.c +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * make_line_models.c - * - * 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 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. - */ - -/*! \page make_line_models_page Telephony line model construction -\section make_line_models_page_sec_1 What does it do? -???. - -\section make_line_models_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#if defined(HAVE_FFTW3_H) -#include -#else -#include -#endif -#include -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif - -#include "spandsp.h" - -#if !defined(M_PI) -# define M_PI 3.14159265358979323846 /* pi */ -#endif - -#define LINE_MODEL_FILE_NAME "line_models.c" - -#define SAMPLE_RATE 8000 - -#define LINE_FILTER_SIZE 129 -#define FFT_SIZE 1024 - -/* Tabulated medium range telephone line response - (from p 537, Digital Communication, John G. Proakis */ -/* - amp 1.0 -> 2.15, freq = 3000 Hz -> 3.2, by 0.2 increments - delay = 4 ms -> 2.2 - */ - -struct -{ - int frequency; - float amp; - float delay; -} proakis[] = -{ - { 0, 0.00, 4.80}, - { 200, 0.90, 3.50}, - { 400, 1.40, 2.20}, - { 600, 1.80, 0.90}, - { 800, 2.00, 0.50}, - {1000, 2.10, 0.25}, - {1200, 2.30, 0.10}, - {1400, 2.30, 0.05}, - {1600, 2.20, 0.00}, - {1800, 2.10, 0.00}, - {2000, 2.00, 0.00}, - {2200, 1.85, 0.05}, - {2400, 1.75, 0.10}, - {2600, 1.55, 0.20}, - {2800, 1.30, 0.40}, - {3000, 1.10, 0.50}, - {3200, 0.80, 0.90}, - {3400, 0.55, 1.20}, - {3600, 0.25, 2.20}, - {3800, 0.05, 3.20}, - {4000, 0.05, 4.20}, - {4200, 0.05, 5.20} -}; - -#define CPE_TO_CO_ATTENUATION 0 /* In dB */ -#define CPE_TO_CO_DELAY 1 /* In us */ -#define CPE_TO_CO_IMPEDANCE 2 /* In ohms */ -#define CPE_TO_CO_PHASE 3 /* In degrees */ -#define CO_TO_CPE_IMPEDANCE 4 /* In ohms */ -#define CO_TO_CPE_PHASE 5 /* In degrees */ -#define CO_TO_CPE_ATTENUATION 6 /* In dB */ -#define CO_TO_CPE_DELAY 7 /* In us */ - -/* Terms used, for V.56bis: - AD = attenuation distortion - EDD = envelope delay distortion */ - -/* V.56bis EIA LL-1, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll1[] = -{ - { 200, {0.0, 0.4, 767, -1.4, 767, -1.4, 0.0, 0.4}}, - { 300, {0.0, 0.7, 766, -2.0, 766, -2.0, 0.0, 0.7}}, - { 400, {0.0, 0.5, 763, -2.8, 763, -2.8, 0.0, 0.5}}, - { 500, {0.0, 0.6, 765, -3.4, 765, -3.4, 0.0, 0.6}}, - { 600, {0.0, 0.2, 764, -4.1, 764, -4.1, 0.0, 0.2}}, - { 700, {0.0, 0.4, 764, -4.7, 764, -4.7, 0.0, 0.4}}, - { 800, {0.0, 0.4, 762, -5.4, 762, -5.4, 0.0, 0.4}}, - { 900, {0.0, 0.2, 762, -6.0, 762, -6.0, 0.0, 0.2}}, - {1000, {1.2, 0.5, 761, -6.7, 761, -6.7, 1.2, 0.5}}, - {1100, {0.0, 0.6, 759, -7.4, 759, -7.4, 0.0, 0.6}}, - {1200, {0.0, 0.4, 757, -8.1, 757, -8.1, 0.0, 0.4}}, - {1300, {0.0, 0.1, 757, -8.6, 757, -8.6, 0.0, 0.1}}, - {1400, {0.0, 0.3, 755, -9.3, 755, -9.3, 0.0, 0.3}}, - {1500, {0.0, 0.4, 753, -10.0, 753, -10.0, 0.0, 0.4}}, - {1600, {0.0, 0.3, 751, -10.7, 751, -10.7, 0.0, 0.3}}, - {1700, {0.0, 0.1, 748, -11.3, 748, -11.3, 0.0, 0.1}}, - {1800, {0.0, 11.0, 748, -11.9, 748, -11.9, 0.0, 11.0}}, - {1900, {0.1, 0.1, 745, -12.5, 745, -12.5, 0.1, 0.1}}, - {2000, {0.1, 0.3, 743, -13.9, 743, -13.9, 0.1, 0.3}}, - {2100, {0.1, 0.3, 740, -13.9, 740, -13.9, 0.1, 0.3}}, - {2200, {0.1, 0.3, 737, -14.5, 737, -14.5, 0.1, 0.3}}, - {2300, {0.1, 0.3, 734, -15.2, 734, -15.2, 0.1, 0.3}}, - {2400, {0.1, 0.2, 731, -15.8, 731, -15.8, 0.1, 0.2}}, - {2500, {0.1, 0.0, 728, -16.4, 728, -16.4, 0.1, 0.0}}, - {2600, {0.1, 0.0, 729, -16.8, 729, -16.8, 0.1, 0.0}}, - {2700, {0.2, 0.1, 726, -17.4, 726, -17.4, 0.2, 0.1}}, - {2800, {0.2, 0.2, 722, -18.0, 722, -18.0, 0.2, 0.2}}, - {2900, {0.2, 0.3, 719, -18.6, 719, -18.6, 0.2, 0.3}}, - {3000, {0.2, 0.4, 715, -19.3, 715, -19.3, 0.2, 0.4}}, - {3100, {0.2, 0.4, 712, -19.9, 712, -19.9, 0.2, 0.4}}, - {3200, {0.2, 0.5, 708, -20.5, 708, -20.5, 0.2, 0.5}}, - {3300, {0.2, 0.5, 704, -21.1, 704, -21.1, 0.2, 0.5}}, - {3400, {0.2, 0.5, 700, -21.7, 700, -21.7, 0.2, 0.5}}, - {3500, {0.2, 0.5, 696, -22.3, 696, -22.3, 0.2, 0.5}}, - {3600, {0.2, 0.4, 692, -22.9, 692, -22.9, 0.2, 0.4}}, - {3700, {0.2, 0.3, 688, -23.5, 688, -23.5, 0.2, 0.3}}, - {3800, {0.2, 0.2, 684, -24.1, 684, -24.1, 0.2, 0.2}}, - {3900, {0.2, 0.1, 680, -24.7, 680, -24.7, 0.2, 0.1}}, - {4000, {0.2, -0.1, 676, -25.2, 676, -25.2, 0.2, -0.1}} -}; - -/* V.56bis EIA LL-2, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll2[] = -{ - { 200, {-0.2, 6.6, 1086, -4.9, 1085, -5.6, -0.2, 6.6}}, - { 300, {-0.2, 7.7, 1079, -7.3, 1077, -8.3, -0.2, 7.7}}, - { 400, {-0.2, 6.7, 1062, -9.9, 1058, -11.2, -0.2, 6.7}}, - { 500, {-0.2, 7.1, 1059, -12.0, 1053, -13.6, -0.2, 7.1}}, - { 600, {-0.1, 5.2, 1041, -14.4, 1034, -16.3, -0.1, 5.2}}, - { 700, {-0.1, 5.8, 1030, -16.5, 1020, -18.6, -0.1, 5.8}}, - { 800, {-0.1, 5.4, 1010, -18.7, 998, -21.0, -0.1, 5.4}}, - { 900, { 0.0, 4.5, 997, -20.5, 982, -23.1, 0.0, 4.5}}, - {1000, { 3.2, 5.1, 976, -22.5, 959, -25.3, 3.2, 5.1}}, - {1100, { 0.1, 5.0, 954, -24.5, 934, -27.4, 0.1, 5.0}}, - {1200, { 0.1, 4.0, 931, -26.2, 909, -29.4, 0.1, 4.0}}, - {1300, { 0.2, 2.7, 918, -27.6, 894, -30.9, 0.2, 2.7}}, - {1400, { 0.2, 2.8, 897, -29.2, 871, -32.6, 0.2, 2.8}}, - {1500, { 0.3, 2.6, 874, -30.7, 847, -34.3, 0.3, 2.6}}, - {1600, { 0.3, 2.0, 852, -32.1, 823, -35.8, 0.3, 2.0}}, - {1700, { 0.4, 0.9, 831, -33.4, 800, -37.2, 0.4, 0.9}}, - {1800, { 0.5, 40.8, 816, -34.4, 783, -38.4, 0.5, 40.8}}, - {1900, { 0.6, 0.0, 796, -35.6, 762, -39.6, 0.6, 0.0}}, - {2000, { 0.6, -0.2, 776, -36.6, 741, -40.7, 0.6, -0.2}}, - {2100, { 0.7, -0.6, 756, -37.6, 720, -41.8, 0.7, -0.6}}, - {2200, { 0.8, -1.1, 737, -38.6, 700, -42.9, 0.8, -1.1}}, - {2300, { 0.9, -1.8, 719, -39.4, 681, -43.8, 0.9, -1.8}}, - {2400, { 1.0, -2.6, 701, -40.2, 663, -44.7, 1.0, -2.6}}, - {2500, { 1.0, -3.7, 684, -41.0, 646, -45.5, 1.0, -3.7}}, - {2600, { 1.1, -4.1, 678, -41.3, 639, -45.9, 1.1, -4.1}}, - {2700, { 1.2, -4.3, 663, -42.0, 623, -46.6, 1.2, -4.3}}, - {2800, { 1.3, -4.5, 647, -42.6, 607, -47.3, 1.3, -4.5}}, - {2900, { 1.4, -4.8, 632, -43.1, 591, -47.9, 1.4, -4.8}}, - {3000, { 1.5, -5.2, 617, -43.6, 576, -48.4, 1.5, -5.2}}, - {3100, { 1.6, -5.6, 603, -44.1, 562, -49.0, 1.6, -5.6}}, - {3200, { 1.7, -6.0, 589, -44.5, 548, -49.5, 1.7, -6.0}}, - {3300, { 1.8, -6.5, 576, -44.9, 535, -49.9, 1.8, -6.5}}, - {3400, { 1.9, -7.1, 563, -45.3, 522, -50.3, 1.9, -7.1}}, - {3500, { 2.0, -7.7, 551, -45.6, 509, -50.7, 2.0, -7.7}}, - {3600, { 2.1, -8.4, 539, -45.9, 498, -51.0, 2.1, -8.4}}, - {3700, { 2.2, -9.1, 528, -46.2, 486, -51.3, 2.2, -9.1}}, - {3800, { 2.3, -9.9, 518, -46.4, 476, -51.6, 2.3, -9.9}}, - {3900, { 2.4, -10.6, 507, -46.6, 466, -51.9, 2.4, -10.6}}, - {4000, { 2.5, -11.5, 498, -46.8, 456, -52.1, 2.5, -11.5}} -}; - -/* V.56bis EIA LL-3, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll3[] = -{ - { 200, {-0.3, 10.5, 1176, -5.9, 1173, -7.4, -0.3, 10.5}}, - { 300, {-0.3, 11.5, 1165, -8.8, 1159, -11.0, -0.3, 11.5}}, - { 400, {-0.3, 10.6, 1140, -11.8, 1130, -14.7, -0.3, 10.6}}, - { 500, {-0.3, 11.0, 1133, -14.3, 1117, -17.8, -0.3, 11.0}}, - { 600, {-0.2, 8.5, 1108, -17.1, 1086, -21.2, -0.2, 8.5}}, - { 700, {-0.2, 8.5, 1090, -19.4, 1062, -24.0, -0.2, 8.5}}, - { 800, {-0.1, 8.4, 1062, -21.9, 1029, -27.0, -0.1, 8.4}}, - { 900, { 0.0, 7.1, 1042, -23.9, 1003, -29.4, 0.0, 7.1}}, - {1000, { 3.8, 7.7, 1013, -23.0, 969, -31.9, 3.8, 7.7}}, - {1100, { 0.1, 7.4, 982, -28.1, 934, -34.3, 0.1, 7.4}}, - {1200, { 0.1, 6.0, 953, -29.9, 900, -36.5, 0.1, 6.0}}, - {1300, { 0.2, 4.2, 935, -31.3, 878, -38.1, 0.2, 4.2}}, - {1400, { 0.3, 4.2, 907, -32.8, 847, -40.0, 0.3, 4.2}}, - {1500, { 0.4, 3.7, 880, -34.3, 817, -41.7, 0.4, 3.7}}, - {1600, { 0.5, 2.7, 853, -35.6, 787, -43.2, 0.5, 2.7}}, - {1700, { 0.6, 1.2, 827, -36.8, 760, -44.6, 0.6, 1.2}}, - {1800, { 0.7, 48.7, 809, -37.8, 739, -45.8, 0.7, 48.7}}, - {1900, { 0.8, -0.2, 785, -38.8, 715, -47.0, 0.8, -0.2}}, - {2000, { 0.9, -0.7, 763, -39.7, 691, -48.0, 0.9, -0.7}}, - {2100, { 1.0, -1.3, 741, -40.5, 668, -49.1, 1.0, -1.3}}, - {2200, { 1.1, -2.1, 719, -41.3, 647, -50.0, 1.1, -2.1}}, - {2300, { 1.2, -2.1, 699, -42.0, 625, -50.8, 1.2, -2.1}}, - {2400, { 1.2, -4.3, 680, -42.6, 606, -51.6, 1.2, -4.3}}, - {2500, { 1.3, -5.6, 663, -43.2, 588, -52.3, 1.3, -5.6}}, - {2600, { 1.6, -6.2, 656, -43.4, 581, -52.7, 1.6, -6.2}}, - {2700, { 1.7, -6.6, 640, -43.9, 564, -53.3, 1.7, -6.6}}, - {2800, { 1.8, -7.0, 624, -44.3, 548, -53.9, 1.8, -7.0}}, - {2900, { 1.9, -7.5, 609, -44.7, 533, -54.4, 1.9, -7.5}}, - {3000, { 2.0, -8.0, 594, -45.0, 518, -54.8, 2.0, -8.0}}, - {3100, { 2.2, -8.6, 580, -45.3, 504, -55.3, 2.2, -8.6}}, - {3200, { 2.3, -9.2, 566, -45.6, 490, -55.7, 2.3, -9.2}}, - {3300, { 2.4, -9.9, 553, -45.8, 477, -56.0, 2.4, -9.9}}, - {3400, { 2.6, -10.7, 540, -46.0, 465, -56.3, 2.6, -10.7}}, - {3500, { 2.7, -11.4, 529, -46.2, 454, -56.6, 2.7, -11.4}}, - {3600, { 2.8, -12.3, 517, -46.3, 443, -56.9, 2.8, -12.3}}, - {3700, { 3.0, -13.1, 507, -46.4, 432, -57.1, 3.0, -13.1}}, - {3800, { 3.1, -14.0, 497, -46.5, 422, -57.3, 3.1, -14.0}}, - {3900, { 3.2, -14.9, 487, -46.6, 413, -57.5, 3.2, -14.9}}, - {4000, { 3.3, -15.9, 478, -46.6, 404, -57.7, 3.3, -15.9}} -}; - - -/* V.56bis EIA LL-4, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll4[] = -{ - { 200, {-0.8, 31.0, 1564, -10.7, 1564, -10.7, -0.8, 31.0}}, - { 300, {-0.8, 32.6, 1520, -15.6, 1520, -15.6, -0.8, 32.6}}, - { 400, {-0.8, 29.8, 1447, -20.5, 1447, -20.5, -0.8, 29.8}}, - { 500, {-0.6, 29.7, 1402, -24.3, 1402, -24.3, -0.6, 29.7}}, - { 600, {-0.5, 24.9, 1328, -28.1, 1328, -28.1, -0.5, 24.9}}, - { 700, {-0.4, 24.8, 1270, -31.2, 1270, -31.2, -0.4, 24.8}}, - { 800, {-0.3, 22.7, 1200, -34.0, 1200, -34.0, -0.3, 22.7}}, - { 900, {-0.1, 19.8, 1148, -36.2, 1148, -36.2, -0.1, 19.8}}, - {1000, { 6.1, 19.3, 1086, -38.3, 1086, -38.3, 6.1, 19.3}}, - {1100, { 0.1, 17.5, 1027, -40.1, 1027, -40.1, 0.1, 17.5}}, - {1200, { 0.3, 14.3, 974, -41.6, 974, -41.6, 0.3, 14.3}}, - {1300, { 0.5, 10.9, 941, -42.6, 941, -42.6, 0.5, 10.9}}, - {1400, { 0.7, 9.6, 897, -43.7, 897, -43.7, 0.7, 9.6}}, - {1500, { 0.9, 7.7, 856, -44.6, 856, -44.6, 0.9, 7.7}}, - {1600, { 1.1, 5.3, 818, -45.3, 818, -45.3, 1.1, 5.3}}, - {1700, { 1.3, 2.4, 784, -45.9, 784, -45.9, 1.3, 2.4}}, - {1800, { 1.4, 69.1, 761, -46.3, 761, -46.3, 1.4, 69.1}}, - {1900, { 1.7, -1.3, 732, -46.6, 732, -46.6, 1.7, -1.3}}, - {2000, { 1.9, -2.7, 706, -46.9, 706, -46.9, 1.9, -2.7}}, - {2100, { 2.1, -4.3, 682, -47.1, 682, -47.1, 2.1, -4.3}}, - {2200, { 2.3, -6.0, 659, -47.3, 659, -47.3, 2.3, -6.0}}, - {2300, { 2.5, -7.9, 638, -47.4, 638, -47.4, 2.5, -7.9}}, - {2400, { 2.7, -9.9, 619, -47.4, 619, -47.4, 2.7, -9.9}}, - {2500, { 2.9, -12.0, 602, -47.5, 602, -47.5, 2.9, -12.0}}, - {2600, { 3.1, -13.0, 596, -47.4, 596, -47.4, 3.1, -13.0}}, - {2700, { 3.3, -13.9, 580, -47.4, 580, -47.4, 3.3, -13.9}}, - {2800, { 3.5, -14.8, 566, -47.3, 566, -47.3, 3.5, -14.8}}, - {2900, { 3.7, -15.7, 552, -47.2, 552, -47.2, 3.7, -15.7}}, - {3000, { 3.9, -16.7, 539, -47.1, 539, -47.1, 3.9, -16.7}}, - {3100, { 4.1, -17.7, 526, -47.0, 526, -47.0, 4.1, -17.7}}, - {3200, { 4.3, -18.7, 515, -46.8, 515, -46.8, 4.3, -18.7}}, - {3300, { 4.5, -19.8, 504, -46.7, 504, -46.7, 4.5, -19.8}}, - {3400, { 4.7, -20.8, 493, -46.5, 493, -46.5, 4.7, -20.8}}, - {3500, { 4.9, -21.8, 484, -46.4, 484, -46.4, 4.9, -21.8}}, - {3600, { 5.1, -22.9, 475, -46.2, 475, -46.2, 5.1, -22.9}}, - {3700, { 5.3, -23.9, 466, -46.0, 466, -46.0, 5.3, -23.9}}, - {3800, { 5.5, -25.0, 458, -45.9, 458, -45.9, 5.5, -25.0}}, - {3900, { 5.6, -26.1, 451, -45.7, 451, -45.7, 5.6, -26.1}}, - {4000, { 5.8, -27.2, 444, -45.5, 444, -45.5, 5.8, -27.2}} -}; - - -/* V.56bis EIA LL-5, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll5[] = -{ - { 200, {-1.4, 55.8, 1607, -12.7, 1574, -17.4, -1.4, 55.8}}, - { 300, {-1.3, 57.2, 1541, -18.3, 1478, -24.8, -1.3, 57.2}}, - { 400, {-1.2, 52.2, 1443, -23.6, 1350, -31.5, -1.2, 52.2}}, - { 500, {-1.0, 51.0, 1379, -27.5, 1261, -36.4, -1.0, 51.0}}, - { 600, {-0.9, 43.2, 1287, -31.2, 1150, -40.7, -0.9, 43.2}}, - { 700, {-0.7, 41.8, 1216, -34.0, 1066, -44.0, -0.7, 41.8}}, - { 800, {-0.5, 37.4, 1137, -36.5, 979, -46.9, -0.5, 37.4}}, - { 900, {-0.2, 32.4, 1080, -38.3, 915, -48.9, -0.2, 32.4}}, - {1000, { 7.0, 30.5, 1015, -39.8, 848, -50.7, 7.0, 30.5}}, - {1100, { 0.3, 26.8, 956, -41.1, 788, -52.2, 0.3, 26.8}}, - {1200, { 0.5, 21.5, 904, -42.1, 736, -53.3, 0.5, 21.5}}, - {1300, { 0.8, 16.6, 873, -42.7, 703, -54.1, 0.8, 16.6}}, - {1400, { 1.0, 14.1, 832, -43.2, 663, -54.8, 1.0, 14.1}}, - {1500, { 1.3, 10.9, 795, -43.7, 627, -55.3, 1.3, 10.9}}, - {1600, { 1.6, 7.3, 762, -44.0, 595, -55.7, 1.6, 7.3}}, - {1700, { 1.9, 3.2, 733, -44.2, 567, -56.0, 1.9, 3.2}}, - {1800, { 2.2, 81.5, 713, -44.3, 547, -56.2, 2.2, 81.5}}, - {1900, { 2.4, -1.9, 689, -44.4, 524, -56.4, 2.4, -1.9}}, - {2000, { 2.7, -3.9, 667, -44.4, 503, -56.5, 2.7, -3.9}}, - {2100, { 3.0, -6.1, 646, -44.4, 485, -56.5, 3.0, -6.1}}, - {2200, { 3.3, -8.3, 628, -44.4, 466, -56.5, 3.3, -8.3}}, - {2300, { 3.6, -10.7, 610, -44.3, 450, -56.5, 3.6, -10.7}}, - {2400, { 3.8, -13.1, 595, -44.2, 436, -56.4, 3.8, -13.1}}, - {2500, { 4.1, -15.5, 581, -44.1, 422, -56.3, 4.1, -15.5}}, - {2600, { 4.3, -16.7, 577, -44.0, 417, -56.2, 4.3, -16.7}}, - {2700, { 4.6, -17.7, 565, -43.9, 406, -56.1, 4.6, -17.7}}, - {2800, { 4.8, -18.8, 553, -43.8, 395, -56.0, 4.8, -18.8}}, - {2900, { 5.1, -19.9, 542, -43.7, 395, -55.9, 5.1, -19.9}}, - {3000, { 5.4, -21.0, 531, -43.6, 375, -55.7, 5.4, -21.0}}, - {3100, { 5.6, -22.1, 521, -43.5, 366, -55.6, 5.6, -22.1}}, - {3200, { 5.9, -23.2, 511, -43.4, 357, -55.4, 5.9, -23.2}}, - {3300, { 6.1, -24.3, 502, -43.3, 349, -55.3, 6.1, -24.3}}, - {3400, { 6.4, -25.4, 494, -43.2, 341, -55.1, 6.4, -25.4}}, - {3500, { 6.6, -26.5, 486, -43.1, 334, -55.0, 6.6, -26.5}}, - {3600, { 6.9, -27.6, 478, -43.0, 327, -54.8, 6.9, -27.6}}, - {3700, { 7.1, -28.7, 471, -42.9, 321, -54.7, 7.1, -28.7}}, - {3800, { 7.3, -29.9, 464, -42.8, 315, -54.6, 7.3, -29.9}}, - {3900, { 7.5, -31.0, 458, -42.7, 310, -54.4, 7.5, -31.0}}, - {4000, { 7.8, -32.1, 452, -42.7, 304, -54.3, 7.8, -32.1}} -}; - - -/* V.56bis EIA LL-6, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll6[] = -{ - { 200, {-0.2, -39.3, 1756, -12.0, 1748, -19.8, -0.2, -39.3}}, - { 300, {-0.2, -31.7, 1642, -15.9, 1689, -26.9, -0.2, -31.7}}, - { 400, {-0.2, -37.5, 1506, -18.4, 1427, -33.4, -0.2, -37.5}}, - { 500, {-0.1, -34.7, 1442, -19.5, 1301, -37.7, -0.1, -34.7}}, - { 600, {-0.1, -46.0, 1363, -20.1, 1153, -40.7, -0.1, -46.0}}, - { 700, { 0.0, -40.8, 1320, -20.7, 1045, -42.2, 0.0, -40.8}}, - { 800, { 0.0, -40.1, 1269, -21.5, 943, -42.3, 0.0, -40.1}}, - { 900, { 0.0, -40.6, 1227, -22.5, 878, -41.3, 0.0, -40.6}}, - {1000, { 6.6, -28.0, 1161, -23.4, 825, -39.3, 6.6, -28.0}}, - {1100, { 0.0, -16.5, 1082, -23.5, 797, -36.8, 0.0, -16.5}}, - {1200, {-0.1, 0.3, 1000, -22.2, 798, -34.4, -0.1, 0.3}}, - {1300, { 0.0, -2.3, 943, -19.3, 826, -33.2, 0.0, -2.3}}, - {1400, { 0.0, 13.5, 896, -14.0, 870, -33.8, 0.0, 13.5}}, - {1500, { 0.1, 22.6, 890, -7.2, 916, -36.8, 0.1, 22.6}}, - {1600, { 0.3, 30.3, 940, -0.3, 938, -42.0, 0.3, 30.3}}, - {1700, { 0.5, 12.5, 1052, 4.6, 929, -48.0, 0.5, 12.5}}, - {1800, { 0.8, 458.6, 1212, 6.9, 880, -52.8, 0.8, 458.6}}, - {1900, { 1.1, -5.1, 1410, 3.5, 814, -56.5, 1.1, -5.1}}, - {2000, { 1.4, -5.0, 1579, -3.6, 747, -58.5, 1.4, -5.0}}, - {2100, { 1.5, 6.1, 1618, -13.2, 688, -58.8, 1.5, 6.1}}, - {2200, { 1.5, 33.5, 1491, -21.5, 646, -57.7, 1.5, 33.5}}, - {2300, { 1.4, 80.5, 1275, -24.9, 625, -55.6, 1.4, 80.5}}, - {2400, { 1.3, 142.3, 1078, -20.8, 633, -53.8, 1.3, 142.3}}, - {2500, { 1.4, 196.5, 985, -9.3, 664, -54.5, 1.4, 196.5}}, - {2600, { 1.6, 214.5, 1045, 2.4, 692, -57.6, 1.6, 214.5}}, - {2700, { 2.4, 196.8, 1326, 13.7, 684, -63.5, 2.4, 196.8}}, - {2800, { 3.4, 150.4, 1887, 14.7, 637, -68.3, 3.4, 150.4}}, - {2900, { 4.3, 125.3, 2608, 1.3, 501, -70.7, 4.3, 125.3}}, - {3000, { 4.9, 174.6, 2730, -21.8, 533, -70.6, 4.9, 174.6}}, - {3100, { 4.9, 380.0, 2094, -33.7, 506, -68.5, 4.9, 380.0}}, - {3200, { 5.2, 759.3, 1642, -21.3, 522, -67.0, 5.2, 759.3}}, - {3300, { 8.0, 680.1, 2348, 0.5, 531, -72.9, 8.0, 680.1}}, - {3400, {13.1, 237.8, 4510, -20.9, 482, -77.3, 13.1, 237.8}}, - {3500, {18.2, -18.8, 4116, -59.6, 439, -78.0, 18.2, -18.8}}, - {3600, {22.7, -145.4, 3041, -74.4, 487, -77.7, 22.7, -145.4}}, - {3700, {26.8, -214.5, 2427, -80.1, 383, -77.1, 26.8, -214.5}}, - {3800, {30.4, -257.0, 2054, -82.7, 364, -76.4, 30.4, -257.0}}, - {3900, {33.7, -285.6, 1803, -84.2, 348, -75.0, 33.7, -285.6}}, - {4000, {36.8, -306.2, 1621, -85.1, 334, -75.7, 36.8, -306.2}} -}; - - -/* V.56bis EIA LL-7, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} eia_ll7[] = -{ - { 200, { 0.4, -81.3, 1848, -10.5, 1737, -15.6, 0.4, -81.3}}, - { 300, { 0.3, -68.9, 1785, -16.2, 1585, -21.6, 0.3, -68.9}}, - { 400, { 0.2, -68.1, 1646, -22.0, 1388, -25.8, 0.2, -68.1}}, - { 500, { 0.1, -57.0, 1528, -26.2, 1247, -27.7, 0.1, -57.0}}, - { 600, { 0.0, -59.8, 1349, -28.9, 1087, -27.3, 0.0, -59.8}}, - { 700, { 0.0, -45.0, 1205, -29.1, 975, -24.8, 0.0, -45.0}}, - { 800, {-0.1, -36.9, 1064, -26.8, 885, -19.7, -0.1, -36.9}}, - { 900, {-0.1, -37.1, 989, -22.6, 846, -13.5, -0.1, -37.1}}, - {1000, { 5.9, -29.2, 944, -16.6, 847, -6.1, 5.9, -29.2}}, - {1100, { 0.1, -30.8, 951, -10.5, 900, 0.3, 0.1, -30.8}}, - {1200, { 0.2, -40.7, 1008, -5.9, 999, 4.9, 0.2, -40.7}}, - {1300, { 0.4, -53.3, 1897, -4.0, 1122, 4.6, 0.4, -53.3}}, - {1400, { 0.5, -52.7, 1197, -4.8, 1253, 1.9, 0.5, -52.7}}, - {1500, { 0.6, -48.3, 1269, -8.4, 1339, -3.8, 0.6, -48.3}}, - {1600, { 0.6, -38.0, 1274, -13.2, 1337, -10.4, 0.6, -38.0}}, - {1700, { 0.5, -21.6, 1208, -16.9, 1250, -15.2, 0.5, -21.6}}, - {1800, { 0.4, 539.7, 1119, -17.8, 1143, -16.6, 0.4, 539.7}}, - {1900, { 0.3, 35.4, 1027, -14.7, 1036, -13.7, 0.3, 35.4}}, - {2000, { 0.3, 64.1, 989, -7.9, 998, -6.9, 0.3, 64.1}}, - {2100, { 0.4, 76.1, 1045, 0.1, 1040, 1.0, 0.4, 76.1}}, - {2200, { 0.6, 69.8, 1210, 5.3, 1197, 6.9, 0.6, 69.8}}, - {2300, { 1.0, 55.9, 1460, 4.6, 1430, 5.4, 1.0, 55.9}}, - {2400, { 1.2, 51.3, 1692, -2.8, 1640, -1.7, 1.2, 51.3}}, - {2500, { 1.3, 72.6, 1730, -13.4, 1666, -11.5, 1.3, 72.6}}, - {2600, { 1.3, 117.1, 1613, -49.6, 1556, -16.9, 1.3, 117.1}}, - {2700, { 1.1, 222.5, 1371, -19.5, 1334, -16.1, 1.1, 222.5}}, - {2800, { 1.1, 332.3, 1258, -8.9, 1243, -5.1, 1.1, 332.3}}, - {2900, { 1.7, 356.1, 1474, 4.8, 1480, 8.4, 1.7, 356.1}}, - {3000, { 2.8, 299.9, 2128, 6.6, 2143, 9.8, 2.8, 299.9}}, - {3100, { 3.9, 309.4, 2813, -10.5, 2882, -7.1, 3.9, 309.4}}, - {3200, { 4.4, 576.4, 2490, -27.7, 2487, -22.2, 4.4, 576.4}}, - {3300, { 5.6, 1030.6, 2237, -17.4, 2385, -9.0, 5.6, 1030.6}}, - {3400, {10.7, 570.2, 3882, -19.2, 4855, -14.9, 10.7, 570.2}}, - {3500, {17.3, 83.5, 4116, -57.4, 4649, -63.5, 17.3, 83.5}}, - {3600, {23.2, -130.6, 3057, -74.0, 3175, -78.6, 23.2, -130.6}}, - {3700, {28.3, -153.9, 2432, -80.0, 2471, -83.1, 28.3, -153.9}}, - {3800, {32.8, -292.4, 2055, -82.8, 2072, -85.1, 32.8, -292.4}}, - {3900, {36.9, -249.9, 1803, -84.2, 1811, -86.1, 36.9, -249.9}}, - {4000, {40.7, -356.2, 1621, -85.1, 1625, -86.7, 40.7, -356.2}} -}; - - -/* V.56bis ETSI LL-1, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} etsi_ll1[] = -{ - { 200, {-0.78, 14.0, 1248.5, -9.7, 1248.5, -9.7, -0.78, 14.0}}, - { 300, {-0.74, 10.0, 1220.9, -14.3, 1220.9, -14.3, -0.74, 10.0}}, - { 400, {-0.68, 8.0, 1185.2, -18.6, 1185.2, -18.6, -0.68, 8.0}}, - { 500, {-0.60, 7.0, 1143.9, -22.6, 1143.9, -22.6, -0.60, 7.0}}, - { 600, {-0.51, 6.0, 1099.0, -26.2, 1099.0, -26.2, -0.51, 6.0}}, - { 700, {-0.40, 5.6, 1052.5, -29.5, 1052.5, -29.5, -0.40, 5.6}}, - { 800, {-0.28, 5.3, 1005.9, -32.4, 1005.9, -32.4, -0.28, 5.3}}, - { 900, {-0.14, 5.0, 960.3, -35.0, 960.3, -35.0, -0.14, 5.0}}, - {1000, { 4.7, 4.6, 916.4, -37.3, 916.4, -37.3, 4.7, 4.6}}, - {1100, { 0.16, 4.3, 874.6, -39.3, 874.6, -39.3, 0.16, 4.3}}, - {1200, { 0.33, 3.6, 835.3, -41.1, 835.3, -41.1, 0.33, 3.6}}, - {1300, { 0.49, 2.6, 798.5, -42.6, 798.5, -42.6, 0.49, 2.6}}, - {1400, { 0.67, 2.0, 764.2, -43.9, 764.2, -43.9, 0.67, 2.0}}, - {1500, { 0.85, 1.0, 732.3, -45.1, 732.3, -45.1, 0.85, 1.0}}, - {1600, { 1.04, 0.6, 702.7, -46.1, 702.7, -46.1, 1.04, 0.6}}, - {1700, { 1.23, 0.3, 675.3, -47.0, 675.3, -47.0, 1.23, 0.3}}, - {1800, { 1.43, 40.0, 649.8, -47.7, 649.8, -47.7, 1.43, 40.0}}, - {1900, { 1.63, -1.0, 626.2, -48.4, 626.2, -48.4, 1.63, -1.0}}, - {2000, { 1.83, -2.0, 604.3, -48.9, 604.3, -48.9, 1.83, -2.0}}, - {2100, { 2.03, -3.3, 584.0, -49.4, 584.0, -49.4, 2.03, -3.3}}, - {2200, { 2.23, -3.6, 565.1, -49.8, 565.1, -49.8, 2.23, -3.6}}, - {2300, { 2.44, -4.3, 547.5, -50.1, 547.5, -50.1, 2.44, -4.3}}, - {2400, { 2.64, -5.0, 531.1, -50.4, 531.1, -50.4, 2.64, -5.0}}, - {2500, { 2.84, -6.1, 515.9, -50.6, 515.9, -50.6, 2.84, -6.1}}, - {2600, { 3.05, -6.6, 501.6, -50.8, 501.6, -50.8, 3.05, -6.6}}, - {2700, { 3.25, -7.3, 488.2, -51.0, 488.2, -51.0, 3.25, -7.3}}, - {2800, { 3.45, -7.6, 475.7, -51.1, 475.7, -51.1, 3.45, -7.6}}, - {2900, { 3.65, -8.3, 464.0, -51.1, 464.0, -51.1, 3.65, -8.3}}, - {3000, { 3.85, -8.6, 453.0, -51.2, 453.0, -51.2, 3.85, -8.6}}, - {3100, { 4.04, -9.3, 442.6, -51.2, 442.6, -51.2, 4.04, -9.3}}, - {3200, { 4.24, -10.3, 432.9, -51.2, 432.9, -51.2, 4.24, -10.3}}, - {3300, { 4.43, -10.6, 423.7, -51.2, 423.7, -51.2, 4.43, -10.6}}, - {3400, { 4.62, -11.3, 415.1, -51.2, 415.1, -51.2, 4.62, -11.3}}, - {3500, { 4.81, -11.6, 406.9, -51.1, 406.9, -51.1, 4.81, -11.6}}, - {3600, { 5.00, -12.3, 399.1, -51.1, 399.1, -51.1, 5.00, -12.3}}, - {3700, { 5.19, -13.0, 391.8, -51.0, 391.8, -51.0, 5.19, -13.0}}, - {3800, { 5.37, -13.4, 384.9, -51.0, 384.9, -51.0, 5.37, -13.4}}, - {3900, { 5.56, -13.8, 378.3, -50.9, 378.3, -50.9, 5.56, -13.8}}, - {4000, { 5.74, -14.4, 372.0, -50.8, 372.0, -50.8, 5.74, -14.4}} -}; - - -/* V.56bis ETSI LL-2, non-loaded loop */ - -struct -{ - int freq; - float ad[8]; -} etsi_ll2[] = -{ - { 200, {-0.10, 15.0, 850.3, -3.4, 850.3, -3.4, -0.10, 15.0}}, - { 300, {-0.09, 8.0, 848.1, -5.1, 848.1, -5.1, -0.09, 8.0}}, - { 400, {-0.09, 7.0, 845.1, -6.7, 845.1, -6.7, -0.09, 7.0}}, - { 500, {-0.08, 5.0, 841.3, -8.4, 841.3, -8.4, -0.08, 5.0}}, - { 600, {-0.07, 4.6, 836.7, -10.0, 836.7, -10.0, -0.07, 4.6}}, - { 700, {-0.06, 4.3, 831.3, -11.6, 831.3, -11.6, -0.06, 4.3}}, - { 800, {-0.04, 3.8, 825.3, -13.2, 825.3, -13.2, -0.04, 3.8}}, - { 900, {-0.02, 3.4, 818.6, -14.8, 818.6, -14.8, -0.02, 3.4}}, - {1000, { 1.80, 3.0, 811.4, -16.3, 811.4, -16.3, 1.8, 3.0}}, - {1100, { 0.02, 2.6, 803.6, -17.8, 803.6, -17.8, 0.02, 2.6}}, - {1200, { 0.04, 2.3, 795.3, -19.3, 795.3, -19.3, 0.04, 2.3}}, - {1300, { 0.06, 1.3, 786.6, -20.7, 786.6, -20.7, 0.06, 1.3}}, - {1400, { 0.09, 0.9, 777.5, -22.1, 777.5, -22.1, 0.09, 0.9}}, - {1500, { 0.12, 0.6, 768.1, -23.5, 768.1, -23.5, 0.12, 0.6}}, - {1600, { 0.15, 0.3, 758.4, -24.8, 758.4, -24.8, 0.15, 0.3}}, - {1700, { 0.18, 0.0, 748.4, -26.1, 748.4, -26.1, 0.18, 0.0}}, - {1800, { 0.21, 15, 738.4, -27.3, 738.4, -27.3, 0.21, 15.0}}, - {1900, { 0.24, -1.0, 728.1, -28.5, 728.1, -28.5, 0.24, -1.0}}, - {2000, { 0.28, -2.3, 717.8, -29.7, 717.8, -29.7, 0.28, -2.3}}, - {2100, { 0.32, -2.6, 707.4, -30.8, 707.4, -30.8, 0.32, -2.6}}, - {2200, { 0.36, -3.0, 697.0, -31.9, 697.0, -31.9, 0.36, -3.0}}, - {2300, { 0.40, -3.3, 686.6, -33.0, 686.6, -33.0, 0.40, -3.3}}, - {2400, { 0.44, -3.6, 676.2, -34.0, 676.2, -34.0, 0.44, -3.6}}, - {2500, { 0.48, -4.5, 665.9, -35.0, 665.9, -35.0, 0.48, -4.5}}, - {2600, { 0.53, -5.4, 655.6, -35.9, 655.6, -35.9, 0.53, -5.4}}, - {2700, { 0.57, -6.3, 645.5, -36.8, 645.5, -36.8, 0.57, -6.3}}, - {2800, { 0.62, -6.6, 635.5, -37.7, 635.5, -37.7, 0.62, -6.6}}, - {2900, { 0.67, -6.9, 625.6, -38.6, 625.6, -38.6, 0.67, -6.9}}, - {3000, { 0.72, -7.5, 615.8, -39.4, 615.8, -39.4, 0.72, -7.5}}, - {3100, { 0.77, -8.3, 606.2, -40.2, 606.2, -40.2, 0.77, -8.3}}, - {3200, { 0.82, -8.6, 596.7, -40.9, 596.7, -40.9, 0.82, -8.6}}, - {3300, { 0.87, -9.3, 587.4, -41.6, 587.4, -41.6, 0.87, -9.3}}, - {3400, { 0.92, -9.6, 578.3, -42.3, 578.3, -42.3, 0.92, -9.6}}, - {3500, { 0.98, -10.3, 569.3, -43.0, 569.3, -43.0, 0.98, -10.3}}, - {3600, { 1.03, -10.6, 560.6, -43.7, 560.6, -43.7, 1.03, -10.6}}, - {3700, { 1.09, -11.3, 552.0, -44.3, 552.0, -44.3, 1.09, -11.3}}, - {3800, { 1.14, -11.6, 543.5, -44.9, 543.5, -44.9, 1.14, -11.6}}, - {3900, { 1.20, -12.3, 535.3, -45.4, 535.3, -45.4, 1.20, -12.3}}, - {4000, { 1.26, -13.3, 527.2, -46.0, 527.2, -46.0, 1.26, -13.3}} -}; - -/* V.56bis AD-1 AD-5 AD-6 AD-7 AD-8 AD-9 */ - -struct -{ - int freq; - float ad[6]; -} ad[] = -{ - { 0, {90.0, 90.0, 90.0, 90.0, 90.0, 90.0}}, - { 200, { 6.0, 3.2, 3.0, 2.9, 11.6, 23.3}}, - { 300, { 1.3, 1.4, 1.2, 1.1, 6.9, 13.9}}, - { 400, { 0.0, 0.4, 0.3, 0.3, 4.0, 7.9}}, - { 500, { 0.0, -0.1, 0.0, 0.1, 2.0, 4.1}}, - { 600, { 0.0, -0.1, 0.0, 0.1, 1.2, 2.4}}, - { 700, { 0.0, 0.1, 0.0, 0.0, 0.8, 1.7}}, - { 800, { 0.0, 0.0, 0.0, -0.1, 0.5, 1.1}}, - { 900, { 0.0, 0.0, 0.0, -0.1, 0.2, 0.4}}, - {1000, { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}, - {1100, { 0.0, 0.0, 0.1, 0.0, -0.1, -0.2}}, - {1200, { 0.0, 0.0, 0.1, 0.1, -0.1, -0.2}}, - {1300, { 0.0, 0.1, 0.2, 0.3, -0.1, -0.2}}, - {1400, { 0.0, 0.2, 0.3, 0.4, -0.1, -0.3}}, - {1500, { 0.0, 0.2, 0.3, 0.4, -0.2, -0.4}}, - {1600, { 0.0, 0.3, 0.5, 0.5, -0.1, -0.3}}, - {1700, { 0.0, 0.3, 0.5, 0.6, -0.1, -0.1}}, - {1800, { 0.0, 0.3, 0.5, 0.6, 0.0, 0.0}}, - {1900, { 0.0, 0.4, 0.7, 0.7, 0.1, 0.2}}, - {2000, { 0.0, 0.5, 0.8, 0.9, 0.2, 0.5}}, - {2100, { 0.1, 0.6, 1.0, 1.0, 0.5, 0.9}}, - {2200, { 0.2, 0.7, 1.1, 1.1, 0.6, 1.1}}, - {2300, { 0.3, 0.9, 1.2, 1.4, 0.8, 1.5}}, - {2400, { 0.4, 1.1, 1.5, 1.6, 0.9, 1.8}}, - {2500, { 0.5, 1.3, 1.8, 2.0, 1.1, 2.3}}, - {2600, { 0.6, 1.6, 2.4, 2.7, 1.4, 2.8}}, - {2700, { 0.7, 2.0, 3.0, 3.5, 1.7, 3.4}}, - {2800, { 0.7, 2.3, 3.5, 4.3, 2.0, 4.0}}, - {2900, { 0.9, 2.8, 4.2, 5.0, 2.4, 4.9}}, - {3000, { 1.1, 3.2, 4.9, 5.8, 3.0, 5.9}}, - {3100, { 1.2, 3.5, 5.6, 6.7, 3.4, 6.8}}, - {3200, { 1.3, 4.1, 6.7, 8.0, 3.9, 7.7}}, - {3300, { 1.6, 4.8, 8.0, 9.6, 4.6, 9.2}}, - {3400, { 1.8, 5.3, 9.1, 11.0, 5.4, 10.7}}, - {3500, { 2.4, 5.7, 10.3, 12.2, 6.3, 12.6}}, - {3600, { 3.0, 6.6, 12.1, 13.9, 7.8, 15.5}}, - {3700, { 5.7, 8.9, 15.8, 17.3, 10.3, 20.5}}, - {3800, {13.5, 15.7, 24.4, 25.7, 16.2, 32.4}}, - {3900, {31.2, 31.1, 42.2, 43.3, 29.9, 59.9}}, - {4000, {31.2, 31.1, 42.2, 43.3, 29.9, 59.9}} -}; - -/* V.56bis EDD-1 EDD-2 EDD-3 */ - -struct -{ - int freq; - float edd[3]; -} edd[] = -{ - { 0, {3.98, 3.76, 8.00}}, - { 200, {3.98, 3.76, 8.00}}, - { 300, {2.70, 3.76, 8.00}}, - { 400, {1.69, 2.20, 6.90}}, - { 500, {1.15, 1.36, 5.50}}, - { 600, {0.80, 0.91, 4.40}}, - { 700, {0.60, 0.64, 3.40}}, - { 800, {0.50, 0.46, 2.80}}, - { 900, {0.40, 0.34, 2.00}}, - {1000, {0.30, 0.24, 1.50}}, - {1100, {0.20, 0.16, 1.00}}, - {1200, {0.20, 0.11, 0.70}}, - {1300, {0.10, 0.07, 0.40}}, - {1400, {0.05, 0.05, 0.30}}, - {1500, {0.00, 0.03, 0.20}}, - {1600, {0.00, 0.01, 0.10}}, - {1700, {0.00, 0.00, 0.10}}, - {1800, {0.00, 0.00, 0.00}}, - {1900, {0.00, 0.02, 0.10}}, - {2000, {0.00, 0.04, 0.10}}, - {2100, {0.02, 0.08, 0.10}}, - {2200, {0.02, 0.12, 0.20}}, - {2300, {0.02, 0.16, 0.20}}, - {2400, {0.02, 0.20, 0.30}}, - {2500, {0.10, 0.27, 0.40}}, - {2600, {0.12, 0.36, 0.50}}, - {2700, {0.15, 0.47, 0.80}}, - {2800, {0.20, 0.60, 1.10}}, - {2900, {0.27, 0.77, 1.50}}, - {3000, {0.40, 1.01, 2.00}}, - {3100, {0.56, 1.32, 2.60}}, - {3200, {0.83, 1.78, 3.20}}, - {3300, {1.07, 1.78, 4.00}}, - {3400, {1.39, 1.78, 4.00}}, - {3500, {1.39, 1.78, 4.00}}, - {3600, {1.39, 1.78, 4.00}}, - {3700, {1.39, 1.78, 4.00}}, - {3800, {1.39, 1.78, 4.00}}, - {3900, {1.39, 1.78, 4.00}}, - {4000, {1.39, 1.78, 4.00}} -}; - -/* V.56bis PCM AD-1, AD-2, AD-3 */ - -struct -{ - int freq; - float ad[3]; -} pcm_ad[] = -{ - { 50, {41.4, 77.8, 114.2}}, - { 100, {15.5, 27.7, 39.9}}, - { 150, { 3.7, 6.1, 8.6}}, - { 200, { 0.5, 0.8, 1.0}}, - { 250, {-0.2, -0.2, -0.3}}, - { 300, {-0.2, -0.3, -0.4}}, - { 400, { 0.0, -0.2, -0.3}}, - { 500, {-0.2, -0.4, -0.5}}, - { 600, {-0.2, -0.3, -0.5}}, - { 700, {-0.2, -0.3, -0.5}}, - { 800, {-0.2, -0.4, -0.5}}, - { 900, {-0.2, -0.3, -0.4}}, - {1000, {-0.1, -0.2, -0.3}}, - {1100, {-0.2, -0.3, -0.3}}, - {1200, {-0.2, -0.3, -0.4}}, - {1300, {-0.2, -0.3, -0.5}}, - {1400, {-0.1, -0.3, -0.4}}, - {1500, {-0.1, -0.3, -0.4}}, - {1600, {-0.1, -0.2, -0.3}}, - {1700, {-0.1, -0.3, -0.4}}, - {1800, {-0.2, -0.3, -0.4}}, - {1900, {-0.2, -0.3, -0.3}}, - {2000, {-0.1, -0.2, -0.3}}, - {2100, {-0.1, -0.2, -0.3}}, - {2200, {-0.1, -0.3, -0.4}}, - {2300, {-0.1, -0.1, -0.2}}, - {2400, {-0.1, -0.1, -0.2}}, - {2500, { 0.0, -0.1, -0.1}}, - {2600, { 0.0, -0.1, -0.1}}, - {2700, { 0.0, 0.0, 0.1}}, - {2800, { 0.0, 0.0, 0.1}}, - {2900, { 0.1, 0.2, 0.2}}, - {3000, { 0.0, 0.0, 0.1}}, - {3100, { 0.0, 0.0, 0.0}}, - {3200, { 0.0, 0.0, 0.1}}, - {3300, { 0.3, 0.7, 1.0}}, - {3400, { 1.2, 2.4, 3.6}}, - {3500, { 3.2, 6.3, 9.5}}, - {3550, { 5.0, 9.6, 14.3}}, - {3600, { 7.0, 13.5, 19.9}}, - {3650, {10.0, 18.7, 27.5}}, - {3700, {13.4, 24.6, 35.8}}, - {3750, {18.1, 32.1, 46.2}}, - {3800, {24.3, 41.2, 58.2}}, - {3850, {32.5, 52.6, 72.7}}, - {3900, {43.4, 66.6, 89.8}}, - {4000, {43.4, 66.6, 89.8}} -}; - -/* V.56bis PCM EDD-1, EDD-2, EDD-3 */ - -struct -{ - int freq; - float edd[3]; -} pcm_edd[] = -{ - { 150, { 2.76, 5.5, 8.3}}, - { 200, { 1.70, 3.4, 5.1}}, - { 250, { 0.92, 1.8, 2.8}}, - { 300, { 0.55, 1.1, 1.7}}, - { 400, { 0.25, 0.5, 0.7}}, - { 500, { 0.12, 0.2, 0.4}}, - { 600, { 0.06, 0.1, 0.2}}, - { 700, { 0.03, 0.1, 0.1}}, - { 800, { 0.01, 0.0, 0.0}}, - { 900, { 0.00, 0.0, 0.0}}, - {1000, {-0.01, 0.0, 0.0}}, - {1100, {-0.01, 0.0, 0.0}}, - {1200, {-0.02, 0.0, -0.1}}, - {1300, {-0.02, 0.0, -0.1}}, - {1400, {-0.01, 0.0, 0.0}}, - {1500, {-0.01, 0.0, 0.0}}, - {1600, { 0.00, 0.0, 0.0}}, - {1700, { 0.00, 0.0, 0.0}}, - {1800, { 0.01, 0.0, 0.0}}, - {1900, { 0.02, 0.0, 0.0}}, - {2000, { 0.02, 0.0, 0.1}}, - {2100, { 0.04, 0.1, 0.1}}, - {2200, { 0.05, 0.1, 0.2}}, - {2300, { 0.06, 0.1, 0.2}}, - {2400, { 0.07, 0.1, 0.2}}, - {2500, { 0.10, 0.2, 0.3}}, - {2600, { 0.11, 0.2, 0.3}}, - {2700, { 0.14, 0.3, 0.4}}, - {2800, { 0.18, 0.4, 0.5}}, - {2900, { 0.22, 0.4, 0.6}}, - {3000, { 0.27, 0.5, 0.8}}, - {3100, { 0.34, 0.7, 1.0}}, - {3200, { 0.45, 0.9, 1.4}}, - {3250, { 0.52, 1.0, 1.6}}, - {3300, { 0.60, 1.2, 1.8}}, - {3350, { 0.66, 1.3, 2.0}}, - {3400, { 0.74, 1.5, 2.2}}, - {3450, { 0.79, 1.6, 2.4}}, - {3500, { 0.83, 1.7, 2.5}}, - {3550, { 0.84, 1.7, 2.5}}, - {3600, { 0.81, 1.6, 2.4}}, - {3700, { 0.81, 1.6, 2.4}}, - {3800, { 0.81, 1.6, 2.4}}, - {3900, { 0.81, 1.6, 2.4}}, - {4000, { 0.81, 1.6, 2.4}} -}; - -FILE *outfile; - -float impulse_responses[100][LINE_FILTER_SIZE]; -int filter_sets = 0; - -static void generate_ad_edd(void) -{ - float f; - float offset; - float amp; - float phase; - //float delay; - float pw; -#if defined(HAVE_FFTW3_H) - double in[FFT_SIZE][2]; - double out[FFT_SIZE][2]; -#else - fftw_complex in[FFT_SIZE]; - fftw_complex out[FFT_SIZE]; -#endif - fftw_plan p; - int i; - int j; - int k; - int l; - -#if defined(HAVE_FFTW3_H) - p = fftw_plan_dft_1d(FFT_SIZE, in, out, FFTW_BACKWARD, FFTW_ESTIMATE); -#else - p = fftw_create_plan(FFT_SIZE, FFTW_BACKWARD, FFTW_ESTIMATE); -#endif - for (j = 0; j < 6; j++) - { - for (k = 0; k < 3; k++) - { - for (i = 0; i < FFT_SIZE; i++) - { -#if defined(HAVE_FFTW3_H) - in[i][0] = - in[i][1] = 0.0f; -#else - in[i].re = - in[i].im = 0.0f; -#endif - } - for (i = 1; i < FFT_SIZE/2; i++) - { - f = (float) i*SAMPLE_RATE/FFT_SIZE; - amp = 0.0f; - for (l = 0; l < (int) (sizeof(ad)/sizeof(ad[0])); l++) - { - if (f < ad[l].freq) - break; - } - if (l < (int) (sizeof(ad)/sizeof(ad[0]))) - { - offset = (f - ad[l - 1].freq)/(ad[l].freq - ad[l - 1].freq); - amp = (1.0 - offset)*ad[l - 1].ad[j] + offset*ad[l].ad[j]; - amp = pow(10.0, -amp/20.0); - } - //delay = 0.0f; - for (l = 0; l < (int) (sizeof(edd)/sizeof(edd[0])); l++) - { - if (f < edd[l].freq) - break; - } - if (l < (int) (sizeof(edd)/sizeof(edd[0]))) - { - offset = (f - edd[l - 1].freq)/(edd[l].freq - edd[l - 1].freq); - //delay = (1.0f - offset)*edd[l - 1].edd[k] + offset*edd[l].edd[k]; - } - //phase = 2.0f*M_PI*f*delay*0.001f; - phase = 0.0f; -#if defined(HAVE_FFTW3_H) - in[i][0] = amp*cosf(phase); - in[i][1] = amp*sinf(phase); - in[FFT_SIZE - i][0] = in[i][0]; - in[FFT_SIZE - i][1] = -in[i][1]; -#else - in[i].re = amp*cosf(phase); - in[i].im = amp*sinf(phase); - in[FFT_SIZE - i].re = in[i].re; - in[FFT_SIZE - i].im = -in[i].im; -#endif - } -#if 0 - for (i = 0; i < FFT_SIZE; i++) - fprintf(outfile, "%5d %15.5f,%15.5f\n", i, in[i].re, in[i].im); -#endif -#if defined(HAVE_FFTW3_H) - fftw_execute(p); -#else - fftw_one(p, in, out); -#endif - - fprintf(outfile, "/* V.56bis AD-%d, EDD%d */\n", (j == 0) ? 1 : j + 4, k + 1); - - fprintf(outfile, "const float ad_%d_edd_%d_model[] =\n", (j == 0) ? 1 : j + 4, k + 1); - fprintf(outfile, "{\n"); - /* Normalise the filter's gain */ - pw = 0.0f; - l = FFT_SIZE - (LINE_FILTER_SIZE - 1)/2; - for (i = 0; i < LINE_FILTER_SIZE; i++) - { -#if defined(HAVE_FFTW3_H) - pw += out[l][0]*out[l][0]; -#else - pw += out[l].re*out[l].re; -#endif - if (++l == FFT_SIZE) - l = 0; - } - pw = sqrt(pw); - l = FFT_SIZE - (LINE_FILTER_SIZE - 1)/2; - for (i = 0; i < LINE_FILTER_SIZE; i++) - { -#if defined(HAVE_FFTW3_H) - impulse_responses[filter_sets][i] = out[l][0]/pw; -#else - impulse_responses[filter_sets][i] = out[l].re/pw; -#endif - fprintf(outfile, "%15.5f,\n", impulse_responses[filter_sets][i]); - if (++l == FFT_SIZE) - l = 0; - } - fprintf(outfile, "};\n\n"); - filter_sets++; - } - } -} - -static void generate_proakis(void) -{ - float f; - float f1; - float offset; - float amp; - float phase; - //float delay; - float pw; - int index; - int i; - int l; -#if defined(HAVE_FFTW3_H) - double in[FFT_SIZE][2]; - double out[FFT_SIZE][2]; -#else - fftw_complex in[FFT_SIZE]; - fftw_complex out[FFT_SIZE]; -#endif - fftw_plan p; - -#if defined(HAVE_FFTW3_H) - p = fftw_plan_dft_1d(FFT_SIZE, in, out, FFTW_BACKWARD, FFTW_ESTIMATE); -#else - p = fftw_create_plan(FFT_SIZE, FFTW_BACKWARD, FFTW_ESTIMATE); -#endif - for (i = 0; i < FFT_SIZE; i++) - { -#if defined(HAVE_FFTW3_H) - in[i][0] = - in[i][1] = 0.0f; -#else - in[i].re = - in[i].im = 0.0f; -#endif - } - for (i = 1; i < FFT_SIZE/2; i++) - { - f = (float) i*SAMPLE_RATE/FFT_SIZE; - f1 = f/200.0f; - offset = f1 - floor(f1); - index = (int) floor(f1); - - /* Linear interpolation */ - amp = ((1.0f - offset)*proakis[index].amp + offset*proakis[index + 1].amp)/2.3f; - //delay = (1.0f - offset)*proakis[index].delay + offset*proakis[index + 1].delay; - //phase = 2.0f*M_PI*f*delay*0.001f; - phase = 0.0f; -#if defined(HAVE_FFTW3_H) - in[i][0] = amp*cosf(phase); - in[i][1] = amp*sinf(phase); - in[FFT_SIZE - i][0] = in[i][0]; - in[FFT_SIZE - i][1] = -in[i][1]; -#else - in[i].re = amp*cosf(phase); - in[i].im = amp*sinf(phase); - in[FFT_SIZE - i].re = in[i].re; - in[FFT_SIZE - i].im = -in[i].im; -#endif - } - -#if defined(HAVE_FFTW3_H) - fftw_execute(p); -#else - fftw_one(p, in, out); -#endif - - fprintf(outfile, "/* Medium range telephone line response\n"); - fprintf(outfile, " (from p 537, Digital Communication, John G. Proakis */\n"); - - fprintf(outfile, "const float proakis_line_model[] =\n"); - fprintf(outfile, "{\n"); - /* Normalise the filter's gain */ - pw = 0.0f; - l = FFT_SIZE - (LINE_FILTER_SIZE - 1)/2; - for (i = 0; i < LINE_FILTER_SIZE; i++) - { -#if defined(HAVE_FFTW3_H) - pw += out[l][0]*out[l][0]; -#else - pw += out[l].re*out[l].re; -#endif - if (++l == FFT_SIZE) - l = 0; - } - pw = sqrt(pw); - l = FFT_SIZE - (LINE_FILTER_SIZE - 1)/2; - for (i = 0; i < LINE_FILTER_SIZE; i++) - { -#if defined(HAVE_FFTW3_H) - impulse_responses[filter_sets][i] = out[l][0]/pw; -#else - impulse_responses[filter_sets][i] = out[l].re/pw; -#endif - fprintf(outfile, "%15.5f,\n", impulse_responses[filter_sets][i]); - if (++l == FFT_SIZE) - l = 0; - } - fprintf(outfile, "};\n\n"); - filter_sets++; -} - -int main(int argc, char *argv[]) -{ - int i; - int j; - - if ((outfile = fopen(LINE_MODEL_FILE_NAME, "w")) == NULL) - { - fprintf(stderr, "Failed to open %s\n", "line_model.txt"); - exit(2); - } - - generate_proakis(); - generate_ad_edd(); - - fclose(outfile); - - if (argc > 1) - { - for (i = 0; i < LINE_FILTER_SIZE; i++) - { - printf("%d, ", i); - for (j = 0; j < filter_sets; j++) - { - printf("%15.5f, ", impulse_responses[j][i]); - } - printf("\n"); - } - } - return 0; -} diff --git a/libs/spandsp/spandsp-sim/msvc/make_line_models.2008.vcproj b/libs/spandsp/spandsp-sim/msvc/make_line_models.2008.vcproj deleted file mode 100644 index 1083210545..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/make_line_models.2008.vcproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp-sim/msvc/msvcproj.foot b/libs/spandsp/spandsp-sim/msvc/msvcproj.foot deleted file mode 100644 index f5ed822476..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/msvcproj.foot +++ /dev/null @@ -1,7 +0,0 @@ - -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/libs/spandsp/spandsp-sim/msvc/msvcproj.head b/libs/spandsp/spandsp-sim/msvc/msvcproj.head deleted file mode 100644 index b91c780b04..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/msvcproj.head +++ /dev/null @@ -1,92 +0,0 @@ -# Microsoft Developer Studio Project File - Name="spandsp" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=spandsp - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "spandsp.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "spandsp.mak" CFG="spandsp - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "spandsp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "spandsp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "spandsp - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /D "_WINDLL" /FR /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /map /debug /machine:I386 /out:"Release/libspandsp.dll" - -!ELSEIF "$(CFG)" == "spandsp - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /FR /FD /GZ /c -# SUBTRACT CPP /WX /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"Debug/libspandsp.dll" /pdbtype:sept -# SUBTRACT LINK32 /nodefaultlib - -!ENDIF - -# Begin Target - -# Name "spandsp - Win32 Release" -# Name "spandsp - Win32 Debug" diff --git a/libs/spandsp/spandsp-sim/msvc/vc8proj.foot b/libs/spandsp/spandsp-sim/msvc/vc8proj.foot deleted file mode 100644 index ed37265d27..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/vc8proj.foot +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/libs/spandsp/spandsp-sim/msvc/vc8proj.head b/libs/spandsp/spandsp-sim/msvc/vc8proj.head deleted file mode 100644 index 39cf6caa51..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/vc8proj.head +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp-sim/msvc/vc9proj.foot b/libs/spandsp/spandsp-sim/msvc/vc9proj.foot deleted file mode 100644 index ed37265d27..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/vc9proj.foot +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/libs/spandsp/spandsp-sim/msvc/vc9proj.head b/libs/spandsp/spandsp-sim/msvc/vc9proj.head deleted file mode 100644 index 868afb4aeb..0000000000 --- a/libs/spandsp/spandsp-sim/msvc/vc9proj.head +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp-sim/rfc2198_sim.c b/libs/spandsp/spandsp-sim/rfc2198_sim.c deleted file mode 100644 index 9e286b5dbd..0000000000 --- a/libs/spandsp/spandsp-sim/rfc2198_sim.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * rfc2198_sim.c - Simulate the behaviour of RFC2198 (or UDPTL) redundancy. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#define GEN_CONST -#include -#endif -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif -#include "floating_fudge.h" - -#include "spandsp.h" -#include "spandsp/g1050.h" -#include "spandsp/rfc2198_sim.h" - -#define PACKET_LOSS_TIME -1 - -SPAN_DECLARE(rfc2198_sim_state_t *) rfc2198_sim_init(int model, - int speed_pattern, - int packet_size, - int packet_rate, - int redundancy_depth) -{ - rfc2198_sim_state_t *s; - - if ((s = (rfc2198_sim_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - memset(s, 0, sizeof(*s)); - - s->g1050 = g1050_init(model, speed_pattern, packet_size, packet_rate); - s->redundancy_depth = redundancy_depth; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) rfc2198_sim_free(rfc2198_sim_state_t *s) -{ - g1050_free(s->g1050); - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) rfc2198_sim_put(rfc2198_sim_state_t *s, - const uint8_t buf[], - int len, - int seq_no, - double departure_time) -{ - uint8_t buf2[8192]; - uint8_t *p; - uint16_t *q; - int slot; - int i; - - /* Save the packet in the history buffer */ - memcpy(s->tx_pkt[s->next_pkt], buf, len); - s->tx_pkt_len[s->next_pkt] = len; - s->tx_pkt_seq_no[s->next_pkt] = seq_no; - - /* Construct the redundant packet */ - p = buf2; - slot = s->next_pkt; - q = (uint16_t *) p; - *q = s->redundancy_depth; - p += sizeof(uint16_t); - for (i = 0; i < s->redundancy_depth; i++) - { - q = (uint16_t *) p; - *q = s->tx_pkt_len[slot]; - p += sizeof(uint16_t); - memcpy(p, s->tx_pkt[slot], s->tx_pkt_len[slot]); - p += s->tx_pkt_len[slot]; - slot = (slot - 1) & 0x1F; - } - s->next_pkt = (s->next_pkt + 1) & 0x1F; - return g1050_put(s->g1050, buf2, p - buf2, seq_no, departure_time); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) rfc2198_sim_get(rfc2198_sim_state_t *s, - uint8_t buf[], - int max_len, - double current_time, - int *seq_no, - double *departure_time, - double *arrival_time) -{ - int len; - int lenx; - int seq_nox; - int i; -#if defined(_MSC_VER) - uint8_t *bufx = (uint8_t *) _alloca(s->redundancy_depth*1024); -#else - uint8_t bufx[s->redundancy_depth*1024]; -#endif - uint8_t *p; - uint16_t *q; - int redundancy_depth; - - if (s->rx_queued_pkts) - { - /* We have some stuff from the last g1050_get() still to deliver */ - s->rx_queued_pkts--; - memcpy(buf, s->rx_pkt[s->rx_queued_pkts], s->rx_pkt_len[s->rx_queued_pkts]); - *seq_no = s->rx_pkt_seq_no[s->rx_queued_pkts]; - return s->rx_pkt_len[s->rx_queued_pkts]; - } - len = g1050_get(s->g1050, bufx, s->redundancy_depth*1024, current_time, &seq_nox, departure_time, arrival_time); - if (len > 0) - { - p = bufx; - q = (uint16_t *) p; - redundancy_depth = *q; - p += sizeof(uint16_t); - i = 0; - if (seq_nox > s->next_seq_no) - { - /* Some stuff is missing. Try to fill it in. */ - s->rx_queued_pkts = seq_nox - s->next_seq_no; - if (s->rx_queued_pkts >= redundancy_depth) - s->rx_queued_pkts = redundancy_depth - 1; - for (i = 0; i < s->rx_queued_pkts; i++) - { - q = (uint16_t *) p; - s->rx_pkt_len[i] = *q; - p += sizeof(uint16_t); - memcpy(s->rx_pkt[i], p, s->rx_pkt_len[i]); - s->rx_pkt_seq_no[i] = seq_nox - i; - p += s->rx_pkt_len[i]; - } - } - *seq_no = seq_nox - i; - q = (uint16_t *) p; - lenx = *q; - p += sizeof(uint16_t); - memcpy(buf, p, lenx); - s->next_seq_no = seq_nox + 1; - } - else - { - lenx = len; - } - return lenx; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/spandsp-sim.h b/libs/spandsp/spandsp-sim/spandsp-sim.h deleted file mode 100644 index ea15435665..0000000000 --- a/libs/spandsp/spandsp-sim/spandsp-sim.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * spandsp-sim.h - The head guy amongst the simulator headers - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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 */ - -#if !defined(_SPANDSP_SIM_H_) -#define _SPANDSP_SIM_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/spandsp/g1050.h b/libs/spandsp/spandsp-sim/spandsp/g1050.h deleted file mode 100644 index d9d62bc23c..0000000000 --- a/libs/spandsp/spandsp-sim/spandsp/g1050.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g1050.h - IP network modeling, as per G.1050/TIA-921. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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 */ - -/*! \page g1050_ip_network_model_page G.1050/TIA-921 IP network path model -\section g1050_ip_network_model_page_sec_1 What does it do? -The ITU G.1050 specification defines a model of an IP network, appropriate -for the testing of how streaming media woud behave across the internet. The -model is based on a path having 5 segments: - - a local LAN (wired or wireless) - - an access link to the internet - - an internet of arbitrary complexity - - an access link from the internet - - a distant LAN (wired or wireless) -The impairments typical of these segments at various service levels are modelled. -8 standard service level behaviours are defined, covering lightly loaded to heavily -congested levels. 168 standard sets of link speeds are defined, covering typical -wired and wireless LAN, broadband access link, and backbone characteristics. - -The G.1050 model is suitable for testing the behaviour of RTP, UDPTL and other streaming -protocols for packet loss and jitter behaviour. -*/ - -#if !defined(_G1050_H_) -#define _G1050_H_ - -/* This is the time slice at which delays, packet loss, etc. are calculated. */ -#define G1050_TICKS_PER_SEC 1000 - -/* Search back 200 ms to preserve order of legitimately out of sequence packets. */ -#define SEARCHBACK_PERIOD 200 - -#define G1050_LOW_LOSS 0 -#define G1050_HIGH_LOSS 1 - -#define G1050_LAN_LINK 1 -#define G1050_ACCESS_LINK 2 - -/*! Segment constants, as defined in G.1050. */ -typedef struct -{ - /*! Probability of changing from low to high and high to low loss states */ - double prob_loss_rate_change[2]; - /*! Probability of an impulse in the low and high loss states */ - double prob_impulse[2][2]; - - /*! Impulse height, based on MTU and bit rate */ - double impulse_height; - /*! Impulse decay coefficient for the single pole IIR filter. */ - double impulse_coeff; - - /*! Probability of packet loss due to occupancy. */ - double prob_packet_loss; - /*! Probability of packet loss due to a multiple access collision. */ - double prob_packet_collision_loss; -} g1050_segment_constants_t; - -/*! End-to-end constants, as defined in G.1050. */ -typedef struct -{ - g1050_segment_constants_t segment[4]; -} g1050_constants_t; - -/*! The model definition for a LAN or access link segment */ -typedef struct -{ - /*! Percentage occupancy of the media */ - double percentage_occupancy; - /*! MTU of the media */ - int mtu; - /*! Maximum jitter in the segment. */ - double max_jitter; -} g1050_segment_model_t; - -/*! The model definition for the core network (backbone) segment */ -typedef struct -{ - /*! Basic delay of the backbone for regional paths */ - double base_regional_delay; - /*! Basic delay of the backbone for intercontinental paths */ - double base_intercontinental_delay; - /*! Percentage packet loss of the backbone */ - /*! Percentage packet loss of the backbone. */ - double percentage_packet_loss; - /*! Maximum jitter in the backbone. */ - double max_jitter; - /*! Interval between the backbone route flapping between two paths, in seconds. */ - double route_flap_interval; - /*! The difference in backbone delay between the two routes we flap between, in seconds. */ - double route_flap_delay; - /*! The interval between link failures. */ - double link_failure_interval; - /*! The duration of link failures. */ - double link_failure_duration; - /*! Probability of packet loss in the backbone. */ - double prob_packet_loss; - /*! Probability of a packet going out of sequence in the backbone. */ - double prob_oos; -} g1050_core_model_t; - -/*! The model definition for a complete end-to-end path */ -typedef struct -{ - /*! The likelyhood of occurance probabilities for the A, B and C scenarios defined in G.1050 */ - int loo[3]; - g1050_segment_model_t sidea_lan; - g1050_segment_model_t sidea_access_link; - g1050_core_model_t core; - g1050_segment_model_t sideb_access_link; - g1050_segment_model_t sideb_lan; -} g1050_model_t; - -/*! The speed model for a complete end-to-end path */ -typedef struct -{ - int sidea_lan_bit_rate; - int sidea_lan_multiple_access; - int sidea_access_link_bit_rate_ab; - int sidea_access_link_bit_rate_ba; - int sidea_access_link_qos_enabled; - int sideb_lan_bit_rate; - int sideb_lan_multiple_access; - int sideb_access_link_bit_rate_ab; - int sideb_access_link_bit_rate_ba; - int sideb_access_link_qos_enabled; - double loo; -} g1050_channel_speeds_t; - -/*! The model state for a LAN or access link segment */ -typedef struct -{ - /*! The type of link, G1050_LAN_LINK or G_1050_ACCESS_LINK */ - int link_type; - /*! 1 if in the high loss state, or 0 if in the low loss state. */ - int high_loss; - - /*! The probability of a loss rate change, for both loss rate states. */ - double prob_loss_rate_change[2]; - /*! The probability of a impulse occuring, for both loss rate states. */ - double prob_impulse[2]; - - /*! The maximum permitted height of impulses. */ - double impulse_height; - /*! The impulse decay coefficient. */ - double impulse_coeff; - - /*! The basic serial delay due to the link. */ - double serial_delay; - /*! Peak jitter in the segment. */ - double max_jitter; - /*! The probability of packet loss. */ - double prob_packet_loss; - /*! The probability of packet loss due to collision. */ - double prob_packet_collision_loss; - /*! The maximum addition delay due to congestion. */ - double congestion_delay; - - /*! TRUE if QoS is enabled on the link. */ - int qos_enabled; - /*! TRUE if the link is a multiple access type (e.g. an ethernet hub). */ - int multiple_access; - - /*! The latest packet arrival time seen on the link. */ - double last_arrival_time; - - /*! 3 seconds of predicted delays for the link */ - double delays[3*G1050_TICKS_PER_SEC]; - - /*! A count of packets lost on the link. */ - uint32_t lost_packets; - /*! An extra debug count of packets lost on the link. */ - uint32_t lost_packets_2; -} g1050_segment_state_t; - -/*! The model state for the core network (backbone) segment */ -typedef struct -{ - /* Router model. */ - int32_t route_flap_counter; - int32_t route_flap_interval; - double route_flap_delta; - - /* Link failure model. */ - int32_t link_failure_counter; - int32_t link_recovery_counter; - - int32_t link_failure_interval_ticks; - int32_t link_failure_duration_ticks; - - /*! Basic backbone delay */ - double base_delay; - /*! Peak jitter in the backbone delay */ - double max_jitter; - /*! Probability of packet loss in the backbone, in percent */ - double prob_packet_loss; - /*! Probability of a packet going out of sequence in the backbone. */ - double prob_oos; - - /*! The latest packet arrival time seen on the link. */ - double last_arrival_time; - double delay_delta; - - /*! 3 seconds of predicted delays for the link */ - double delays[3*G1050_TICKS_PER_SEC]; - - /*! A count of packets lost on the link. */ - uint32_t lost_packets; - /*! An extra debug count of packets lost on the link. */ - uint32_t lost_packets_2; -} g1050_core_state_t; - -/*! The definition of an element in the packet queue */ -typedef struct g1050_queue_element_s -{ - struct g1050_queue_element_s *next; - struct g1050_queue_element_s *prev; - int seq_no; - double departure_time; - double arrival_time; - int len; - uint8_t pkt[]; -} g1050_queue_element_t; - -/*! The model definition for a complete end-to-end path */ -typedef struct -{ - int packet_rate; - int packet_size; - float base_time; - g1050_segment_state_t segment[4]; - g1050_core_state_t core; - double arrival_times_1[3*G1050_TICKS_PER_SEC]; - double arrival_times_2[3*G1050_TICKS_PER_SEC]; - g1050_queue_element_t *first; - g1050_queue_element_t *last; -} g1050_state_t; - -extern g1050_constants_t g1050_constants[1]; -extern g1050_channel_speeds_t g1050_speed_patterns[168]; -extern g1050_model_t g1050_standard_models[9]; - -#ifdef __cplusplus -extern "C" -{ -#endif - -SPAN_DECLARE(g1050_state_t *) g1050_init(int model, - int speed_pattern, - int packet_size, - int packet_rate); - -SPAN_DECLARE(int) g1050_free(g1050_state_t *s); - -SPAN_DECLARE(void) g1050_dump_parms(int model, int speed_pattern); - -SPAN_DECLARE(int) g1050_put(g1050_state_t *s, - const uint8_t buf[], - int len, - int seq_no, - double departure_time); - -SPAN_DECLARE(int) g1050_get(g1050_state_t *s, - uint8_t buf[], - int max_len, - double current_time, - int *seq_no, - double *departure_time, - double *arrival_time); - -SPAN_DECLARE(void) g1050_queue_dump(g1050_state_t *s); - -#ifdef __cplusplus -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/spandsp/line_model.h b/libs/spandsp/spandsp-sim/spandsp/line_model.h deleted file mode 100644 index 72fe4811c9..0000000000 --- a/libs/spandsp/spandsp-sim/spandsp/line_model.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * line_model.h - Model a telephone line. - * - * 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 */ - -/*! \page line_model_page Telephone line model -\section line_model_page_sec_1 What does it do? -The telephone line modelling module provides simple modelling of one way and two -way telephone lines. - -The path being modelled is: - - - terminal - - | < hybrid echo (2-way models) - - | - - | < noise and filtering - - | - - | < hybrid echo (2-way models) - - CO - - | - - | < A-law distortion + bulk delay - - | - - CO - - | < hybrid echo (2-way models) - - | - - | < noise and filtering - - | - - | < hybrid echo (2-way models) - - terminal -*/ - -#if !defined(_SPANDSP_LINE_MODEL_H_) -#define _SPANDSP_LINE_MODEL_H_ - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -#include - -#define LINE_FILTER_SIZE 129 - -/*! - One way line model descriptor. This holds the complete state of - a line model with transmission in only one direction. -*/ -typedef struct -{ - codec_munge_state_t *munge; - - /*! The coefficients for the near end analogue section simulation filter */ - const float *near_filter; - /*! The number of coefficients for the near end analogue section simulation filter */ - int near_filter_len; - /*! Last transmitted samples (ring buffer, used by the line filter) */ - float near_buf[LINE_FILTER_SIZE]; - /*! Pointer of the last transmitted sample in buf */ - int near_buf_ptr; - /*! The noise source for local analogue section of the line */ - awgn_state_t near_noise; - - /*! The bulk delay of the path, in samples */ - int bulk_delay; - /*! A pointer to the current write position in the bulk delay store. */ - int bulk_delay_ptr; - /*! The data store for simulating the bulk delay */ - int16_t bulk_delay_buf[8000]; - - /*! The coefficients for the far end analogue section simulation filter */ - const float *far_filter; - /*! The number of coefficients for the far end analogue section simulation filter */ - int far_filter_len; - /*! Last transmitted samples (ring buffer, used by the line filter) */ - float far_buf[LINE_FILTER_SIZE]; - /*! Pointer of the last transmitted sample in buf */ - int far_buf_ptr; - /*! The noise source for distant analogue section of the line */ - awgn_state_t far_noise; - - /*! The scaling factor for the local CPE hybrid echo */ - float near_cpe_hybrid_echo; - /*! The scaling factor for the local CO hybrid echo */ - float near_co_hybrid_echo; - - /*! The scaling factor for the far CPE hybrid echo */ - float far_cpe_hybrid_echo; - /*! The scaling factor for the far CO hybrid echo */ - float far_co_hybrid_echo; - /*! DC offset impairment */ - float dc_offset; - - /*! Mains pickup impairment */ - int mains_interference; - tone_gen_state_t mains_tone; -} one_way_line_model_state_t; - -/*! - Two way line model descriptor. This holds the complete state of - a line model with transmission in both directions. -*/ -typedef struct -{ - one_way_line_model_state_t line1; - one_way_line_model_state_t line2; - float fout1; - float fout2; -} both_ways_line_model_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -SPAN_DECLARE_DATA extern const float *line_models[]; - -SPAN_DECLARE(void) both_ways_line_model(both_ways_line_model_state_t *s, - int16_t output1[], - const int16_t input1[], - int16_t output2[], - const int16_t input2[], - int samples); - -SPAN_DECLARE(void) both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2); - -SPAN_DECLARE(void) both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2); - -SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model1, - float noise1, - float echo_level_cpe1, - float echo_level_co1, - int model2, - float noise2, - float echo_level_cpe2, - float echo_level_co2, - int codec, - int rbs_pattern); - -SPAN_DECLARE(int) both_ways_line_model_free(both_ways_line_model_state_t *s); - -SPAN_DECLARE(void) one_way_line_model(one_way_line_model_state_t *s, - int16_t output[], - const int16_t input[], - int samples); - -SPAN_DECLARE(void) one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc); - -SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level); - -SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, float noise, int codec, int rbs_pattern); - -SPAN_DECLARE(int) one_way_line_model_free(one_way_line_model_state_t *s); - -#ifdef __cplusplus -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/spandsp/line_models.h b/libs/spandsp/spandsp-sim/spandsp/line_models.h deleted file mode 100644 index 3acdd4492c..0000000000 --- a/libs/spandsp/spandsp-sim/spandsp/line_models.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * line_model.h - Model a telephone line. - * - * 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_LINE_MODELS_H_) -#define _SPANDSP_LINE_MODELS_H_ - -extern float proakis_line_model[]; -extern float ad_1_edd_1_model[]; -extern float ad_1_edd_2_model[]; -extern float ad_1_edd_3_model[]; -extern float ad_5_edd_1_model[]; -extern float ad_5_edd_2_model[]; -extern float ad_5_edd_3_model[]; -extern float ad_6_edd_1_model[]; -extern float ad_6_edd_2_model[]; -extern float ad_6_edd_3_model[]; -extern float ad_7_edd_1_model[]; -extern float ad_7_edd_2_model[]; -extern float ad_7_edd_3_model[]; -extern float ad_8_edd_1_model[]; -extern float ad_8_edd_2_model[]; -extern float ad_8_edd_3_model[]; -extern float ad_9_edd_1_model[]; -extern float ad_9_edd_2_model[]; -extern float ad_9_edd_3_model[]; - -#ifdef __cplusplus -extern "C" -{ -#endif - -#ifdef __cplusplus -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h b/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h deleted file mode 100644 index 5aaa495ba1..0000000000 --- a/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * rfc2198_sim.h - Simulate the behaviour of RFC2198 (or UDPTL) redundancy. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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 */ - -/*! \page rfc2198_model_page RFC2198 simulation -\section rfc2198_model_page_sec_1 What does it do? -*/ - -#if !defined(_RFC2198_SIM_H_) -#define _RFC2198_SIM_H_ - -/*! The definition of an element in the packet queue */ -typedef struct rfc2198_sim_queue_element_s -{ - struct rfc2198_sim_queue_element_s *next; - struct rfc2198_sim_queue_element_s *prev; - int seq_no; - double departure_time; - double arrival_time; - int len; - uint8_t pkt[]; -} rfc2198_sim_queue_element_t; - -/*! The model definition for a complete end-to-end path */ -typedef struct -{ - int redundancy_depth; - int next_seq_no; - g1050_state_t *g1050; - rfc2198_sim_queue_element_t *first; - rfc2198_sim_queue_element_t *last; - uint8_t tx_pkt[32][1024]; - int tx_pkt_len[32]; - int tx_pkt_seq_no[32]; - int next_pkt; - uint8_t rx_pkt[32][1024]; - int rx_pkt_len[32]; - int rx_pkt_seq_no[32]; - int rx_queued_pkts; -} rfc2198_sim_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -SPAN_DECLARE(rfc2198_sim_state_t *) rfc2198_sim_init(int model, - int speed_pattern, - int packet_size, - int packet_rate, - int redundancy_depth); - -SPAN_DECLARE(int) rfc2198_sim_free(rfc2198_sim_state_t *s); - -SPAN_DECLARE(int) rfc2198_sim_put(rfc2198_sim_state_t *s, - const uint8_t buf[], - int len, - int seq_no, - double departure_time); - -SPAN_DECLARE(int) rfc2198_sim_get(rfc2198_sim_state_t *s, - uint8_t buf[], - int max_len, - double current_time, - int *seq_no, - double *departure_time, - double *arrival_time); - -#ifdef __cplusplus -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/spandsp/test_utils.h b/libs/spandsp/spandsp-sim/spandsp/test_utils.h deleted file mode 100644 index 9a7214976e..0000000000 --- a/libs/spandsp/spandsp-sim/spandsp/test_utils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * test_utils.h - Utility routines for module tests. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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(_TEST_UTILS_H_) -#define _TEST_UTILS_H_ - -#include - -enum -{ - MUNGE_CODEC_NONE = 0, - MUNGE_CODEC_ALAW, - MUNGE_CODEC_ULAW, - MUNGE_CODEC_G726_40K, - MUNGE_CODEC_G726_32K, - MUNGE_CODEC_G726_24K, - MUNGE_CODEC_G726_16K, -}; - -typedef struct codec_munge_state_s codec_munge_state_t; - -typedef struct complexify_state_s complexify_state_t; - -#ifdef __cplusplus -extern "C" { -#endif - -SPAN_DECLARE(complexify_state_t *) complexify_init(void); - -SPAN_DECLARE(int) complexify_free(complexify_state_t *s); - -SPAN_DECLARE(complexf_t) complexify(complexify_state_t *s, int16_t amp); - -SPAN_DECLARE(void) fft(complex_t data[], int len); - -SPAN_DECLARE(void) ifft(complex_t data[], int len); - -SPAN_DECLARE(codec_munge_state_t *) codec_munge_init(int codec, int info); - -SPAN_DECLARE(int) codec_munge_free(codec_munge_state_t *s); - -SPAN_DECLARE(void) codec_munge(codec_munge_state_t *s, int16_t amp[], int len); - -SPAN_DECLARE(SNDFILE *) sf_open_telephony_read(const char *name, int channels); - -SPAN_DECLARE(SNDFILE *) sf_open_telephony_write(const char *name, int channels); - -SPAN_DECLARE(int) sf_close_telephony(SNDFILE *handle); - -#ifdef __cplusplus -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp-sim/test_utils.c b/libs/spandsp/spandsp-sim/test_utils.c deleted file mode 100644 index 21f019ec91..0000000000 --- a/libs/spandsp/spandsp-sim/test_utils.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * test_utils.c - Utility routines for module tests. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 */ - -#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 "floating_fudge.h" -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -#include "spandsp.h" -#include "spandsp-sim.h" - -#define MAX_FFT_LEN 8192 - -struct codec_munge_state_s -{ - int munging_codec; - g726_state_t g726_enc_state; - g726_state_t g726_dec_state; - int rbs_pattern; - int sequence; -}; - -struct complexify_state_s -{ - float history[128]; - int ptr; -}; - -static complex_t circle[MAX_FFT_LEN/2]; -static int circle_init = false; -static complex_t icircle[MAX_FFT_LEN/2]; -static int icircle_init = false; - -#define SF_MAX_HANDLE 32 - -static int sf_close_at_exit_registered = false; - -static SNDFILE *sf_close_at_exit_list[SF_MAX_HANDLE] = -{ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -SPAN_DECLARE(complexify_state_t *) complexify_init(void) -{ - complexify_state_t *s; - int i; - - if ((s = (complexify_state_t *) malloc(sizeof(*s)))) - { - s->ptr = 0; - for (i = 0; i < 128; i++) - s->history[i] = 0.0f; - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) complexify_free(complexify_state_t *s) -{ - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) complexify(complexify_state_t *s, int16_t amp) -{ -#define HILBERT_GAIN 1.569546344 - static const float hilbert_coeffs[] = - { - +0.0012698413f, +0.0013489483f, - +0.0015105196f, +0.0017620440f, - +0.0021112899f, +0.0025663788f, - +0.0031358856f, +0.0038289705f, - +0.0046555545f, +0.0056265487f, - +0.0067541562f, +0.0080522707f, - +0.0095370033f, +0.0112273888f, - +0.0131463382f, +0.0153219442f, - +0.0177892941f, +0.0205930381f, - +0.0237910974f, +0.0274601544f, - +0.0317040029f, +0.0366666667f, - +0.0425537942f, +0.0496691462f, - +0.0584802574f, +0.0697446887f, - +0.0847739823f, +0.1060495199f, - +0.1388940865f, +0.1971551103f, - +0.3316207267f, +0.9994281838f - }; - float famp; - int i; - int j; - int k; - complexf_t res; - - s->history[s->ptr] = amp; - i = s->ptr - 63; - if (i < 0) - i += 128; - res.re = s->history[i]; - - famp = 0.0f; - j = s->ptr - 126; - if (j < 0) - j += 128; - for (i = 0, k = s->ptr; i < 32; i++) - { - famp += (s->history[k] - s->history[j])*hilbert_coeffs[i]; - j += 2; - if (j >= 128) - j -= 128; - k -= 2; - if (k < 0) - k += 128; - } - res.im = famp/HILBERT_GAIN; - - if (++s->ptr >= 128) - s->ptr = 0; - return res; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t expj(double theta) -{ - return complex_set(cos(theta), sin(theta)); -} -/*- End of function --------------------------------------------------------*/ - -static void fftx(complex_t data[], complex_t temp[], int n) -{ - int i; - int h; - int p; - int t; - int i2; - complex_t wkt; - - if (n > 1) - { - h = n/2; - for (i = 0; i < h; i++) - { - i2 = i*2; - temp[i] = data[i2]; /* Even */ - temp[h + i] = data[i2 + 1]; /* Odd */ - } - fftx(&temp[0], &data[0], h); - fftx(&temp[h], &data[h], h); - p = 0; - t = MAX_FFT_LEN/n; - for (i = 0; i < h; i++) - { - wkt = complex_mul(&circle[p], &temp[h + i]); - data[i] = complex_add(&temp[i], &wkt); - data[h + i] = complex_sub(&temp[i], &wkt); - p += t; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static void ifftx(complex_t data[], complex_t temp[], int n) -{ - int i; - int h; - int p; - int t; - int i2; - complex_t wkt; - - if (n > 1) - { - h = n/2; - for (i = 0; i < h; i++) - { - i2 = i*2; - temp[i] = data[i2]; /* Even */ - temp[h + i] = data[i2 + 1]; /* Odd */ - } - fftx(&temp[0], &data[0], h); - fftx(&temp[h], &data[h], h); - p = 0; - t = MAX_FFT_LEN/n; - for (i = 0; i < h; i++) - { - wkt = complex_mul(île[p], &temp[h + i]); - data[i] = complex_add(&temp[i], &wkt); - data[h + i] = complex_sub(&temp[i], &wkt); - p += t; - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fft(complex_t data[], int len) -{ - int i; - double x; - complex_t temp[MAX_FFT_LEN]; - - /* A very slow and clunky FFT, that's just fine for tests. */ - if (!circle_init) - { - for (i = 0; i < MAX_FFT_LEN/2; i++) - { - x = -(2.0*3.1415926535*i)/(double) MAX_FFT_LEN; - circle[i] = expj(x); - } - circle_init = true; - } - fftx(data, temp, len); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) ifft(complex_t data[], int len) -{ - int i; - double x; - complex_t temp[MAX_FFT_LEN]; - - /* A very slow and clunky FFT, that's just fine for tests. */ - if (!icircle_init) - { - for (i = 0; i < MAX_FFT_LEN/2; i++) - { - x = (2.0*3.1415926535*i)/(double) MAX_FFT_LEN; - icircle[i] = expj(x); - } - icircle_init = true; - } - ifftx(data, temp, len); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(codec_munge_state_t *) codec_munge_init(int codec, int info) -{ - codec_munge_state_t *s; - - if ((s = (codec_munge_state_t *) malloc(sizeof(*s)))) - { - switch (codec) - { - case MUNGE_CODEC_G726_40K: - g726_init(&s->g726_enc_state, 40000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - g726_init(&s->g726_dec_state, 40000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - s->munging_codec = MUNGE_CODEC_G726_32K; - break; - case MUNGE_CODEC_G726_32K: - g726_init(&s->g726_enc_state, 32000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - g726_init(&s->g726_dec_state, 32000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - s->munging_codec = MUNGE_CODEC_G726_32K; - break; - case MUNGE_CODEC_G726_24K: - g726_init(&s->g726_enc_state, 24000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - g726_init(&s->g726_dec_state, 24000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - s->munging_codec = MUNGE_CODEC_G726_32K; - break; - case MUNGE_CODEC_G726_16K: - g726_init(&s->g726_enc_state, 16000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - g726_init(&s->g726_dec_state, 16000, G726_ENCODING_LINEAR, G726_PACKING_NONE); - s->munging_codec = MUNGE_CODEC_G726_32K; - break; - default: - s->munging_codec = codec; - break; - } - s->sequence = 0; - s->rbs_pattern = info; - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) codec_munge_free(codec_munge_state_t *s) -{ - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) codec_munge(codec_munge_state_t *s, int16_t amp[], int len) -{ - uint8_t law; - uint8_t adpcmdata[160]; - int i; - int adpcm; - int x; - - switch (s->munging_codec) - { - case MUNGE_CODEC_NONE: - /* Do nothing */ - break; - case MUNGE_CODEC_ALAW: - for (i = 0; i < len; i++) - { - law = linear_to_alaw(amp[i]); - amp[i] = alaw_to_linear(law); - } - break; - case MUNGE_CODEC_ULAW: - for (i = 0; i < len; i++) - { - law = linear_to_ulaw(amp[i]); - if (s->rbs_pattern & (1 << s->sequence)) - { - /* Strip the bottom bit at the RBS rate */ - law &= 0xFE; - } - amp[i] = ulaw_to_linear(law); - } - break; - case MUNGE_CODEC_G726_32K: - /* This could actually be any of the G.726 rates */ - for (i = 0; i < len; i += x) - { - x = (len - i >= 160) ? 160 : (len - i); - adpcm = g726_encode(&s->g726_enc_state, adpcmdata, amp + i, x); - g726_decode(&s->g726_dec_state, amp + i, adpcmdata, adpcm); - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void sf_close_at_exit(void) -{ - int i; - - for (i = 0; i < SF_MAX_HANDLE; i++) - { - if (sf_close_at_exit_list[i]) - { - sf_close(sf_close_at_exit_list[i]); - sf_close_at_exit_list[i] = NULL; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static int sf_record_handle(SNDFILE *handle) -{ - int i; - - for (i = 0; i < SF_MAX_HANDLE; i++) - { - if (sf_close_at_exit_list[i] == NULL) - break; - } - if (i >= SF_MAX_HANDLE) - return -1; - sf_close_at_exit_list[i] = handle; - if (!sf_close_at_exit_registered) - { - atexit(sf_close_at_exit); - sf_close_at_exit_registered = true; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(SNDFILE *) sf_open_telephony_read(const char *name, int channels) -{ - SNDFILE *handle; - SF_INFO info; - - memset(&info, 0, sizeof(info)); - if ((handle = sf_open(name, SFM_READ, &info)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s' for reading\n", name); - exit(2); - } - if (info.samplerate != SAMPLE_RATE) - { - printf(" Unexpected sample rate in audio file '%s'\n", name); - exit(2); - } - if (info.channels != channels) - { - printf(" Unexpected number of channels in audio file '%s'\n", name); - exit(2); - } - sf_record_handle(handle); - return handle; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(SNDFILE *) sf_open_telephony_write(const char *name, int channels) -{ - SNDFILE *handle; - SF_INFO info; - - memset(&info, 0, sizeof(info)); - info.frames = 0; - info.samplerate = SAMPLE_RATE; - info.channels = channels; - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - info.sections = 1; - info.seekable = 1; - - if ((handle = sf_open(name, SFM_WRITE, &info)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s' for writing\n", name); - exit(2); - } - sf_record_handle(handle); - return handle; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) sf_close_telephony(SNDFILE *handle) -{ - int res; - int i; - - if ((res = sf_close(handle)) == 0) - { - for (i = 0; i < SF_MAX_HANDLE; i++) - { - if (sf_close_at_exit_list[i] == handle) - { - sf_close_at_exit_list[i] = NULL; - break; - } - } - } - return res; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/spandsp.pc.in b/libs/spandsp/spandsp.pc.in deleted file mode 100644 index 19fb1d501a..0000000000 --- a/libs/spandsp/spandsp.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: spandsp -Description: A DSP library for telephony. -Requires: -Version: @VERSION@ -Libs: -L${libdir} -lspandsp -Libs.private: -ltiff -lm -Cflags: -I${includedir} diff --git a/libs/spandsp/spandsp.spec b/libs/spandsp/spandsp.spec deleted file mode 100644 index d248ac71fb..0000000000 --- a/libs/spandsp/spandsp.spec +++ /dev/null @@ -1,106 +0,0 @@ -%global pre 21 - -Summary: A DSP library for telephony. -Name: spandsp -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-1.99.0.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: libtiff-devel%{?_isa} -BuildRequires: libjpeg-turbo-devel%{?_isa} -BuildRequires: libxml2-devel%{?_isa} -BuildRequires: libsndfile-devel%{?_isa} -BuildRequires: doxygen -BuildRequires: libxslt -BuildRequires: docbook-style-xsl - -%description -SpanDSP is a library of DSP functions for telephony, in the 8000 -sample per second world of E1s, T1s, and higher order PCM channels. It -contains low level functions, such as basic filters. It also contains -higher level functions, such as cadenced supervisory tone detection, -and a complete software FAX machine. The software has been designed to -avoid intellectual property issues, using mature techniques where all -relevant patents have expired. See the file DueDiligence for important -information about these intellectual property issues. - -%package devel -Summary: SpanDSP development files -Group: Development/Libraries -Requires: spandsp%{?_isa} = %{version}-%{release} -Requires: libtiff-devel%{?_isa} -Requires: libjpeg-turbo-devel%{?_isa} - -%description devel -SpanDSP development files. - -%package apidoc -Summary: SpanDSP API documentation -Group: Development/Libraries - -%description apidoc -SpanDSP API documentation. - -%prep -%setup -q - -%build -%configure --enable-doc --disable-static --disable-rpath -make -find doc/api -type f | xargs touch -r configure - -%install -rm -rf %{buildroot} -make install DESTDIR=%{buildroot} -rm %{buildroot}%{_libdir}/libspandsp.la -mkdir -p %{buildroot}%{_datadir}/spandsp - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc DueDiligence ChangeLog AUTHORS COPYING NEWS README - -%{_libdir}/libspandsp.so.* - -%{_datadir}/spandsp - -%files devel -%defattr(-,root,root,-) -%{_includedir}/spandsp.h -%{_includedir}/spandsp -%{_libdir}/libspandsp.so -%{_libdir}/pkgconfig/spandsp.pc - -%files apidoc -%defattr(-,root,root,-) -%doc doc/api/html/* - -%post -p /sbin/ldconfig - -%postun -p /sbin/ldconfig - -%changelog -* Mon Oct 03 2011 Steve Underwood 0.0.6-1 -- Converge with what Fedora do - -* Wed Sep 24 2008 Tzafrir Cohen 0.0.5-1 -- Preparing for 0.0.5pre4 release -- License: LGPL - -* Mon Jun 23 2008 Steve Underwood 0.0.5-1 -- Cleared out the dependency on libxml2 - -* Sun Dec 31 2006 Steve Underwood 0.0.3-1 -- Preparing for 0.0.3 release - -* Sat Oct 16 2004 Steve Underwood 0.0.2-1 -- Preparing for 0.0.2 release - -* Thu Apr 15 2004 Steve Underwood 0.0.1-1 -- Initial version diff --git a/libs/spandsp/spandsp.spec.in b/libs/spandsp/spandsp.spec.in deleted file mode 100644 index 759dd17c07..0000000000 --- a/libs/spandsp/spandsp.spec.in +++ /dev/null @@ -1,106 +0,0 @@ -%global pre 21 - -Summary: A DSP library for telephony. -Name: @PACKAGE@ -Version: @VERSION@ -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/@PACKAGE@-@VERSION@.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: libtiff-devel%{?_isa} -BuildRequires: libjpeg-turbo-devel%{?_isa} -BuildRequires: libxml2-devel%{?_isa} -BuildRequires: libsndfile-devel%{?_isa} -BuildRequires: doxygen -BuildRequires: libxslt -BuildRequires: docbook-style-xsl - -%description -SpanDSP is a library of DSP functions for telephony, in the 8000 -sample per second world of E1s, T1s, and higher order PCM channels. It -contains low level functions, such as basic filters. It also contains -higher level functions, such as cadenced supervisory tone detection, -and a complete software FAX machine. The software has been designed to -avoid intellectual property issues, using mature techniques where all -relevant patents have expired. See the file DueDiligence for important -information about these intellectual property issues. - -%package devel -Summary: SpanDSP development files -Group: Development/Libraries -Requires: spandsp%{?_isa} = %{version}-%{release} -Requires: libtiff-devel%{?_isa} -Requires: libjpeg-turbo-devel%{?_isa} - -%description devel -SpanDSP development files. - -%package apidoc -Summary: SpanDSP API documentation -Group: Development/Libraries - -%description apidoc -SpanDSP API documentation. - -%prep -%setup -q - -%build -%configure --enable-doc --disable-static --disable-rpath -make -find doc/api -type f | xargs touch -r configure - -%install -rm -rf %{buildroot} -make install DESTDIR=%{buildroot} -rm %{buildroot}%{_libdir}/libspandsp.la -mkdir -p %{buildroot}%{_datadir}/spandsp - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc DueDiligence ChangeLog AUTHORS COPYING NEWS README - -%{_libdir}/libspandsp.so.* - -%{_datadir}/spandsp - -%files devel -%defattr(-,root,root,-) -%{_includedir}/spandsp.h -%{_includedir}/spandsp -%{_libdir}/libspandsp.so -%{_libdir}/pkgconfig/spandsp.pc - -%files apidoc -%defattr(-,root,root,-) -%doc doc/api/html/* - -%post -p /sbin/ldconfig - -%postun -p /sbin/ldconfig - -%changelog -* Mon Oct 03 2011 Steve Underwood 0.0.6-1 -- Converge with what Fedora do - -* Wed Sep 24 2008 Tzafrir Cohen 0.0.5-1 -- Preparing for 0.0.5pre4 release -- License: LGPL - -* Mon Jun 23 2008 Steve Underwood 0.0.5-1 -- Cleared out the dependency on libxml2 - -* Sun Dec 31 2006 Steve Underwood 0.0.3-1 -- Preparing for 0.0.3 release - -* Sat Oct 16 2004 Steve Underwood 0.0.2-1 -- Preparing for 0.0.2 release - -* Thu Apr 15 2004 Steve Underwood 0.0.1-1 -- Initial version diff --git a/libs/spandsp/spandsp/fax-tests.dtd b/libs/spandsp/spandsp/fax-tests.dtd deleted file mode 100644 index 8299ecbb34..0000000000 --- a/libs/spandsp/spandsp/fax-tests.dtd +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp/fax-tests.xml b/libs/spandsp/spandsp/fax-tests.xml deleted file mode 100644 index b6ff399699..0000000000 --- a/libs/spandsp/spandsp/fax-tests.xml +++ /dev/null @@ -1,707 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp/global-tones.xml b/libs/spandsp/spandsp/global-tones.xml deleted file mode 100644 index 5b376d1e86..0000000000 --- a/libs/spandsp/spandsp/global-tones.xml +++ /dev/null @@ -1,7363 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp/tones.dtd b/libs/spandsp/spandsp/tones.dtd deleted file mode 100644 index b751d2387d..0000000000 --- a/libs/spandsp/spandsp/tones.dtd +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/spandsp/tsb85.xml b/libs/spandsp/spandsp/tsb85.xml deleted file mode 100644 index c72a863151..0000000000 --- a/libs/spandsp/spandsp/tsb85.xml +++ /dev/null @@ -1,7000 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/Makefile.am b/libs/spandsp/src/Makefile.am deleted file mode 100644 index 6a80d13c16..0000000000 --- a/libs/spandsp/src/Makefile.am +++ /dev/null @@ -1,582 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -AM_CFLAGS = $(COMP_VENDOR_CFLAGS) -AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) - -DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \ - $(srcdir)/cielab_luts.h \ - $(srcdir)/math_fixed_tables.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.2005.sln \ - libspandsp.2008.sln \ - libspandsp.2005.vcproj \ - libspandsp.2008.vcproj \ - libspandsp.2010.vcproj \ - libspandsp.2012.vcxproj \ - libtiff.2005.vcproj \ - libtiff.2008.vcproj \ - filter_tools.c \ - make_at_dictionary.c \ - 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 \ - msvc/getopt.c \ - msvc/gettimeofday.c \ - msvc/inttypes.h \ - msvc/make_at_dictionary.2005.vcproj \ - msvc/make_at_dictionary.2008.vcproj \ - msvc/make_modem_filter.2005.vcproj \ - msvc/make_modem_filter.2008.vcproj \ - msvc/msvcproj.head \ - msvc/msvcproj.foot \ - msvc/spandsp.h \ - msvc/tgmath.h \ - msvc/tiff/cleancount \ - msvc/unistd.h \ - msvc/util.vbs \ - msvc/vc8proj.foot \ - msvc/vc8proj.head \ - msvc/vc9proj.foot \ - msvc/vc9proj.head \ - msvc/vc10proj.foot \ - msvc/vc10proj.head \ - msvc/vc12proj.foot \ - msvc/vc12proj.head \ - msvc/sys/time.h \ - spandsp/private/README \ - spandsp/version.h.in - -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 \ - bell_r2_mf.c \ - bert.c \ - bit_operations.c \ - bitstream.c \ - complex_filters.c \ - complex_vector_float.c \ - complex_vector_int.c \ - crc.c \ - data_modems.c \ - dds_float.c \ - dds_int.c \ - dtmf.c \ - echo.c \ - fax.c \ - fax_modems.c \ - fsk.c \ - g711.c \ - g722.c \ - g726.c \ - gsm0610_decode.c \ - gsm0610_encode.c \ - gsm0610_long_term.c \ - gsm0610_lpc.c \ - gsm0610_preprocess.c \ - gsm0610_rpe.c \ - gsm0610_short_term.c \ - hdlc.c \ - ima_adpcm.c \ - image_translate.c \ - logging.c \ - lpc10_analyse.c \ - lpc10_decode.c \ - lpc10_encode.c \ - lpc10_placev.c \ - lpc10_voicing.c \ - math_fixed.c \ - modem_echo.c \ - modem_connect_tones.c \ - noise.c \ - oki_adpcm.c \ - playout.c \ - plc.c \ - power_meter.c \ - queue.c \ - schedule.c \ - sig_tone.c \ - silence_gen.c \ - super_tone_rx.c \ - super_tone_tx.c \ - swept_tone.c \ - t30.c \ - t30_api.c \ - t30_logging.c \ - t31.c \ - t35.c \ - t38_core.c \ - t38_gateway.c \ - t38_non_ecm_buffer.c \ - t38_terminal.c \ - t4_t6_decode.c \ - t4_t6_encode.c \ - t4_rx.c \ - t4_tx.c \ - t42.c \ - t43.c \ - t81_t82_arith_coding.c \ - t85_decode.c \ - t85_encode.c \ - testcpuid.c \ - time_scale.c \ - timezone.c \ - tone_detect.c \ - tone_generate.c \ - v17rx.c \ - v17tx.c \ - v18.c \ - v22bis_rx.c \ - v22bis_tx.c \ - v27ter_rx.c \ - v27ter_tx.c \ - v29rx.c \ - v29tx.c \ - v42.c \ - v42bis.c \ - v8.c \ - vector_float.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 \ - spandsp/awgn.h \ - spandsp/bell_r2_mf.h \ - spandsp/bert.h \ - spandsp/biquad.h \ - spandsp/bit_operations.h \ - spandsp/bitstream.h \ - spandsp/crc.h \ - spandsp/complex.h \ - spandsp/complex_filters.h \ - spandsp/complex_vector_float.h \ - spandsp/complex_vector_int.h \ - spandsp/data_modems.h \ - spandsp/dc_restore.h \ - spandsp/dds.h \ - spandsp/dtmf.h \ - spandsp/echo.h \ - spandsp/fast_convert.h \ - spandsp/fax.h \ - spandsp/fax_modems.h \ - spandsp/fir.h \ - spandsp/fsk.h \ - spandsp/g168models.h \ - spandsp/g711.h \ - spandsp/g722.h \ - spandsp/g726.h \ - spandsp/gsm0610.h \ - spandsp/hdlc.h \ - spandsp/ima_adpcm.h \ - spandsp/image_translate.h \ - spandsp/logging.h \ - spandsp/lpc10.h \ - spandsp/math_fixed.h \ - spandsp/modem_echo.h \ - spandsp/modem_connect_tones.h \ - spandsp/noise.h \ - spandsp/oki_adpcm.h \ - spandsp/playout.h \ - spandsp/plc.h \ - spandsp/power_meter.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 \ - spandsp/super_tone_tx.h \ - spandsp/swept_tone.h \ - spandsp/t30.h \ - spandsp/t30_api.h \ - spandsp/t30_fcf.h \ - spandsp/t30_logging.h \ - spandsp/t31.h \ - spandsp/t35.h \ - spandsp/t38_core.h \ - spandsp/t38_gateway.h \ - spandsp/t38_non_ecm_buffer.h \ - spandsp/t38_terminal.h \ - spandsp/t4_rx.h \ - spandsp/t4_tx.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 \ - spandsp/time_scale.h \ - spandsp/timezone.h \ - spandsp/timing.h \ - spandsp/tone_detect.h \ - spandsp/tone_generate.h \ - spandsp/v17rx.h \ - spandsp/v17tx.h \ - spandsp/v18.h \ - spandsp/v22bis.h \ - spandsp/v27ter_rx.h \ - spandsp/v27ter_tx.h \ - spandsp/v29rx.h \ - spandsp/v29tx.h \ - spandsp/v42.h \ - spandsp/v42bis.h \ - spandsp/v8.h \ - spandsp/vector_float.h \ - spandsp/vector_int.h \ - spandsp/version.h \ - spandsp/private/ademco_contactid.h \ - spandsp/private/adsi.h \ - spandsp/private/async.h \ - spandsp/private/at_interpreter.h \ - spandsp/private/awgn.h \ - spandsp/private/bell_r2_mf.h \ - spandsp/private/bert.h \ - spandsp/private/bitstream.h \ - spandsp/private/data_modems.h \ - spandsp/private/dtmf.h \ - spandsp/private/echo.h \ - spandsp/private/fax.h \ - spandsp/private/fax_modems.h \ - spandsp/private/fsk.h \ - spandsp/private/g711.h \ - spandsp/private/g722.h \ - spandsp/private/g726.h \ - spandsp/private/gsm0610.h \ - spandsp/private/hdlc.h \ - spandsp/private/ima_adpcm.h \ - spandsp/private/image_translate.h \ - spandsp/private/logging.h \ - spandsp/private/lpc10.h \ - spandsp/private/modem_connect_tones.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 \ - spandsp/private/silence_gen.h \ - spandsp/private/super_tone_rx.h \ - spandsp/private/super_tone_tx.h \ - spandsp/private/swept_tone.h \ - spandsp/private/t30.h \ - spandsp/private/t30_dis_dtc_dcs_bits.h \ - spandsp/private/t31.h \ - spandsp/private/t38_core.h \ - spandsp/private/t38_gateway.h \ - spandsp/private/t38_non_ecm_buffer.h \ - spandsp/private/t38_terminal.h \ - spandsp/private/t4_rx.h \ - spandsp/private/t4_tx.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 \ - spandsp/private/timezone.h \ - spandsp/private/tone_detect.h \ - spandsp/private/tone_generate.h \ - spandsp/private/v17rx.h \ - spandsp/private/v17tx.h \ - spandsp/private/v18.h \ - spandsp/private/v22bis.h \ - spandsp/private/v27ter_rx.h \ - spandsp/private/v27ter_tx.h \ - spandsp/private/v29rx.h \ - spandsp/private/v29tx.h \ - spandsp/private/v42.h \ - spandsp/private/v42bis.h \ - spandsp/private/v8.h \ - spandsp/expose.h - -nodist_include_HEADERS = spandsp.h - -noinst_HEADERS = cielab_luts.h \ - faxfont.h \ - filter_tools.h \ - gsm0610_local.h \ - lpc10_encdecs.h \ - mmx_sse_decs.h \ - t30_local.h \ - t4_t6_decode_states.h \ - t42_t43_local.h \ - v17_v32bis_rx_constellation_maps.h \ - v17_v32bis_tx_constellation_maps.h \ - v29tx_constellation_maps.h - -make_at_dictionary$(EXEEXT): $(top_srcdir)/src/make_at_dictionary.c - $(CC_FOR_BUILD) -o make_at_dictionary$(EXEEXT) $(top_srcdir)/src/make_at_dictionary.c -DHAVE_CONFIG_H -I$(top_builddir)/src - -make_cielab_luts$(EXEEXT): $(top_srcdir)/src/make_cielab_luts.c - $(CC_FOR_BUILD) -o make_cielab_luts$(EXEEXT) $(top_srcdir)/src/make_cielab_luts.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm - -make_math_fixed_tables$(EXEEXT): $(top_srcdir)/src/make_math_fixed_tables.c - $(CC_FOR_BUILD) -o make_math_fixed_tables$(EXEEXT) $(top_srcdir)/src/make_math_fixed_tables.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm - -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 - -at_interpreter.$(OBJEXT): at_interpreter_dictionary.h - -at_interpreter.lo: at_interpreter_dictionary.h - -at_interpreter_dictionary.h: make_at_dictionary$(EXEEXT) - ./make_at_dictionary$(EXEEXT) >at_interpreter_dictionary.h - -math_fixed.$(OBJEXT): math_fixed_tables.h - -math_fixed.lo: math_fixed_tables.h - -math_fixed_tables.h: make_math_fixed_tables$(EXEEXT) - ./make_math_fixed_tables$(EXEEXT) >math_fixed_tables.h - -t4_rx.$(OBJEXT): spandsp/version.h - -t4_rx.lo: spandsp/version.h - -t42.$(OBJEXT): cielab_luts.h - -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} - -v17rx.lo: ${V17_V32BIS_RX_INCL} - -v17_v32bis_rx_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.17 -r >v17_v32bis_rx_rrc.h - -V17_V32BIS_TX_INCL = v17_v32bis_tx_rrc.h - -v17tx.$(OBJEXT): ${V17_V32BIS_TX_INCL} - -v17tx.lo: ${V17_V32BIS_TX_INCL} - -v17_v32bis_tx_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.17 -t >v17_v32bis_tx_rrc.h - -V22BIS_RX_INCL = v22bis_rx_1200_rrc.h \ - v22bis_rx_2400_rrc.h - -v22bis_rx.$(OBJEXT): ${V22BIS_RX_INCL} - -v22bis_rx.lo: ${V22BIS_RX_INCL} - -v22bis_rx_1200_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.22bis1200 -r >v22bis_rx_1200_rrc.h - -v22bis_rx_2400_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.22bis2400 -r >v22bis_rx_2400_rrc.h - -V22BIS_TX_INCL = v22bis_tx_rrc.h - -v22bis_tx.$(OBJEXT): ${V22BIS_TX_INCL} - -v22bis_tx.lo: ${V22BIS_TX_INCL} - -v22bis_tx_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.22bis -t >v22bis_tx_rrc.h - -V27_RX_INCL = v27ter_rx_2400_rrc.h \ - v27ter_rx_4800_rrc.h - -v27ter_rx.$(OBJEXT): ${V27_RX_INCL} - -v27ter_rx.lo: ${V27_RX_INCL} - -v27ter_rx_2400_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.27ter2400 -r >v27ter_rx_2400_rrc.h - -v27ter_rx_4800_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.27ter4800 -r >v27ter_rx_4800_rrc.h - -V27TER_TX_INCL = v27ter_tx_2400_rrc.h \ - v27ter_tx_4800_rrc.h - -v27ter_tx_.$(OBJEXT): ${V27TER_TX_INCL} - -v27ter_tx.lo: ${V27TER_TX_INCL} - -v27ter_tx_2400_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.27ter2400 -t >v27ter_tx_2400_rrc.h - -v27ter_tx_4800_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.27ter4800 -t >v27ter_tx_4800_rrc.h - -V29_RX_INCL = v29rx_rrc.h - -v29rx.$(OBJEXT): ${V29_RX_INCL} - -v29rx.lo: ${V29_RX_INCL} - -v29rx_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.29 -r >v29rx_rrc.h - -V29_TX_INCL = v29tx_rrc.h - -v29tx.$(OBJEXT): ${V29_TX_INCL} - -v29tx.lo: ${V29_TX_INCL} - -v29tx_rrc.h: make_modem_filter$(EXEEXT) - ./make_modem_filter$(EXEEXT) -m V.29 -t >v29tx_rrc.h - -VCPROJ8 = libspandsp.2005.vcproj -VCPROJ9 = libspandsp.2008.vcproj -VCPROJ10 = libspandsp.2010.vcproj -VCPROJ12 = libspandsp.2012.vcxproj - -WIN32SOURCES = $(libspandsp_la_SOURCES) .\\msvc\\gettimeofday.c -WIN32HEADERS = $(nobase_include_HEADERS) spandsp.h - -VCPROJOUT8 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ8) -VCPROJOUT9 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ9) -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)" - @(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ8); \ - for file in $(WIN32SOURCES); do \ - echo "" $(VCPROJOUT8); \ - done; \ - echo "" $(VCPROJOUT8); \ - for file in $(WIN32HEADERS); do \ - echo "" $(VCPROJOUT8); \ - done; \ - cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT8) ) - -$(VCPROJ9): msvc/vc9proj.head msvc/vc9proj.foot Makefile.am - echo "creating $(VCPROJ9)" - @(cp $(srcdir)/msvc/vc9proj.head $(VCPROJ9); \ - for file in $(WIN32SOURCES); do \ - echo "" $(VCPROJOUT9); \ - done; \ - echo "" $(VCPROJOUT9); \ - for file in $(WIN32HEADERS); do \ - echo "" $(VCPROJOUT9); \ - 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)/" \ - -e "s/\@SPANDSP_USE_FIXED_POINT\@/#undef SPANDSP_USE_FIXED_POINT/" \ - -e "s/\@SPANDSP_MISALIGNED_ACCESS_FAILS\@/#undef SPANDSP_MISALIGNED_ACCESS_FAILS/" \ - -e "s/\@SPANDSP_USE_EXPORT_CAPABILITY\@/#define SPANDSP_USE_EXPORT_CAPABILITY 1/" \ - -e "s/\@INSERT_INTTYPES_HEADER\@/#include /" \ - -e "s/\@INSERT_MATH_HEADER\@/#include /" $(srcdir)/spandsp.h.in > $(srcdir)/msvc/spandsp.h - -dist-hook: spandsp/version.h - -spandsp/version.h: - mkdir -p $(@D) - NOWDATE=`date --utc +"%Y%m%d"` ; \ - NOWTIME=`date --utc +"%H%M%S"` ; \ - sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \ - <$(srcdir)/spandsp/version.h.in >$@ diff --git a/libs/spandsp/src/ademco_contactid.c b/libs/spandsp/src/ademco_contactid.c deleted file mode 100644 index d26fab4a2c..0000000000 --- a/libs/spandsp/src/ademco_contactid.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * ademco_contactid.c - Ademco ContactID alarm protocol - * - * 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 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 "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/queue.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" -#include "spandsp/power_meter.h" -#include "spandsp/async.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/dtmf.h" -#include "spandsp/ademco_contactid.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/queue.h" -#include "spandsp/private/tone_detect.h" -#include "spandsp/private/tone_generate.h" -#include "spandsp/private/dtmf.h" -#include "spandsp/private/ademco_contactid.h" - -/* -Ademco ContactID Protocol - -Answer -Wait 0.5s to 2s for the line to settle -Send 1400Hz for 100ms -Send silence for 100ms -Send 2300Hz for 100ms -Receiver now waits - -(both timing and frequency errors specified as 3%, but sender side should accept these tones with 5% frequency error.) - -Sender waits 250-300ms after end of 2300Hz tone - -Send ACCT MT QXYZ GG CCC S - -ACCT = 4 digit account code (0-9, B-F) -MT = 2 digit message type (18 preferred, 98 optional) -Q = 1 digit event qualifier. 1 = New event or opening. 3 = New restore or closing. 6 = Previous condition still present -XYZ = 3 digit event code (0-9, B-F) -GG = 2 digit group or partition number (0-9, B-F). 00=no specific group -CCC = 3 digit zone number (event reports) or user number (open/close reports). 000=no specific zone or user information -S = 1 digit hex checksum (sum all message digits + S) mod 15 == 0 - -DTMF tones are 50-60ms on 50-60ms off - -0 10 (counted as 10 in checksum calculations) -1 1 -2 2 -3 3 -4 4 -5 5 -6 6 -7 7 -8 8 -9 9 -B (*) 11 -C (#) 12 -D (A) 13 -E (B) 14 -F (C) 15 - -DTMF D is not used - -Wait 1.25s for a kiss-off tone -Detect at least 400ms of kissoff to be valid, then wait for end of tone - -Wait 250-300ms before sending the next DTMF message - -If kissoff doesn't start within 1.25s of the end of the DTMF, repeat the DTMF message - -Receiver sends 750-1000ms of 1400Hz as the kissoff tone - -Sender shall make 4 attempts before giving up. One successful kissoff resets the attempt counter - - -Ademco Express 4/1 - - ACCT MT C - -ACCT = 4 digit account code (0-9, B-F) -MT = 2 digit message type (17) -C = alarm code -S = 1 digit hex checksum - -Ademco Express 4/2 - - ACCT MT C Z S - -ACCT = 4 digit account code (0-9, B-F) -MT = 2 digit message type (27) -C = 1 digit alarm code -Z = 1 digit zone or user number -S = 1 digit hex checksum - -Ademco High speed - - ACCT MT PPPPPPPP X S - -ACCT = 4 digit account code (0-9, B-F) -MT = 2 digit message type (55) -PPPPPPPP = 8 digit status of each zone -X = 1 digit type of information in the PPPPPPPP field -S = 1 digit hex checksum - -Each P digit contains one of the following values: - 1 new alarm - 2 new opening - 3 new restore - 4 new closing - 5 normal - 6 outstanding -The X field contains one of the following values: - 0 AlarmNet messages - 1 ambush or duress - 2 opening by user (the first P field contains the user number) - 3 bypass (the P fields indicate which zones are bypassed) - 4 closing by user (the first P field contain the user number) - 5 trouble (the P fields contain which zones are in trouble) - 6 system trouble - 7 normal message (the P fields indicate zone status) - 8 low battery (the P fields indicate zone status) - 9 test (the P fields indicate zone status) - -Ademco Super fast - - ACCT MT PPPPPPPP X S - -ACCT = 4 digit account code (0-9, B-F) -MT = 2 digit message type (56) - -There are versions somewhat like the above, with 8, 16 or 24 'P' digits, -and no message type - ACCT PPPPPPPP X - ACCT PPPPPPPPPPPPPPPP X - ACCT PPPPPPPPPPPPPPPPPPPPPPPP X - -ACCT = 4 digit account code (0-9, B-F) -PPPPPPPP = 8, 16 or 24 digit status of each zone -X = 1 digit status of the communicator -S = 1 digit hex checksum - -*/ - -struct ademco_code_s -{ - int code; - const char *name; - int data_type; -}; - -static const struct ademco_code_s ademco_codes[] = -{ - {0x100, "Medical", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x101, "Personal emergency", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x102, "Fail to report in", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x110, "Fire", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x111, "Smoke", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x112, "Combustion", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x113, "Water flow", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x114, "Heat", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x115, "Pull station", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x116, "Duct", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x117, "Flame", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x118, "Near alarm", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x120, "Panic", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x121, "Duress", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x122, "Silent", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x123, "Audible", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x124, "Duress - Access granted", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x125, "Duress - Egress granted", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x130, "Burglary", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x131, "Perimeter", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x132, "Interior", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x133, "24 hour (safe)", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x134, "Entry/Exit", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x135, "Day/Night", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x136, "Outdoor", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x137, "Tamper", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x138, "Near alarm", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x139, "Intrusion verifier", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x140, "General alarm", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x141, "Polling loop open", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x142, "Polling loop short", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x143, "Expansion module failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x144, "Sensor tamper", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x145, "Expansion module tamper", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x146, "Silent burglary", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x147, "Sensor supervision failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x150, "24 hour non-burglary", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x151, "Gas detected", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x152, "Refrigeration", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x153, "Loss of heat", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x154, "Water leakage", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x155, "Foil break", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x156, "Day trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x157, "Low bottled gas level", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x158, "High temp", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x159, "Low temp", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x161, "Loss of air flow", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x162, "Carbon monoxide detected", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x163, "Tank level", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x200, "Fire supervisory", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x201, "Low water pressure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x202, "Low CO2", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x203, "Gate valve sensor", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x204, "Low water level", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x205, "Pump activated", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x206, "Pump failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x300, "System trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x301, "AC loss", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x302, "Low system battery", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x303, "RAM checksum bad", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x304, "ROM checksum bad", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x305, "System reset", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x306, "Panel programming changed", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x307, "Self-test failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x308, "System shutdown", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x309, "Battery test failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x310, "Ground fault", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x311, "Battery missing/dead", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x312, "Power supply overcurrent", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x313, "Engineer reset", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x320, "Sounder/relay", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x321, "Bell 1", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x322, "Bell 2", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x323, "Alarm relay", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x324, "Trouble relay", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x325, "Reversing relay", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x326, "Notification appliance ckt. #3", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x327, "Notification appliance ckt. #4", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x330, "System peripheral trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x331, "Polling loop open", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x332, "Polling loop short", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x333, "Expansion module failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x334, "Repeater failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x335, "Local printer out of paper", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x336, "Local printer failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x337, "Exp. module DC loss", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x338, "Exp. module low battery", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x339, "Exp. module reset", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x341, "Exp. module tamper", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x342, "Exp. module AC loss", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x343, "Exp. module self-test fail", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x344, "RF receiver jam detect", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x350, "Communication trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x351, "Telco 1 fault", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x352, "Telco 2 fault", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x353, "Long range radio transmitter fault", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x354, "Failure to communicate event", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x355, "Loss of radio supervision", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x356, "Loss of central polling", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x357, "Long range radio VSWR problem", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x370, "Protection loop", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x371, "Protection loop open", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x372, "Protection loop short", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x373, "Fire trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x374, "Exit error alarm (zone)", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x375, "Panic zone trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x376, "Hold-up zone trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x377, "Swinger trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x378, "Cross-zone trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x380, "Sensor trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x381, "Loss of supervision - RF", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x382, "Loss of supervision - RPM", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x383, "Sensor tamper", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x384, "RF low battery", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x385, "Smoke detector high sensitivity", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x386, "Smoke detector low sensitivity", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x387, "Intrusion detector high sensitivity", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x388, "Intrusion detector low sensitivity", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x389, "Sensor self-test failure", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x391, "Sensor Watch trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x392, "Drift compensation error", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x393, "Maintenance alert", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x400, "Open/Close", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x401, "O/C by user", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x402, "Group O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x403, "Automatic O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x404, "Late to O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x405, "Deferred O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x406, "Cancel", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x407, "Remote arm/disarm", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x408, "Quick arm", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x409, "Keyswitch O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x441, "Armed STAY", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x442, "Keyswitch Armed STAY", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x450, "Exception O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x451, "Early O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x452, "Late O/C", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x453, "Failed to open", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x454, "Failed to close", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x455, "Auto-arm failed", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x456, "Partial arm", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x457, "Exit error (user)", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x458, "User on Premises", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x459, "Recent close", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x461, "Wrong code entry", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x462, "Legal code entry", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x463, "Re-arm after alarm", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x464, "Auto-arm time extended", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x465, "Panic alarm reset", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x466, "Service on/off premises", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x411, "Callback request made", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x412, "Successful download/access", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x413, "Unsuccessful access", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x414, "System shutdown command received", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x415, "Dialer shutdown command received", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x416, "Successful Upload", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x421, "Access denied", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x422, "Access report by user", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x423, "Forced Access", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x424, "Egress Denied", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x425, "Egress Granted", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x426, "Access Door propped open", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x427, "Access point door status monitor trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x428, "Access point request to exit trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x429, "Access program mode entry", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x430, "Access program mode exit", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x431, "Access threat level change", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x432, "Access relay/trigger fail", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x433, "Access RTE shunt", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x434, "Access DSM shunt", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x501, "Access reader disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x520, "Sounder/Relay disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x521, "Bell 1 disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x522, "Bell 2 disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x523, "Alarm relay disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x524, "Trouble relay disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x525, "Reversing relay disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x526, "Notification appliance ckt. #3 disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x527, "Notification appliance ckt. #4 disable", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x531, "Module added", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x532, "Module removed", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x551, "Dialer disabled", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x552, "Radio transmitter disabled", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x553, "Remote upload/download disabled", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x570, "Zone/Sensor bypass", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x571, "Fire bypass", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x572, "24 hour zone bypass", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x573, "Burg. bypass", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x574, "Group bypass", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x575, "Swinger bypass", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x576, "Access zone shunt", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x577, "Access point bypass", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x601, "Manual trigger test report", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x602, "Periodic test report", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x603, "Periodic RF transmission", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x604, "Fire test", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x605, "Status report to follow", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x606, "Listen-in to follow", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x607, "Walk test mode", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x608, "Periodic test - system trouble present", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x609, "Video transmitter active", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x611, "Point tested OK", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x612, "Point not tested", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x613, "Intrusion zone walk tested", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x614, "Fire zone walk tested", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x615, "Panic zone walk tested", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x616, "Service request", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x621, "Event log reset", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x622, "Event log 50% full", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x623, "Event log 90% full", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x624, "Event log overflow", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x625, "Time/Date reset", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x626, "Time/Date inaccurate", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x627, "Program mode entry", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x628, "Program mode exit", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x629, "32 hour event log marker", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x630, "Schedule change", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x631, "Exception schedule change", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x632, "Access schedule change", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x641, "Senior watch trouble", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x642, "Latch-key supervision", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x651, "Reserved for Ademco use", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x652, "Reserved for Ademco use", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x653, "Reserved for Ademco use", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x654, "System inactivity", ADEMCO_CONTACTID_DATA_IS_ZONE}, - {0x900, "Download abort", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x901, "Download start/end", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x902, "Download interrupted", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x910, "Auto-close with bypass", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x911, "Bypass closing", ADEMCO_CONTACTID_DATA_IS_USER}, - {0x999, "32 hour no read of event log", ADEMCO_CONTACTID_DATA_IS_USER}, - {-1, "???"} -}; - -#define GOERTZEL_SAMPLES_PER_BLOCK 55 /* We need to detect over a +-5% range */ - -#if defined(SPANDSP_USE_FIXED_POINT) -#define DETECTION_THRESHOLD 3035 /* -42dBm0 */ -#define TONE_TO_TOTAL_ENERGY 45.2233f /* -0.85dB */ -#else -#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; - -SPAN_DECLARE(int) encode_msg(char buf[], const ademco_contactid_report_t *report) -{ - char *s; - int sum; - int x; - static const char remap[] = {'D', '*', '#', 'A', 'B', 'C'}; - - sprintf(buf, "%04X%02X%1X%03X%02X%03X", report->acct, report->mt, report->q, report->xyz, report->gg, report->ccc); - for (sum = 0, s = buf; *s; s++) - { - if (*s == 'A') - return -1; - if (*s > '9') - { - x = *s - ('A' - 10); - /* Remap the Ademco B-F digits to normal DTMF *#ABC digits */ - *s = remap[x - 10]; - } - else - { - x = *s - '0'; - if (x == 0) - x = 10; - } - sum += x; - } - sum = ((sum + 15)/15)*15 - sum; - if (sum == 0) - sum = 'C'; - else if (sum <= 9) - sum += '0'; - else - sum = remap[sum - 10]; - *s++ = sum; - *s = '\0'; - return s - buf; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) decode_msg(ademco_contactid_report_t *report, const char buf[]) -{ - const char *s; - char *t; - int sum; - int x; - char buf2[20]; - - /* We need to remap normal DTMF (0-9, *, #, A-D) to Ademco's pseudo-hex (0-9, B-F, nothing for A) - and calculate the checksum */ - for (sum = 0, s = buf, t = buf2; *s; s++, t++) - { - x = *s; - switch (x) - { - case '*': - x = 'B'; - break; - case '#': - x = 'C'; - break; - case 'A': - x = 'D'; - break; - case 'B': - x = 'E'; - break; - case 'C': - x = 'F'; - break; - case 'D': - /* This should not happen in the Ademco protocol */ - x = 'A'; - break; - default: - x = *s; - break; - } - *t = x; - if (x > '9') - { - x -= ('B' - 11); - } - else - { - if (x == '0') - x = 10; - else - x -= '0'; - } - sum += x; - } - *t = '\0'; - if (sum%15 != 0) - return -1; - if (sscanf(buf2, "%04x%02x%1x%03x%02x%03x", &report->acct, &report->mt, &report->q, &report->xyz, &report->gg, &report->ccc) != 6) - return -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) ademco_contactid_msg_qualifier_to_str(int q) -{ - switch (q) - { - case ADEMCO_CONTACTID_QUALIFIER_NEW_EVENT: - return "New event"; - case ADEMCO_CONTACTID_QUALIFIER_NEW_RESTORE: - return "New restore"; - case ADEMCO_CONTACTID_QUALIFIER_STATUS_REPORT: - return "Status report"; - } - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) ademco_contactid_event_to_str(int xyz) -{ - int entry; - - for (entry = 0; ademco_codes[entry].code >= 0; entry++) - { - if (xyz == ademco_codes[entry].code) - return ademco_codes[entry].name; - } - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_receiver_log_msg(ademco_contactid_receiver_state_t *s, const ademco_contactid_report_t *report) -{ - const char *t; - - span_log(&s->logging, SPAN_LOG_FLOW, "Ademco Contact ID message:\n"); - span_log(&s->logging, SPAN_LOG_FLOW, " Account %X\n", report->acct); - switch (report->mt) - { - case ADEMCO_CONTACTID_MESSAGE_TYPE_18: - case ADEMCO_CONTACTID_MESSAGE_TYPE_98: - t = "Contact ID"; - break; - default: - t = "???"; - break; - } - span_log(&s->logging, SPAN_LOG_FLOW, " Message type %s (%X)\n", t, report->mt); - t = ademco_contactid_msg_qualifier_to_str(report->q); - span_log(&s->logging, SPAN_LOG_FLOW, " Qualifier %s (%X)\n", t, report->q); - t = ademco_contactid_event_to_str(report->xyz); - span_log(&s->logging, SPAN_LOG_FLOW, " Event %s (%X)\n", t, report->xyz); - span_log(&s->logging, SPAN_LOG_FLOW, " Group/partition %X\n", report->gg); - span_log(&s->logging, SPAN_LOG_FLOW, " User/Zone information %X\n", report->ccc); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_receiver_tx(ademco_contactid_receiver_state_t *s, int16_t amp[], int max_samples) -{ - int i; - int samples; - - switch (s->step) - { - case 0: - samples = (s->remaining_samples > max_samples) ? max_samples : s->remaining_samples; - vec_zeroi16(amp, samples); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "Initial silence finished\n"); - s->step++; - s->tone_phase_rate = dds_phase_rate(1400.0); - s->tone_level = dds_scaling_dbm0(-11); - s->tone_phase = 0; - s->remaining_samples = ms_to_samples(100); - return samples; - case 1: - samples = (s->remaining_samples > max_samples) ? max_samples : s->remaining_samples; - for (i = 0; i < samples; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->tone_level, 0); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "1400Hz tone finished\n"); - s->step++; - s->remaining_samples = ms_to_samples(100); - return samples; - case 2: - samples = (s->remaining_samples > max_samples) ? max_samples : s->remaining_samples; - vec_zeroi16(amp, samples); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "Second silence finished\n"); - s->step++; - s->tone_phase_rate = dds_phase_rate(2300.0); - s->tone_level = dds_scaling_dbm0(-11); - s->tone_phase = 0; - s->remaining_samples = ms_to_samples(100); - return samples; - case 3: - samples = (s->remaining_samples > max_samples) ? max_samples : s->remaining_samples; - for (i = 0; i < samples; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->tone_level, 0); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "2300Hz tone finished\n"); - s->step++; - s->remaining_samples = ms_to_samples(100); - return samples; - case 4: - /* Idle here, waiting for a response */ - return 0; - case 5: - samples = (s->remaining_samples > max_samples) ? max_samples : s->remaining_samples; - vec_zeroi16(amp, samples); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "Sending kissoff\n"); - s->step++; - s->tone_phase_rate = dds_phase_rate(1400.0); - s->tone_level = dds_scaling_dbm0(-11); - s->tone_phase = 0; - s->remaining_samples = ms_to_samples(850); - return samples; - case 6: - samples = (s->remaining_samples > max_samples) ? max_samples : s->remaining_samples; - for (i = 0; i < samples; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->tone_level, 0); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "1400Hz tone finished\n"); - s->step = 4; - s->remaining_samples = ms_to_samples(100); - return samples; - } - return max_samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_receiver_rx(ademco_contactid_receiver_state_t *s, const int16_t amp[], int samples) -{ - return dtmf_rx(&s->dtmf, amp, samples); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_receiver_fillin(ademco_contactid_receiver_state_t *s, int samples) -{ - return dtmf_rx_fillin(&s->dtmf, samples); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) ademco_contactid_receiver_get_logging_state(ademco_contactid_receiver_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -static void dtmf_digit_delivery(void *user_data, const char *digits, int len) -{ - ademco_contactid_receiver_state_t *s; - ademco_contactid_report_t report; - - s = (ademco_contactid_receiver_state_t *) user_data; - memcpy(&s->rx_digits[s->rx_digits_len], digits, len); - s->rx_digits_len += len; - if (s->rx_digits_len == 16) - { - s->rx_digits[16] = '\0'; - if (decode_msg(&report, s->rx_digits) == 0) - { - ademco_contactid_receiver_log_msg(s, &report); - if (s->callback) - s->callback(s->callback_user_data, &report); - s->step++; - } - s->rx_digits_len = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) ademco_contactid_receiver_set_realtime_callback(ademco_contactid_receiver_state_t *s, - ademco_contactid_report_func_t callback, - void *user_data) -{ - s->callback = callback; - s->callback_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(ademco_contactid_receiver_state_t *) ademco_contactid_receiver_init(ademco_contactid_receiver_state_t *s, - ademco_contactid_report_func_t callback, - void *user_data) -{ - if (s == NULL) - { - if ((s = (ademco_contactid_receiver_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"); - - dtmf_rx_init(&s->dtmf, dtmf_digit_delivery, (void *) s); - s->rx_digits_len = 0; - - s->callback = callback; - s->callback_user_data = user_data; - - s->step = 0; - s->remaining_samples = ms_to_samples(500); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_receiver_release(ademco_contactid_receiver_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_receiver_free(ademco_contactid_receiver_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_sender_tx(ademco_contactid_sender_state_t *s, int16_t amp[], int max_samples) -{ - int sample; - int samples; - - for (sample = 0; sample < max_samples; sample += samples) - { - switch (s->step) - { - case 0: - if (!s->clear_to_send) - return 0; - s->clear_to_send = false; - s->step++; - s->remaining_samples = ms_to_samples(250); - /* Fall through */ - case 1: - samples = (s->remaining_samples > (max_samples - sample)) ? (max_samples - sample) : s->remaining_samples; - vec_zeroi16(&[sample], samples); - s->remaining_samples -= samples; - if (s->remaining_samples > 0) - return samples; - span_log(&s->logging, SPAN_LOG_FLOW, "Pre-send silence finished\n"); - s->step++; - break; - case 2: - samples = dtmf_tx(&s->dtmf, &[sample], max_samples - sample); - if (samples == 0) - { - s->clear_to_send = false; - s->step = 0; - return sample; - } - break; - default: - return sample; - } - } - return sample; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_sender_rx(ademco_contactid_sender_state_t *s, const int16_t amp[], int samples) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t energy_1400; - int32_t energy_2300; - int16_t xamp; -#else - float energy_1400; - float energy_2300; - float xamp; -#endif - int sample; - int limit; - int hit; - int j; - - for (sample = 0; sample < samples; sample = limit) - { - if ((samples - sample) >= (GOERTZEL_SAMPLES_PER_BLOCK - s->current_sample)) - limit = sample + (GOERTZEL_SAMPLES_PER_BLOCK - s->current_sample); - else - limit = samples; - for (j = sample; j < limit; j++) - { - xamp = amp[j]; - xamp = goertzel_preadjust_amp(xamp); -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy += ((int32_t) xamp*xamp); -#else - s->energy += xamp*xamp; -#endif - goertzel_samplex(&s->tone_1400, xamp); - goertzel_samplex(&s->tone_2300, xamp); - } - s->current_sample += (limit - sample); - if (s->current_sample < GOERTZEL_SAMPLES_PER_BLOCK) - continue; - - energy_1400 = goertzel_result(&s->tone_1400); - energy_2300 = goertzel_result(&s->tone_2300); - hit = 0; - if (energy_1400 > DETECTION_THRESHOLD || energy_2300 > DETECTION_THRESHOLD) - { - if (energy_1400 > energy_2300) - { - if (energy_1400 > TONE_TO_TOTAL_ENERGY*s->energy) - hit = 1; - } - else - { - if (energy_2300 > TONE_TO_TOTAL_ENERGY*s->energy) - hit = 2; - } - } - if (hit != s->in_tone && hit == s->last_hit) - { - /* We have two successive indications that something has changed to a - specific new state. */ - switch (s->tone_state) - { - case 0: - if (hit == 1) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Receiving initial 1400Hz\n"); - s->in_tone = hit; - s->tone_state = 1; - s->duration = 0; - } - break; - case 1: - /* We are looking for a burst of 1400Hz which is 100ms +- 5% long */ - if (hit == 0) - { - if (s->duration < ms_to_samples(70) || s->duration > ms_to_samples(130)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad initial 1400Hz tone duration\n"); - s->tone_state = 0; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Received 1400Hz tone\n"); - s->tone_state = 2; - } - s->in_tone = hit; - s->duration = 0; - } - break; - case 2: - /* We are looking for 100ms +-5% of silence after the 1400Hz tone */ - if (s->duration < ms_to_samples(70) || s->duration > ms_to_samples(130)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad silence length\n"); - s->tone_state = 0; - s->in_tone = hit; - } - else if (hit == 2) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Received silence\n"); - s->tone_state = 3; - s->in_tone = hit; - } - else - { - s->tone_state = 0; - s->in_tone = 0; - } - s->duration = 0; - break; - case 3: - /* We are looking for a burst of 2300Hz which is 100ms +- 5% long */ - if (hit == 0) - { - if (s->duration < ms_to_samples(70) || s->duration > ms_to_samples(130)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad initial 2300Hz tone duration\n"); - s->tone_state = 0; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Received 2300Hz\n"); - if (s->callback) - 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->tries = 0; - if (s->tx_digits_len) - s->timer = ms_to_samples(3000); - } - s->in_tone = hit; - s->duration = 0; - } - break; - case 4: - if (hit == 1) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Receiving kissoff\n"); - s->tone_state = 5; - s->in_tone = hit; - s->duration = 0; - } - break; - case 5: - if (hit == 0) - { - 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); - if (++s->tries < 4) - { - dtmf_tx_put(&s->dtmf, s->tx_digits, s->tx_digits_len); - s->timer = ms_to_samples(3000); - s->tone_state = 4; - } - else - { - s->timer = 0; - if (s->callback) - 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->tx_digits_len = 0; - if (s->callback) - s->callback(s->callback_user_data, true, 0, 0); - s->tone_state = 4; - s->clear_to_send = true; - s->tries = 0; - if (s->tx_digits_len) - s->timer = ms_to_samples(3000); - } - s->in_tone = hit; - s->duration = 0; - } - break; - } - } - s->last_hit = hit; - s->duration += GOERTZEL_SAMPLES_PER_BLOCK; - if (s->timer > 0) - { - s->timer -= GOERTZEL_SAMPLES_PER_BLOCK; - if (s->timer <= 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Timer expired\n"); - if (s->tone_state == 4 && s->tx_digits_len) - { - if (++s->tries < 4) - { - dtmf_tx_put(&s->dtmf, s->tx_digits, s->tx_digits_len); - s->timer = ms_to_samples(3000); - } - else - { - s->timer = 0; - if (s->callback) - s->callback(s->callback_user_data, false, 0, 0); - } - } - } - } - s->energy = 0; - s->current_sample = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_sender_fillin(ademco_contactid_sender_state_t *s, int samples) -{ - /* Restart any Goertzel and energy gathering operation we might be in the middle of. */ - goertzel_reset(&s->tone_1400); - goertzel_reset(&s->tone_2300); -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif - s->current_sample = 0; - /* Don't update the hit detection. Pretend it never happened. */ - /* TODO: Surely we can be cleverer than this. */ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_sender_put(ademco_contactid_sender_state_t *s, const ademco_contactid_report_t *report) -{ - if (s->busy) - return -1; - if ((s->tx_digits_len = encode_msg(s->tx_digits, report)) < 0) - return -1; - s->busy = true; - return dtmf_tx_put(&s->dtmf, s->tx_digits, s->tx_digits_len); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) ademco_contactid_sender_get_logging_state(ademco_contactid_sender_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) ademco_contactid_sender_set_realtime_callback(ademco_contactid_sender_state_t *s, - tone_report_func_t callback, - void *user_data) -{ - s->callback = callback; - s->callback_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(ademco_contactid_sender_state_t *) ademco_contactid_sender_init(ademco_contactid_sender_state_t *s, - tone_report_func_t callback, - void *user_data) -{ - if (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 (!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); - s->current_sample = 0; - - s->callback = callback; - s->callback_user_data = user_data; - - s->step = 0; - s->remaining_samples = ms_to_samples(100); - dtmf_tx_init(&s->dtmf, NULL, NULL); - /* The specified timing is 50-60ms on, 50-60ms off */ - dtmf_tx_set_timing(&s->dtmf, 55, 55); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_sender_release(ademco_contactid_sender_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ademco_contactid_sender_free(ademco_contactid_sender_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/adsi.c b/libs/spandsp/src/adsi.c deleted file mode 100644 index 72d85319c1..0000000000 --- a/libs/spandsp/src/adsi.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * adsi.c - Analogue display service interfaces of various types, including - * ADSI, TDD and most caller ID formats. - * - * 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 */ - -#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 "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" -#include "spandsp/complex.h" -#include "spandsp/dds.h" -#include "spandsp/power_meter.h" -#include "spandsp/async.h" -#include "spandsp/crc.h" -#include "spandsp/fsk.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/dtmf.h" -#include "spandsp/adsi.h" - -#include "spandsp/private/logging.h" -#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" - -/*! The baudot code to shift from alpha to digits and symbols */ -#define BAUDOT_FIGURE_SHIFT 0x1B -/*! The baudot code to shift from digits and symbols to alpha */ -#define BAUDOT_LETTER_SHIFT 0x1F - -enum -{ - SOH = 0x01, - STX = 0x02, - ETX = 0x03, - DLE = 0x10, - SUB = 0x1A -}; - -static uint16_t adsi_encode_baudot(adsi_tx_state_t *s, uint8_t ch); -static uint8_t adsi_decode_baudot(adsi_rx_state_t *s, uint8_t ch); - -static int adsi_tx_get_bit(void *user_data) -{ - int bit; - adsi_tx_state_t *s; - - s = (adsi_tx_state_t *) user_data; - /* This is similar to the async. handling code in fsk.c, but a few special - things are needed in the preamble, and postamble of an ADSI message. */ - if (s->bit_no < s->preamble_len) - { - /* Alternating bit preamble */ - bit = s->bit_no & 1; - s->bit_no++; - } - else if (s->bit_no < s->preamble_len + s->preamble_ones_len) - { - /* All 1s for receiver conditioning */ - /* NB: The receiver is an async one. It needs a rest after the - alternating 1/0 sequence so it can reliably pick up on - the next start bit, and sync to the byte stream. */ - /* The length of this period varies with the circumstance */ - bit = 1; - s->bit_no++; - } - else if (s->bit_no <= s->preamble_len + s->preamble_ones_len) - { - /* Push out the 8 bit async. chars, with an appropriate number of stop bits */ - if (s->bit_pos == 0) - { - /* Start bit */ - bit = 0; - s->bit_pos++; - } - else if (s->bit_pos < 1 + 8) - { - bit = (s->msg[s->byte_no] >> (s->bit_pos - 1)) & 1; - s->bit_pos++; - } - else if (s->bit_pos < 1 + 8 + s->stop_bits - 1) - { - /* Stop bit */ - bit = 1; - s->bit_pos++; - } - else - { - /* Stop bit */ - bit = 1; - s->bit_pos = 0; - if (++s->byte_no >= s->msg_len) - s->bit_no++; - } - } - else if (s->bit_no <= s->preamble_len + s->preamble_ones_len + s->postamble_ones_len) - { - /* Extra stop bits beyond the last character, to meet the specs., and ensure - all bits are out of the DSP before we shut off the FSK modem. */ - bit = 1; - s->bit_no++; - } - else - { - bit = SIG_STATUS_END_OF_DATA; - if (s->tx_signal_on) - { - /* The FSK should now be switched off. */ - s->tx_signal_on = false; - s->msg_len = 0; - } - } - //printf("Tx bit %d\n", bit); - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static int adsi_tdd_get_async_byte(void *user_data) -{ - adsi_tx_state_t *s; - - s = (adsi_tx_state_t *) user_data; - if (s->byte_no < s->msg_len) - return s->msg[s->byte_no++]; - if (s->tx_signal_on) - { - /* The FSK should now be switched off. */ - s->tx_signal_on = false; - s->msg_len = 0; - } - return 0x1F; -} -/*- End of function --------------------------------------------------------*/ - -static void adsi_rx_put_bit(void *user_data, int bit) -{ - adsi_rx_state_t *s; - int i; - int sum; - - s = (adsi_rx_state_t *) user_data; - if (bit < 0) - { - /* Special conditions */ - span_log(&s->logging, SPAN_LOG_FLOW, "ADSI signal status is %s (%d)\n", signal_status_to_str(bit), bit); - switch (bit) - { - case SIG_STATUS_CARRIER_UP: - s->consecutive_ones = 0; - s->bit_pos = 0; - s->in_progress = 0; - s->msg_len = 0; - break; - case SIG_STATUS_CARRIER_DOWN: - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special put bit value - %d!\n", bit); - break; - } - return; - } - bit &= 1; - if (s->bit_pos == 0) - { - if (bit == 0) - { - /* Start bit */ - s->bit_pos++; - if (s->consecutive_ones > 10) - { - /* This is a line idle condition, which means we should - restart message acquisition */ - s->msg_len = 0; - } - s->consecutive_ones = 0; - } - else - { - s->consecutive_ones++; - } - } - else if (s->bit_pos <= 8) - { - s->in_progress >>= 1; - if (bit) - s->in_progress |= 0x80; - s->bit_pos++; - } - else - { - /* Stop bit */ - if (bit) - { - if (s->msg_len < 256) - { - if (s->standard == ADSI_STANDARD_JCLIP) - { - if (s->msg_len == 0) - { - /* A message should start DLE SOH, but let's just check - we are starting with a DLE for now */ - if (s->in_progress == (0x80 | DLE)) - s->msg[s->msg_len++] = (uint8_t) s->in_progress; - } - else - { - s->msg[s->msg_len++] = (uint8_t) s->in_progress; - } - if (s->msg_len >= 11 && s->msg_len == ((s->msg[6] & 0x7F) + 11)) - { - /* Test the CRC-16 */ - if (crc_itu16_calc(s->msg + 2, s->msg_len - 2, 0) == 0) - { - /* Strip off the parity bits. It doesn't seem - worthwhile actually checking the parity if a - CRC check has succeeded. */ - for (i = 0; i < s->msg_len - 2; i++) - s->msg[i] &= 0x7F; - /* Put everything, except the CRC octets */ - s->put_msg(s->user_data, s->msg, s->msg_len - 2); - } - else - { - span_log(&s->logging, SPAN_LOG_WARNING, "CRC failed\n"); - } - s->msg_len = 0; - } - } - else - { - s->msg[s->msg_len++] = (uint8_t) s->in_progress; - if (s->msg_len >= 3 && s->msg_len == (s->msg[1] + 3)) - { - /* Test the checksum */ - sum = 0; - for (i = 0; i < s->msg_len - 1; i++) - sum += s->msg[i]; - if ((-sum & 0xFF) == s->msg[i]) - s->put_msg(s->user_data, s->msg, s->msg_len - 1); - else - span_log(&s->logging, SPAN_LOG_WARNING, "Sumcheck failed\n"); - s->msg_len = 0; - } - } - } - } - else - { - s->framing_errors++; - } - s->bit_pos = 0; - s->in_progress = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void adsi_tdd_put_async_byte(void *user_data, int byte) -{ - adsi_rx_state_t *s; - uint8_t octet; - - s = (adsi_rx_state_t *) user_data; - //printf("Rx bit %x\n", bit); - if (byte < 0) - { - /* Special conditions */ - span_log(&s->logging, SPAN_LOG_FLOW, "ADSI signal status is %s (%d)\n", signal_status_to_str(byte), byte); - switch (byte) - { - case SIG_STATUS_CARRIER_UP: - s->consecutive_ones = 0; - s->bit_pos = 0; - s->in_progress = 0; - s->msg_len = 0; - break; - case SIG_STATUS_CARRIER_DOWN: - if (s->msg_len > 0) - { - /* Whatever we have to date constitutes the message */ - s->put_msg(s->user_data, s->msg, s->msg_len); - s->msg_len = 0; - } - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special put byte value - %d!\n", byte); - break; - } - return; - } - if ((octet = adsi_decode_baudot(s, (uint8_t) (byte & 0x1F)))) - s->msg[s->msg_len++] = octet; - if (s->msg_len >= 256) - { - s->put_msg(s->user_data, s->msg, s->msg_len); - s->msg_len = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void adsi_rx_dtmf(void *user_data, const char *digits, int len) -{ - adsi_rx_state_t *s; - - s = (adsi_rx_state_t *) user_data; - if (s->msg_len == 0) - { - /* Message starting. Start a 10s timeout, to make things more noise - tolerant for a detector running continuously when on hook. */ - s->in_progress = 80000; - } - /* It seems all the DTMF variants are a string of digits and letters, - terminated by a "#", or a "C". It appears these are unambiguous, and - non-conflicting. */ - for ( ; len && s->msg_len < 256; len--) - { - s->msg[s->msg_len++] = *digits; - if (*digits == '#' || *digits == 'C') - { - s->put_msg(s->user_data, s->msg, s->msg_len); - s->msg_len = 0; - } - digits++; - } -} -/*- End of function --------------------------------------------------------*/ - -static void start_tx(adsi_tx_state_t *s) -{ - switch (s->standard) - { - case ADSI_STANDARD_CLASS: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_BELL202], adsi_tx_get_bit, s); - break; - case ADSI_STANDARD_CLIP: - case ADSI_STANDARD_ACLIP: - case ADSI_STANDARD_JCLIP: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_V23CH1], adsi_tx_get_bit, s); - break; - case ADSI_STANDARD_CLIP_DTMF: - dtmf_tx_init(&s->dtmftx, NULL, NULL); - break; - case ADSI_STANDARD_TDD: - 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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_rx(adsi_rx_state_t *s, const int16_t amp[], int len) -{ - switch (s->standard) - { - case ADSI_STANDARD_CLIP_DTMF: - /* Apply a message timeout. */ - s->in_progress -= len; - if (s->in_progress <= 0) - s->msg_len = 0; - dtmf_rx(&s->dtmfrx, amp, len); - break; - default: - fsk_rx(&s->fskrx, amp, len); - break; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) adsi_rx_get_logging_state(adsi_rx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s, - int standard, - put_msg_func_t put_msg, - void *user_data) -{ - if (s == NULL) - { - if ((s = (adsi_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->put_msg = put_msg; - s->user_data = user_data; - switch (standard) - { - case ADSI_STANDARD_CLASS: - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_BELL202], FSK_FRAME_MODE_ASYNC, adsi_rx_put_bit, s); - break; - case ADSI_STANDARD_CLIP: - case ADSI_STANDARD_ACLIP: - case ADSI_STANDARD_JCLIP: - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_V23CH1], FSK_FRAME_MODE_ASYNC, adsi_rx_put_bit, s); - break; - case ADSI_STANDARD_CLIP_DTMF: - dtmf_rx_init(&s->dtmfrx, adsi_rx_dtmf, s); - break; - 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_4545], FSK_FRAME_MODE_5N1_FRAMES, adsi_tdd_put_async_byte, s); - break; - } - s->standard = standard; - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_rx_release(adsi_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_rx_free(adsi_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_tx(adsi_tx_state_t *s, int16_t amp[], int max_len) -{ - int len; - int lenx; - - len = tone_gen(&s->alert_tone_gen, amp, max_len); - if (s->tx_signal_on) - { - switch (s->standard) - { - case ADSI_STANDARD_CLIP_DTMF: - if (len < max_len) - len += dtmf_tx(&s->dtmftx, 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; - len += lenx; - } - break; - } - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) adsi_tx_send_alert_tone(adsi_tx_state_t *s) -{ - tone_gen_init(&s->alert_tone_gen, &s->alert_tone_desc); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) adsi_tx_set_preamble(adsi_tx_state_t *s, - int preamble_len, - int preamble_ones_len, - int postamble_ones_len, - int stop_bits) -{ - if (preamble_len < 0) - { - if (s->standard == ADSI_STANDARD_JCLIP) - s->preamble_len = 0; - else - s->preamble_len = 300; - } - else - { - s->preamble_len = preamble_len; - } - if (preamble_ones_len < 0) - { - if (s->standard == ADSI_STANDARD_JCLIP) - s->preamble_ones_len = 75; - else - s->preamble_ones_len = 80; - } - else - { - s->preamble_ones_len = preamble_ones_len; - } - if (postamble_ones_len < 0) - { -#if 0 - if (s->standard == ADSI_STANDARD_JCLIP) - s->postamble_ones_len = 5; - else -#endif - s->postamble_ones_len = 5; - } - else - { - s->postamble_ones_len = postamble_ones_len; - } - if (stop_bits < 0) - { - if (s->standard == ADSI_STANDARD_JCLIP) - s->stop_bits = 4; - else - s->stop_bits = 1; - } - else - { - s->stop_bits = stop_bits; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_tx_put_message(adsi_tx_state_t *s, const uint8_t *msg, int len) -{ - int i; - int j; - int k; - int byte; - int parity; - int sum; - size_t ii; - uint16_t crc_value; - - /* Don't inject a new message when a previous one is still in progress */ - if (s->msg_len > 0) - return 0; - if (!s->tx_signal_on) - { - /* We need to restart the modem */ - start_tx(s); - } - switch (s->standard) - { - case ADSI_STANDARD_CLIP_DTMF: - if (len >= 128) - return -1; - len -= (int) dtmf_tx_put(&s->dtmftx, (char *) msg, len); - break; - case ADSI_STANDARD_JCLIP: - if (len > 128 - 9) - return -1; - i = 0; - s->msg[i++] = DLE; - s->msg[i++] = SOH; - s->msg[i++] = 0x07; //header - s->msg[i++] = DLE; - s->msg[i++] = STX; - s->msg[i++] = msg[0]; - s->msg[i++] = (uint8_t) (len - 2); - /* We might need to byte stuff the overall length, but the rest of the - message should already be stuffed. */ - if (len - 2 == DLE) - s->msg[i++] = DLE; - memcpy(&s->msg[i], &msg[2], len - 2); - i += len - 2; - s->msg[i++] = DLE; - s->msg[i++] = ETX; - - /* Set the parity bits */ - for (j = 0; j < i; j++) - { - byte = s->msg[j]; - parity = 0; - for (k = 1; k <= 7; k++) - parity ^= (byte << k); - s->msg[j] = (s->msg[j] & 0x7F) | ((uint8_t) parity & 0x80); - } - - crc_value = crc_itu16_calc(s->msg + 2, i - 2, 0); - s->msg[i++] = (uint8_t) (crc_value & 0xFF); - s->msg[i++] = (uint8_t) ((crc_value >> 8) & 0xFF); - s->msg_len = i; - break; - case ADSI_STANDARD_TDD: - if (len > 255) - return -1; - memcpy(s->msg, msg, len); - s->msg_len = len; - break; - default: - if (len > 255) - return -1; - memcpy(s->msg, msg, len); - /* Force the length in case it is wrong */ - s->msg[1] = (uint8_t) (len - 2); - /* Add the sumcheck */ - sum = 0; - for (ii = 0; ii < (size_t) len; ii++) - sum += s->msg[ii]; - s->msg[len] = (uint8_t) ((-sum) & 0xFF); - s->msg_len = len + 1; - break; - } - /* Prepare the bit sequencing */ - s->byte_no = 0; - s->bit_pos = 0; - s->bit_no = 0; - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) adsi_tx_get_logging_state(adsi_tx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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 *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - tone_gen_descriptor_init(&s->alert_tone_desc, - 2130, - -13, - 2750, - -13, - 110, - 60, - 0, - 0, - false); - s->standard = standard; - adsi_tx_set_preamble(s, -1, -1, -1, -1); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - start_tx(s); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_tx_release(adsi_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_tx_free(adsi_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static uint16_t adsi_encode_baudot(adsi_tx_state_t *s, uint8_t ch) -{ - static const uint8_t conv[128] = - { - 0x00, /* NUL */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0x42, /* LF */ - 0xFF, /* */ - 0xFF, /* */ - 0x48, /* CR */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0xFF, /* */ - 0x44, /* */ - 0xFF, /* ! */ - 0xFF, /* " */ - 0x94, /* # */ - 0x89, /* $ */ - 0xFF, /* % */ - 0xFF, /* & */ - 0x85, /* ' */ - 0x8F, /* ( */ - 0x92, /* ) */ - 0x8B, /* * */ - 0x91, /* + */ - 0x8C, /* , */ - 0x83, /* - */ - 0x9C, /* . */ - 0x9D, /* / */ - 0x96, /* 0 */ - 0x97, /* 1 */ - 0x93, /* 2 */ - 0x81, /* 3 */ - 0x8A, /* 4 */ - 0x90, /* 5 */ - 0x95, /* 6 */ - 0x87, /* 7 */ - 0x86, /* 8 */ - 0x98, /* 9 */ - 0x8E, /* : */ - 0xFF, /* ; */ - 0xFF, /* < */ - 0x9E, /* = */ - 0xFF, /* > */ - 0x99, /* ? */ - 0xFF, /* @ */ - 0x03, /* A */ - 0x19, /* B */ - 0x0E, /* C */ - 0x09, /* D */ - 0x01, /* E */ - 0x0D, /* F */ - 0x1A, /* G */ - 0x14, /* H */ - 0x06, /* I */ - 0x0B, /* J */ - 0x0F, /* K */ - 0x12, /* L */ - 0x1C, /* M */ - 0x0C, /* N */ - 0x18, /* O */ - 0x16, /* P */ - 0x17, /* Q */ - 0x0A, /* R */ - 0x05, /* S */ - 0x10, /* T */ - 0x07, /* U */ - 0x1E, /* V */ - 0x13, /* W */ - 0x1D, /* X */ - 0x15, /* Y */ - 0x11, /* Z */ - 0xFF, /* [ */ - 0xFF, /* \ */ - 0xFF, /* ] */ - 0x9B, /* ^ */ - 0xFF, /* _ */ - 0xFF, /* ` */ - 0x03, /* a */ - 0x19, /* b */ - 0x0E, /* c */ - 0x09, /* d */ - 0x01, /* e */ - 0x0D, /* f */ - 0x1A, /* g */ - 0x14, /* h */ - 0x06, /* i */ - 0x0B, /* j */ - 0x0F, /* k */ - 0x12, /* l */ - 0x1C, /* m */ - 0x0C, /* n */ - 0x18, /* o */ - 0x16, /* p */ - 0x17, /* q */ - 0x0A, /* r */ - 0x05, /* s */ - 0x10, /* t */ - 0x07, /* u */ - 0x1E, /* v */ - 0x13, /* w */ - 0x1D, /* x */ - 0x15, /* y */ - 0x11, /* z */ - 0xFF, /* { */ - 0xFF, /* | */ - 0xFF, /* } */ - 0xFF, /* ~ */ - 0xFF, /* DEL */ - }; - uint16_t shift; - - ch = conv[ch]; - if (ch == 0xFF) - return 0; - if ((ch & 0x40)) - return ch & 0x1F; - if ((ch & 0x80)) - { - if (s->baudot_shift == 1) - return ch & 0x1F; - s->baudot_shift = 1; - shift = BAUDOT_FIGURE_SHIFT; - } - else - { - if (s->baudot_shift == 0) - return ch & 0x1F; - s->baudot_shift = 0; - shift = BAUDOT_LETTER_SHIFT; - } - return (shift << 5) | (ch & 0x1F); -} -/*- End of function --------------------------------------------------------*/ - -static uint8_t adsi_decode_baudot(adsi_rx_state_t *s, uint8_t ch) -{ - static const uint8_t conv[2][32] = - { - {"\000E\nA SIU\rDRJNFCKTZLWHYPQOBG^MXV^"}, - {"\0003\n- '87\r$4*,*:(5+)2#6019?*^./=^"} - }; - - switch (ch) - { - case BAUDOT_FIGURE_SHIFT: - s->baudot_shift = 1; - break; - case BAUDOT_LETTER_SHIFT: - s->baudot_shift = 0; - break; - default: - return conv[s->baudot_shift][ch]; - } - /* return 0 if we did not produce a character */ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_next_field(adsi_rx_state_t *s, const uint8_t *msg, int msg_len, int pos, uint8_t *field_type, uint8_t const **field_body, int *field_len) -{ - int i; - - /* Return -1 for no more fields. Return -2 for message structure corrupt. */ - switch (s->standard) - { - case ADSI_STANDARD_CLASS: - case ADSI_STANDARD_CLIP: - case ADSI_STANDARD_ACLIP: - if (pos >= msg_len) - return -1; - /* For MDMF type messages, these standards all use "IE" type fields - type, - length, contents - and similar headers */ - if (pos <= 0) - { - /* Return the message type */ - *field_type = msg[0]; - *field_len = 0; - *field_body = NULL; - pos = 2; - } - else - { - if ((msg[0] & 0x80)) - { - /* MDMF messages seem to always have a message type with the MSB set. Is that - guaranteed? */ - *field_type = msg[pos++]; - *field_len = msg[pos++]; - *field_body = msg + pos; - } - else - { - /* SDMF */ - *field_type = 0; - *field_len = msg_len - pos; - *field_body = msg + pos; - } - pos += *field_len; - } - if (pos > msg_len) - return -2; - break; - case ADSI_STANDARD_JCLIP: - if (pos >= msg_len - 2) - return -1; - if (pos <= 0) - { - /* Return the message type */ - pos = 5; - *field_type = msg[pos++]; - if (*field_type == DLE) - pos++; - if (msg[pos++] == DLE) - pos++; - *field_len = 0; - *field_body = NULL; - } - else - { - *field_type = msg[pos++]; - if (*field_type == DLE) - pos++; - *field_len = msg[pos++]; - if (*field_len == DLE) - pos++; - /* TODO: we assume here that the body contains no DLE's that would have been stuffed */ - *field_body = msg + pos; - pos += *field_len; - } - if (pos > msg_len - 2) - return -2; - break; - case ADSI_STANDARD_CLIP_DTMF: - if (pos > msg_len) - return -1; - if (pos <= 0) - { - pos = 1; - *field_type = msg[msg_len - 1]; - *field_len = 0; - *field_body = NULL; - } - else - { - /* Remove bias on the pos value */ - pos--; - if (msg[pos] >= '0' && msg[pos] <= '9') - *field_type = CLIP_DTMF_HASH_UNSPECIFIED; - else - *field_type = msg[pos++]; - *field_body = msg + pos; - i = pos; - while (i < msg_len && msg[i] >= '0' && msg[i] <= '9') - i++; - *field_len = i - pos; - pos = i; - /* Check if we have reached the end of message marker. */ - if (msg[pos] == '#' || msg[pos] == 'C') - pos++; - if (pos > msg_len) - return -2; - /* Bias the pos value, so we don't return 0 inappropriately */ - pos++; - } - break; - case ADSI_STANDARD_TDD: - if (pos >= msg_len) - return -1; - *field_type = 0; - *field_body = msg; - *field_len = msg_len; - pos = msg_len; - break; - } - return pos; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint8_t field_type, uint8_t const *field_body, int field_len) -{ - int i; - int x; - - switch (s->standard) - { - case ADSI_STANDARD_CLASS: - case ADSI_STANDARD_CLIP: - case ADSI_STANDARD_ACLIP: - /* These standards all use "IE" type fields - type, length, value - and similar headers */ - if (len <= 0) - { - /* Initialise a new message. The field type is actually the message type. */ - msg[0] = field_type; - msg[1] = 0; - len = 2; - } - else - { - /* Add to a message in progress. */ - if (field_type) - { - msg[len++] = field_type; - msg[len++] = (uint8_t) field_len; - if (field_len == DLE) - msg[len++] = (uint8_t) field_len; - memcpy(&msg[len], field_body, field_len); - len += field_len; - } - else - { - /* No field type or length, for restricted single message formats */ - memcpy(&msg[len], field_body, field_len); - len += field_len; - } - } - break; - case ADSI_STANDARD_JCLIP: - /* This standard uses "IE" type fields - type, length, value - but escapes DLE characters, - to prevent immitation of a control octet. */ - if (len <= 0) - { - /* Initialise a new message. The field type is actually the message type. */ - msg[0] = field_type; - msg[1] = 0; - len = 2; - } - else - { - /* Add to a message in progress. */ - msg[len++] = field_type; - if (field_type == DLE) - msg[len++] = field_type; - msg[len++] = (uint8_t) field_len; - if (field_len == DLE) - msg[len++] = (uint8_t) field_len; - for (i = 0; i < field_len; i++) - { - msg[len++] = field_body[i]; - if (field_body[i] == DLE) - msg[len++] = field_body[i]; - } - } - break; - case ADSI_STANDARD_CLIP_DTMF: - if (len <= 0) - { - /* Initialise a new message. The field type is actually the message type. */ - msg[0] = field_type; - len = 1; - } - else - { - /* Save and reuse the terminator/message type */ - x = msg[--len]; - if (field_type != CLIP_DTMF_HASH_UNSPECIFIED) - msg[len++] = field_type; - memcpy(&msg[len], field_body, field_len); - msg[len + field_len] = (uint8_t) x; - len += (field_len + 1); - } - break; - case ADSI_STANDARD_TDD: - if (len < 0) - len = 0; - for (i = 0; i < field_len; i++) - { - if ((x = adsi_encode_baudot(s, field_body[i]))) - { - if ((x & 0x3E0)) - msg[len++] = (uint8_t) ((x >> 5) & 0x1F); - msg[len++] = (uint8_t) (x & 0x1F); - } - } - break; - } - - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) adsi_standard_to_str(int standard) -{ - switch (standard) - { - case ADSI_STANDARD_CLASS: - return "CLASS"; - case ADSI_STANDARD_CLIP: - return "CLIP"; - case ADSI_STANDARD_ACLIP: - return "A-CLIP"; - case ADSI_STANDARD_JCLIP: - return "J-CLIP"; - case ADSI_STANDARD_CLIP_DTMF: - return "CLIP-DTMF"; - case ADSI_STANDARD_TDD: - return "TDD"; - } - return "???"; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/alloc.c b/libs/spandsp/src/alloc.c deleted file mode 100644 index a885a3d57f..0000000000 --- a/libs/spandsp/src/alloc.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 -#if defined(__ISO_C_VISIBLE) && __ISO_C_VISIBLE < 2011 -#undef __ISO_C_VISIBLE -#define __ISO_C_VISIBLE 2011 -#endif -#include -#if defined(HAVE_MALLOC_H) && !defined(__OpenBSD__) && !defined(__DragonFly__) -#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; - -#if defined(_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 deleted file mode 100644 index 28d44b4130..0000000000 --- a/libs/spandsp/src/async.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * async.c - Asynchronous serial bit stream encoding and decoding - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#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" - -#include "spandsp/private/async.h" - -SPAN_DECLARE(const char *) signal_status_to_str(int status) -{ - switch (status) - { - case SIG_STATUS_CARRIER_DOWN: - return "Carrier down"; - case SIG_STATUS_CARRIER_UP: - return "Carrier up"; - case SIG_STATUS_TRAINING_IN_PROGRESS: - return "Training in progress"; - case SIG_STATUS_TRAINING_SUCCEEDED: - return "Training succeeded"; - case SIG_STATUS_TRAINING_FAILED: - return "Training failed"; - case SIG_STATUS_FRAMING_OK: - return "Framing OK"; - case SIG_STATUS_END_OF_DATA: - return "End of data"; - case SIG_STATUS_ABORT: - return "Abort"; - case SIG_STATUS_BREAK: - return "Break"; - case SIG_STATUS_SHUTDOWN_COMPLETE: - return "Shutdown complete"; - case SIG_STATUS_OCTET_REPORT: - return "Octet report"; - case SIG_STATUS_POOR_SIGNAL_QUALITY: - return "Poor signal quality"; - case SIG_STATUS_MODEM_RETRAIN_OCCURRED: - return "Modem retrain occurred"; - case SIG_STATUS_LINK_CONNECTED: - return "Link connected"; - case SIG_STATUS_LINK_DISCONNECTED: - return "Link disconnected"; - case SIG_STATUS_LINK_ERROR: - return "Link error"; - case SIG_STATUS_LINK_IDLE: - return "Link idle"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) async_rx_put_bit(void *user_data, int bit) -{ - async_rx_state_t *s; - - s = (async_rx_state_t *) user_data; - if (bit < 0) - { - /* Special conditions */ - switch (bit) - { - case SIG_STATUS_CARRIER_UP: - case SIG_STATUS_CARRIER_DOWN: - case SIG_STATUS_TRAINING_IN_PROGRESS: - case SIG_STATUS_TRAINING_SUCCEEDED: - case SIG_STATUS_TRAINING_FAILED: - case SIG_STATUS_END_OF_DATA: - s->put_byte(s->user_data, bit); - s->bitpos = 0; - s->byte_in_progress = 0; - break; - default: - //printf("Eh!\n"); - break; - } - return; - } - if (s->bitpos == 0) - { - /* Search for the start bit */ - s->bitpos += (bit ^ 1); - s->parity_bit = 0; - s->byte_in_progress = 0; - } - else if (s->bitpos <= s->data_bits) - { - s->byte_in_progress = (s->byte_in_progress >> 1) | (bit << 7); - s->parity_bit ^= bit; - s->bitpos++; - } - else if (s->parity && s->bitpos == s->data_bits + 1) - { - if (s->parity == ASYNC_PARITY_ODD) - s->parity_bit ^= 1; - - if (s->parity_bit != bit) - s->parity_errors++; - s->bitpos++; - } - else - { - /* Stop bit */ - if (bit == 1) - { - /* Align the received value */ - if (s->data_bits < 8) - s->byte_in_progress = (s->byte_in_progress & 0xFF) >> (8 - s->data_bits); - s->put_byte(s->user_data, s->byte_in_progress); - s->bitpos = 0; - } - else if (s->use_v14) - { - /* This is actually the start bit for the next character, and - the stop bit has been dropped from the stream. This is the - rate adaption specified in V.14 */ - /* Align the received value */ - if (s->data_bits < 8) - s->byte_in_progress = (s->byte_in_progress & 0xFF) >> (8 - s->data_bits); - s->put_byte(s->user_data, s->byte_in_progress); - s->bitpos = 1; - s->parity_bit = 0; - s->byte_in_progress = 0; - } - else - { - s->framing_errors++; - s->bitpos = 0; - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(async_rx_state_t *) async_rx_init(async_rx_state_t *s, - int data_bits, - int parity, - int stop_bits, - bool use_v14, - put_byte_func_t put_byte, - void *user_data) -{ - if (s == NULL) - { - if ((s = (async_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - s->data_bits = data_bits; - s->parity = parity; - s->stop_bits = stop_bits; - s->use_v14 = use_v14; - - s->put_byte = put_byte; - s->user_data = user_data; - - s->byte_in_progress = 0; - s->bitpos = 0; - s->parity_bit = 0; - - s->parity_errors = 0; - s->framing_errors = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) async_rx_release(async_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) async_rx_free(async_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) async_tx_get_bit(void *user_data) -{ - async_tx_state_t *s; - int bit; - int parity_bit; - - s = (async_tx_state_t *) user_data; - if (s->bitpos == 0) - { - if (s->presend_bits > 0) - { - s->presend_bits--; - return 1; - } - if ((s->byte_in_progress = s->get_byte(s->user_data)) < 0) - { - if (s->byte_in_progress != SIG_STATUS_LINK_IDLE) - return s->byte_in_progress; - /* Idle for a bit time. If the get byte call configured a presend - time we might idle for longer. */ - return 1; - } - s->byte_in_progress &= (0xFFFF >> (16 - s->data_bits)); - if (s->parity != ASYNC_PARITY_NONE) - { - 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->bitpos++; - } - else - { - bit = s->byte_in_progress & 1; - s->byte_in_progress >>= 1; - if (++s->bitpos > s->total_bits) - s->bitpos = 0; - } - return bit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) async_tx_presend_bits(async_tx_state_t *s, int bits) -{ - s->presend_bits = bits; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(async_tx_state_t *) async_tx_init(async_tx_state_t *s, - int data_bits, - int parity, - int stop_bits, - bool use_v14, - get_byte_func_t get_byte, - void *user_data) -{ - if (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 - applies to the receive side. We are unlikely to have an application where - flow control does not exist, so V.14 stuffing is not needed. */ - s->data_bits = data_bits; - s->parity = parity; - s->total_bits = data_bits + stop_bits; - if (parity != ASYNC_PARITY_NONE) - s->total_bits++; - - s->get_byte = get_byte; - s->user_data = user_data; - - s->byte_in_progress = 0; - s->bitpos = 0; - s->presend_bits = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) async_tx_release(async_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) async_tx_free(async_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/at_interpreter.c b/libs/spandsp/src/at_interpreter.c deleted file mode 100644 index 8b95c48fa2..0000000000 --- a/libs/spandsp/src/at_interpreter.c +++ /dev/null @@ -1,5661 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * at_interpreter.c - AT command interpreter to V.251, V.252, V.253, T.31 and the 3GPP specs. - * - * Written by Steve Underwood - * - * Special thanks to Lee Howard - * for his great work debugging and polishing this code. - * - * Copyright (C) 2004, 2005, 2006 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 - -#if defined(__sun) -#define __EXTENSIONS__ -#endif - -#include -#include -#include -#include -#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" -#include "spandsp/complex.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/hdlc.h" -#include "spandsp/fsk.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/fax_modems.h" - -#include "spandsp/at_interpreter.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/at_interpreter.h" - -#define MANUFACTURER "www.soft-switch.org" -#define SERIAL_NUMBER "42" -#define GLOBAL_OBJECT_IDENTITY "42" - -enum -{ - ASCII_RESULT_CODES = 1, - NUMERIC_RESULT_CODES, - NO_RESULT_CODES -}; - -static at_profile_t profiles[3] = -{ - { -#if defined(_MSC_VER) || defined(__sunos) || defined(__solaris) || defined(__sun) - /*.echo =*/ true, - /*.verbose =*/ true, - /*.result_code_format =*/ ASCII_RESULT_CODES, - /*.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, - .result_code_format = ASCII_RESULT_CODES, - .pulse_dial = false, - .double_escape = false, - .adaptive_receive = false, - .s_regs[0] = 0, - .s_regs[3] = '\r', - .s_regs[4] = '\n', - .s_regs[5] = '\b', - .s_regs[6] = 1, - .s_regs[7] = 60, - .s_regs[8] = 5, - .s_regs[10] = 0 -#endif - } -}; - -typedef const char *(*at_cmd_service_t)(at_state_t *s, const char *cmd); - -static const char *manufacturer = MANUFACTURER; -static const char *model = PACKAGE; -static const char *revision = VERSION; - -#define ETX 0x03 -#define DLE 0x10 -#define SUB 0x1A - -static const char *at_response_codes[] = -{ - "OK", - "CONNECT", - "RING", - "NO CARRIER", - "ERROR", - "???", - "NO DIALTONE", - "BUSY", - "NO ANSWER", - "+FCERROR", - "+FRH:3" -}; - -SPAN_DECLARE(const char *) at_call_state_to_str(int state) -{ - switch (state) - { - case AT_CALL_EVENT_ALERTING: - return "Alerting"; - case AT_CALL_EVENT_CONNECTED: - return "Connected"; - case AT_CALL_EVENT_ANSWERED: - return "Answered"; - case AT_CALL_EVENT_BUSY: - return "Busy"; - case AT_CALL_EVENT_NO_DIALTONE: - return "No dialtone"; - case AT_CALL_EVENT_NO_ANSWER: - return "No answer"; - case AT_CALL_EVENT_HANGUP: - return "Hangup"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) at_modem_control_to_str(int state) -{ - switch (state) - { - case AT_MODEM_CONTROL_CALL: - return "Call"; - case AT_MODEM_CONTROL_ANSWER: - return "Answer"; - case AT_MODEM_CONTROL_HANGUP: - return "Hangup"; - case AT_MODEM_CONTROL_OFFHOOK: - return "Off hook"; - case AT_MODEM_CONTROL_ONHOOK: - return "On hook"; - case AT_MODEM_CONTROL_DTR: - return "DTR"; - case AT_MODEM_CONTROL_RTS: - return "RTS"; - case AT_MODEM_CONTROL_CTS: - return "CTS"; - case AT_MODEM_CONTROL_CAR: - return "CAR"; - case AT_MODEM_CONTROL_RNG: - return "RNG"; - case AT_MODEM_CONTROL_DSR: - return "DSR"; - case AT_MODEM_CONTROL_SETID: - return "Set ID"; - case AT_MODEM_CONTROL_RESTART: - return "Restart"; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - return "DTE timeout"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_set_at_rx_mode(at_state_t *s, int new_mode) -{ - /* The use of a DTE timeout is mode dependent. Set the timeout appropriately in - the modem. */ - switch (new_mode) - { - case AT_MODE_HDLC: - case AT_MODE_STUFFED: - at_modem_control(s, s->dte_inactivity_timeout*1000, (void *) (intptr_t) s->dte_inactivity_timeout); - break; - default: - at_modem_control(s, AT_MODEM_CONTROL_DTE_TIMEOUT, NULL); - break; - } - s->at_rx_mode = new_mode; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_put_response(at_state_t *s, const char *t) -{ - uint8_t buf[3]; - - if (!s) return; - - buf[0] = s->p.s_regs[3]; - buf[1] = s->p.s_regs[4]; - buf[2] = '\0'; - if (s->p.result_code_format == ASCII_RESULT_CODES) - s->at_tx_handler(s->at_tx_user_data, buf, 2); - s->at_tx_handler(s->at_tx_user_data, (uint8_t *) t, strlen(t)); - s->at_tx_handler(s->at_tx_user_data, buf, 2); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_put_numeric_response(at_state_t *s, int val) -{ - char buf[20]; - - snprintf(buf, sizeof(buf), "%d", val); - at_put_response(s, buf); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_put_response_code(at_state_t *s, int code) -{ - uint8_t buf[20]; - - span_log(&s->logging, SPAN_LOG_FLOW, "Sending AT response code %s\n", at_response_codes[code]); - switch (s->p.result_code_format) - { - case ASCII_RESULT_CODES: - at_put_response(s, at_response_codes[code]); - break; - case NUMERIC_RESULT_CODES: - snprintf((char *) buf, sizeof(buf), "%d%c", code, s->p.s_regs[3]); - s->at_tx_handler(s->at_tx_user_data, buf, strlen((char *) buf)); - break; - default: - /* No result codes */ - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int answer_call(at_state_t *s) -{ - if (at_modem_control(s, AT_MODEM_CONTROL_ANSWER, NULL) < 0) - return false; - /* Answering should now be in progress. No AT response should be - issued at this point. */ - s->do_hangup = false; - return true; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_call_event(at_state_t *s, int event) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Call event %d received\n", event); - switch (event) - { - case AT_CALL_EVENT_ALERTING: - at_modem_control(s, AT_MODEM_CONTROL_RNG, (void *) 1); - if (s->display_call_info && !s->call_info_displayed) - at_display_call_info(s); - at_put_response_code(s, AT_RESPONSE_CODE_RING); - if ((++s->rings_indicated) >= s->p.s_regs[0] && s->p.s_regs[0]) - { - /* The modem is set to auto-answer now */ - answer_call(s); - } - break; - case AT_CALL_EVENT_ANSWERED: - at_modem_control(s, AT_MODEM_CONTROL_RNG, (void *) 0); - if (s->fclass_mode == 0) - { - /* Normal data modem connection */ - at_set_at_rx_mode(s, AT_MODE_CONNECTED); - /* TODO: */ - } - else - { - /* FAX modem connection */ - at_set_at_rx_mode(s, AT_MODE_DELIVERY); - at_modem_control(s, AT_MODEM_CONTROL_RESTART, (void *) FAX_MODEM_CED_TONE_TX); - } - break; - case AT_CALL_EVENT_CONNECTED: - span_log(&s->logging, SPAN_LOG_FLOW, "Dial call - connected. FCLASS=%d\n", s->fclass_mode); - at_modem_control(s, AT_MODEM_CONTROL_RNG, (void *) 0); - if (s->fclass_mode == 0) - { - /* Normal data modem connection */ - at_set_at_rx_mode(s, AT_MODE_CONNECTED); - /* TODO: */ - } - else - { - if (s->command_dial) - { - at_put_response_code(s, AT_RESPONSE_CODE_OK); - at_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - } - else - { - /* FAX modem connection */ - at_set_at_rx_mode(s, AT_MODE_DELIVERY); - if (s->silent_dial) - 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; - } - } - break; - case AT_CALL_EVENT_BUSY: - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - at_put_response_code(s, AT_RESPONSE_CODE_BUSY); - break; - case AT_CALL_EVENT_NO_DIALTONE: - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - at_put_response_code(s, AT_RESPONSE_CODE_NO_DIALTONE); - break; - case AT_CALL_EVENT_NO_ANSWER: - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - at_put_response_code(s, AT_RESPONSE_CODE_NO_ANSWER); - break; - case AT_CALL_EVENT_HANGUP: - span_log(&s->logging, SPAN_LOG_FLOW, "Hangup... at_rx_mode %d\n", s->at_rx_mode); - at_modem_control(s, AT_MODEM_CONTROL_ONHOOK, NULL); - if (s->dte_is_waiting) - { - if (s->ok_is_pending) - { - at_put_response_code(s, AT_RESPONSE_CODE_OK); - s->ok_is_pending = false; - } - else - { - at_put_response_code(s, AT_RESPONSE_CODE_NO_CARRIER); - } - s->dte_is_waiting = false; - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - } - else if (s->fclass_mode && s->rx_signal_present) - { - s->rx_data[s->rx_data_bytes++] = DLE; - s->rx_data[s->rx_data_bytes++] = ETX; - s->at_tx_handler(s->at_tx_user_data, s->rx_data, s->rx_data_bytes); - s->rx_data_bytes = 0; - } - 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; - at_modem_control(s, AT_MODEM_CONTROL_RNG, (void *) 0); - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Invalid call event %d received.\n", event); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_reset_call_info(at_state_t *s) -{ - at_call_id_t *call_id; - at_call_id_t *next; - - for (call_id = s->call_id; call_id; call_id = next) - { - next = call_id->next; - span_free(call_id); - } - s->call_id = NULL; - s->rings_indicated = 0; - s->call_info_displayed = false; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_set_call_info(at_state_t *s, char const *id, char const *value) -{ - at_call_id_t *new_call_id; - at_call_id_t *call_id; - - /* 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 - have the relevant field. */ - new_call_id->id = (id) ? strdup(id) : NULL; - new_call_id->value = (value) ? strdup(value) : NULL; - new_call_id->next = NULL; - - if (call_id) - { - while (call_id->next) - call_id = call_id->next; - call_id->next = new_call_id; - } - else - { - s->call_id = new_call_id; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_display_call_info(at_state_t *s) -{ - char buf[132 + 1]; - at_call_id_t *call_id = s->call_id; - - while (call_id) - { - snprintf(buf, - sizeof(buf), - "%s=%s", - (call_id->id) ? call_id->id : "NULL", - (call_id->value) ? call_id->value : ""); - at_put_response(s, buf); - call_id = call_id->next; - } - s->call_info_displayed = true; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_num(const char **s, int max_value) -{ - int i; - - /* The spec. says no digits is valid, and should be treated as zero. */ - i = 0; - while (isdigit((int) **s)) - { - i = i*10 + ((**s) - '0'); - (*s)++; - } - if (i > max_value) - i = -1; - return i; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_hex_num(const char **s, int max_value) -{ - int i; - - /* The spec. says a hex value is always 2 digits, and the alpha digits are - upper case. */ - if (isdigit((int) **s)) - i = **s - '0'; - else if (**s >= 'A' && **s <= 'F') - i = **s - 'A'; - else - return -1; - (*s)++; - - if (isdigit((int) **s)) - i = (i << 4) | (**s - '0'); - else if (**s >= 'A' && **s <= 'F') - i = (i << 4) | (**s - 'A'); - else - return -1; - (*s)++; - if (i > max_value) - i = -1; - return i; -} -/*- End of function --------------------------------------------------------*/ - -static int match_element(const char **variant, const char *variants) -{ - int i; - size_t len; - char const *s; - char const *t; - - s = variants; - for (i = 0; *s; i++) - { - if ((t = strchr(s, ','))) - len = t - s; - else - len = strlen(s); - if (len == (int) strlen(*variant) && memcmp(*variant, s, len) == 0) - { - *variant += len; - return i; - } - s += len; - if (*s == ',') - s++; - } - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_out(at_state_t *s, const char **t, int *target, int max_value, const char *prefix, const char *def) -{ - char buf[100]; - int val; - - switch (*(*t)++) - { - case '=': - switch (**t) - { - case '?': - /* Show possible values */ - (*t)++; - snprintf(buf, sizeof(buf), "%s%s", (prefix) ? prefix : "", def); - at_put_response(s, buf); - break; - default: - /* Set value */ - if ((val = parse_num(t, max_value)) < 0) - return false; - if (target) - *target = val; - break; - } - break; - case '?': - /* Show current value */ - val = (target) ? *target : 0; - snprintf(buf, sizeof(buf), "%s%d", (prefix) ? prefix : "", val); - at_put_response(s, buf); - break; - default: - return false; - } - return true; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_2_out(at_state_t *s, const char **t, int *target1, int max_value1, int *target2, int max_value2, const char *prefix, const char *def) -{ - char buf[100]; - int val1; - int val2; - - switch (*(*t)++) - { - case '=': - switch (**t) - { - case '?': - /* Show possible values */ - (*t)++; - snprintf(buf, sizeof(buf), "%s%s", (prefix) ? prefix : "", def); - at_put_response(s, buf); - break; - default: - /* Set value */ - if ((val1 = parse_num(t, max_value1)) < 0) - return false; - if (target1) - *target1 = val1; - if (**t == ',') - { - (*t)++; - if ((val2 = parse_num(t, max_value2)) < 0) - return false; - if (target2) - *target2 = val2; - } - break; - } - break; - case '?': - /* Show current value */ - val1 = (target1) ? *target1 : 0; - val2 = (target2) ? *target2 : 0; - snprintf(buf, sizeof(buf), "%s%d,%d", (prefix) ? prefix : "", val1, val2); - at_put_response(s, buf); - break; - default: - return false; - } - return true; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_n_out(at_state_t *s, - const char **t, - int *targets[], - const int max_values[], - int entries, - const char *prefix, - const char *def) -{ - char buf[100]; - int val; - int len; - int i; - - switch (*(*t)++) - { - case '=': - switch (**t) - { - case '?': - /* Show possible values */ - (*t)++; - snprintf(buf, sizeof(buf), "%s%s", (prefix) ? prefix : "", def); - at_put_response(s, buf); - break; - default: - /* Set value */ - for (i = 0; i < entries; i++) - { - if ((val = parse_num(t, max_values[i])) < 0) - return false; - if (targets[i]) - *targets[i] = val; - if (**t != ',') - break; - (*t)++; - } - break; - } - break; - case '?': - /* Show current value */ - len = snprintf(buf, sizeof(buf), "%s", (prefix) ? prefix : ""); - for (i = 0; i < entries; i++) - { - if (i > 0) - len += snprintf(&buf[len], sizeof(buf) - len, ","); - val = (targets[i]) ? *targets[i] : 0; - len += snprintf(&buf[len], sizeof(buf) - len, "%d", val); - } - at_put_response(s, buf); - break; - default: - return false; - } - return true; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_hex_out(at_state_t *s, const char **t, int *target, int max_value, const char *prefix, const char *def) -{ - char buf[100]; - int val; - - switch (*(*t)++) - { - case '=': - switch (**t) - { - case '?': - /* Show possible values */ - (*t)++; - snprintf(buf, sizeof(buf), "%s%s", (prefix) ? prefix : "", def); - at_put_response(s, buf); - break; - default: - /* Set value */ - if ((val = parse_hex_num(t, max_value)) < 0) - return false; - if (target) - *target = val; - break; - } - break; - case '?': - /* Show current value */ - val = (target) ? *target : 0; - snprintf(buf, sizeof(buf), "%s%02X", (prefix) ? prefix : "", val); - at_put_response(s, buf); - break; - default: - return false; - } - return true; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_string_list_out(at_state_t *s, const char **t, int *target, int max_value, const char *prefix, const char *def) -{ - char buf[100]; - int val; - size_t len; - char *tmp; - - switch (*(*t)++) - { - case '=': - switch (**t) - { - case '?': - /* Show possible values */ - (*t)++; - snprintf(buf, sizeof(buf), "%s%s", (prefix) ? prefix : "", def); - at_put_response(s, buf); - break; - default: - /* Set value */ - if ((val = match_element(t, def)) < 0) - return false; - if (target) - *target = val; - break; - } - break; - case '?': - /* Show current index value from def */ - val = (target) ? *target : 0; - while (val-- && (def = strchr(def, ','))) - def++; - if (def) - { - if ((tmp = strchr(def, ','))) - len = tmp - def; - else - len = strlen(def); - snprintf(buf, sizeof(buf), "%s%.*s", (prefix) ? prefix : "", (int) len, def); - } - else - { - buf[0] = '\0'; - } - at_put_response(s, buf); - break; - default: - return false; - } - return true; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_string_out(at_state_t *s, const char **t, char **target, const char *prefix) -{ - char buf[100]; - - switch (*(*t)++) - { - case '=': - switch (**t) - { - case '?': - /* Show possible values */ - (*t)++; - snprintf(buf, sizeof(buf), "%s", (prefix) ? prefix : ""); - at_put_response(s, buf); - break; - default: - /* Set value */ - if (*target) - span_free(*target); - /* If this strdup fails, it should be harmless */ - *target = strdup(*t); - break; - } - break; - case '?': - /* Show current index value */ - at_put_response(s, (*target) ? *target : ""); - break; - default: - return false; - } - while (**t) - (*t)++; - return true; -} -/*- End of function --------------------------------------------------------*/ - -static const char *s_reg_handler(at_state_t *s, const char *t, int reg) -{ - int val; - int b; - char buf[4]; - - /* Set or get an S register */ - switch (*t++) - { - case '=': - switch (*t) - { - case '?': - t++; - snprintf(buf, sizeof(buf), "%3.3d", 0); - at_put_response(s, buf); - break; - default: - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->p.s_regs[reg] = (uint8_t) val; - break; - } - break; - case '?': - snprintf(buf, sizeof(buf), "%3.3d", s->p.s_regs[reg]); - at_put_response(s, buf); - break; - case '.': - if ((b = parse_num(&t, 7)) < 0) - return NULL; - switch (*t++) - { - case '=': - switch (*t) - { - case '?': - t++; - at_put_numeric_response(s, 0); - break; - default: - if ((val = parse_num(&t, 1)) < 0) - return NULL; - if (val) - s->p.s_regs[reg] |= (1 << b); - else - s->p.s_regs[reg] &= ~(1 << b); - break; - } - break; - case '?': - at_put_numeric_response(s, (int) ((s->p.s_regs[reg] >> b) & 1)); - break; - default: - return NULL; - } - break; - default: - return NULL; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static int process_class1_cmd(at_state_t *s, const char **t) -{ - int val; - int operation; - int direction; - int result; - const char *allowed; - - direction = (*(*t + 2) == 'T'); - operation = *(*t + 3); - /* Step past the "+Fxx" */ - *t += 4; - switch (operation) - { - case 'S': - allowed = "0-255"; - break; - case 'H': - allowed = "3"; - break; - default: - allowed = "24,48,72,73,74,96,97,98,121,122,145,146"; - break; - } - - val = -1; - if (!parse_out(s, t, &val, 255, NULL, allowed)) - return true; - if (val < 0) - { - /* It was just a query */ - 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; - - result = true; - if (s->class1_handler) - result = s->class1_handler(s->class1_user_data, direction, operation, val); - switch (result) - { - case 0: - /* Inhibit an immediate response. (These commands should not be part of a multi-command entry.) */ - *t = (const char *) -1; - return true; - case -1: - return false; - } - return true; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_dummy(at_state_t *s, const char *t) -{ - /* Dummy routine to absorb delimiting characters from a command string */ - return t + 1; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_A(at_state_t *s, const char *t) -{ - /* V.250 6.3.5 - Answer (abortable) */ - if (!answer_call(s)) - return NULL; - return (const char *) -1; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_D(at_state_t *s, const char *t) -{ - char *u; - char num[100 + 1]; - char ch; - - /* V.250 6.3.1 - Dial (abortable) */ - at_reset_call_info(s); - s->do_hangup = false; - s->silent_dial = false; - s->command_dial = false; - t += 1; - /* There are a numbers of options in a dial command string. - Many are completely irrelevant in this application. */ - u = num; - for ( ; (ch = *t); t++) - { - if (isdigit((int) ch)) - { - /* V.250 6.3.1.1 Basic digit set */ - *u++ = ch; - } - else - { - switch (ch) - { - case 'A': - case 'B': - case 'C': - case 'D': - case '*': - case '#': - /* V.250 6.3.1.1 Full DTMF repertoire */ - if (!s->p.pulse_dial) - *u++ = ch; - break; - case ' ': - case '-': - /* Ignore spaces and dashes */ - /* This is not a standards based thing. It just improves - compatibility with some other modems. */ - break; - case '+': - /* V.250 6.3.1.1 International access code */ - /* TODO: */ - break; - case ',': - /* V.250 6.3.1.2 Pause */ - /* Pass these through to the application to handle. */ - *u++ = ch; - break; - case 'T': - /* V.250 6.3.1.3 Tone dial */ - s->p.pulse_dial = false; - break; - case 'P': - /* V.250 6.3.1.4 Pulse dial */ - s->p.pulse_dial = true; - break; - case '!': - /* V.250 6.3.1.5 Hook flash, register recall */ - /* TODO: */ - break; - case 'W': - /* V.250 6.3.1.6 Wait for dial tone */ - /* TODO: */ - break; - case '@': - /* V.250 6.3.1.7 Wait for quiet answer */ - s->silent_dial = true; - break; - case 'S': - /* V.250 6.3.1.8 Invoke stored string */ - /* S= */ - /* TODO: */ - break; - case 'G': - case 'g': - /* GSM07.07 6.2 - Control the CUG supplementary service for this call */ - /* Uses index and info values set with command +CCUG. See +CCUG */ - /* TODO: */ - break; - case 'I': - case 'i': - /* GSM07.07 6.2 - Override Calling Line Identification Restriction (CLIR) */ - /* I=invocation (restrict CLI presentation), i=suppression (allow CLI presentation). See +CLIR */ - /* TODO: */ - break; - case ';': - /* V.250 6.3.1 - Dial string terminator - make voice call and remain in command mode */ - s->command_dial = true; - break; - case '>': - /* GSM07.07 6.2 - Direct dialling from phone book supplementary service subscription - default value for this call */ - /* TODO: */ - break; - default: - return NULL; - } - } - } - *u = '\0'; - if (at_modem_control(s, AT_MODEM_CONTROL_CALL, num) < 0) - return NULL; - /* Dialing should now be in progress. No AT response should be - issued at this point. */ - return (const char *) -1; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_E(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.2.4 - Command echo */ - t += 1; - if ((val = parse_num(&t, 1)) < 0) - return NULL; - s->p.echo = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_H(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.3.6 - Hook control */ - t += 1; - if ((val = parse_num(&t, 1)) < 0) - return NULL; - if (val) - { - /* Take the receiver off-hook, effectively busying-out the modem. */ - if (s->at_rx_mode != AT_MODE_ONHOOK_COMMAND && s->at_rx_mode != AT_MODE_OFFHOOK_COMMAND) - return NULL; - at_modem_control(s, AT_MODEM_CONTROL_OFFHOOK, NULL); - at_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - return t; - } - at_reset_call_info(s); - if (s->at_rx_mode != AT_MODE_ONHOOK_COMMAND && s->at_rx_mode != AT_MODE_OFFHOOK_COMMAND) - { - /* 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; - at_set_at_rx_mode(s, AT_MODE_CONNECTED); - return (const char *) -1; - } - at_modem_control(s, AT_MODEM_CONTROL_HANGUP, NULL); - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_I(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.1.3 - Request identification information */ - /* N.B. The information supplied in response to an ATIx command is very - variable. It was widely used in different ways before the AT command - set was standardised by the ITU. */ - t += 1; - switch (val = parse_num(&t, 255)) - { - case 0: - at_put_response(s, model); - break; - case 3: - at_put_response(s, manufacturer); - break; - default: - return NULL; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_L(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.3.13 - Monitor speaker loudness */ - /* Just absorb this command, as we have no speaker */ - t += 1; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->speaker_volume = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_M(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.3.14 - Monitor speaker mode */ - /* Just absorb this command, as we have no speaker */ - t += 1; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->speaker_mode = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_O(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.3.7 - Return to online data state */ - t += 1; - if ((val = parse_num(&t, 1)) < 0) - return NULL; - if (val == 0) - { - at_set_at_rx_mode(s, AT_MODE_CONNECTED); - at_put_response_code(s, AT_RESPONSE_CODE_CONNECT); - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -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; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_Q(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.2.5 - Result code suppression */ - t += 1; - if ((val = parse_num(&t, 1)) < 0) - return NULL; - switch (val) - { - case 0: - s->p.result_code_format = (s->p.verbose) ? ASCII_RESULT_CODES : NUMERIC_RESULT_CODES; - break; - case 1: - s->p.result_code_format = NO_RESULT_CODES; - break; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S0(at_state_t *s, const char *t) -{ - /* V.250 6.3.8 - Automatic answer */ - t += 2; - return s_reg_handler(s, t, 0); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S10(at_state_t *s, const char *t) -{ - /* V.250 6.3.12 - Automatic disconnect delay */ - t += 3; - return s_reg_handler(s, t, 10); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S3(at_state_t *s, const char *t) -{ - /* V.250 6.2.1 - Command line termination character */ - t += 2; - return s_reg_handler(s, t, 3); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S4(at_state_t *s, const char *t) -{ - /* V.250 6.2.2 - Response formatting character */ - t += 2; - return s_reg_handler(s, t, 4); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S5(at_state_t *s, const char *t) -{ - /* V.250 6.2.3 - Command line editing character */ - t += 2; - return s_reg_handler(s, t, 5); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S6(at_state_t *s, const char *t) -{ - /* V.250 6.3.9 - Pause before blind dialling */ - t += 2; - return s_reg_handler(s, t, 6); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S7(at_state_t *s, const char *t) -{ - /* V.250 6.3.10 - Connection completion timeout */ - t += 2; - return s_reg_handler(s, t, 7); -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_S8(at_state_t *s, const char *t) -{ - /* V.250 6.3.11 - Comma dial modifier time */ - t += 2; - return s_reg_handler(s, t, 8); -} -/*- End of function --------------------------------------------------------*/ - -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; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_V(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.2.6 - DCE response format */ - t += 1; - if ((val = parse_num(&t, 1)) < 0) - return NULL; - s->p.verbose = val; - if (s->p.result_code_format != NO_RESULT_CODES) - s->p.result_code_format = (s->p.verbose) ? ASCII_RESULT_CODES : NUMERIC_RESULT_CODES; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_X(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.2.7 - Result code selection and call progress monitoring control */ - /* 0 CONNECT result code is given upon entering online data state. - Dial tone and busy detection are disabled. - 1 CONNECT result code is given upon entering online data state. - Dial tone and busy detection are disabled. - 2 CONNECT result code is given upon entering online data state. - Dial tone detection is enabled, and busy detection is disabled. - 3 CONNECT result code is given upon entering online data state. - Dial tone detection is disabled, and busy detection is enabled. - 4 CONNECT result code is given upon entering online data state. - Dial tone and busy detection are both enabled. */ - t += 1; - if ((val = parse_num(&t, 4)) < 0) - return NULL; - s->result_code_mode = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_Z(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.1.1 - Reset to default configuration */ - t += 1; - if ((val = parse_num(&t, sizeof(profiles)/sizeof(profiles[0]) - 1)) < 0) - return NULL; - /* Just make sure we are on hook */ - at_modem_control(s, AT_MODEM_CONTROL_HANGUP, NULL); - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - s->p = profiles[val]; - at_reset_call_info(s); - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_amp_C(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.2.8 - Circuit 109 (received line signal detector) behaviour */ - /* We have no RLSD pin, so just absorb this. */ - t += 2; - if ((val = parse_num(&t, 1)) < 0) - return NULL; - s->rlsd_behaviour = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_amp_D(at_state_t *s, const char *t) -{ - int val; - - /* V.250 6.2.9 - Circuit 108 (data terminal ready) behaviour */ - t += 2; - if ((val = parse_num(&t, 2)) < 0) - return NULL; - /* TODO: We have no DTR pin, but we need this to get into online - command state. */ - s->dtr_behaviour = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_amp_F(at_state_t *s, const char *t) -{ - t += 2; - - /* V.250 6.1.2 - Set to factory-defined configuration */ - /* Just make sure we are on hook */ - at_modem_control(s, AT_MODEM_CONTROL_HANGUP, NULL); - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - s->p = profiles[0]; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8A(at_state_t *s, const char *t) -{ - /* V.251 6.3 - V.8 calling tone indication */ - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8C(at_state_t *s, const char *t) -{ - /* V.251 6.2 - V.8 answer signal indication */ - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8E(at_state_t *s, const char *t) -{ - int val; - - /* V.251 5.1 - V.8 and V.8bis operation controls */ - /* Syntax: +A8E=,,[,][,][,] */ - /* =0 Disable V.8 origination negotiation - =1 Enable DCE-controlled V.8 origination negotiation - =2 Enable DTE-controlled V.8 origination negotiation, send V.8 CI only - =3 Enable DTE-controlled V.8 origination negotiation, send 1100Hz CNG only - =4 Enable DTE-controlled V.8 origination negotiation, send 1300Hz CT only - =5 Enable DTE-controlled V.8 origination negotiation, send no tones - =6 Enable DCE-controlled V.8 origination negotiation, issue +A8x indications - =0 Disable V.8 answer negotiation - =1 Enable DCE-controlled V.8 answer negotiation - =2 Enable DTE-controlled V.8 answer negotiation, send ANSam - =3 Enable DTE-controlled V.8 answer negotiation, send no signal - =4 Disable DTE-controlled V.8 answer negotiation, send ANS - =5 Enable DCE-controlled V.8 answer negotiation, issue +A8x indications - =X..Y Set the V.8 CI signal call function to the hexadecimal octet value X..Y - =0 Disable V.8bis negotiation - =1 Enable DCE-controlled V.8bis negotiation - =2 Enable DTE-controlled V.8bis negotiation - ="" Set to alternative list of call function "option bit" - values that the answering DCE shall accept from the caller - ="" Set to alternative list of protocol "option bit" values that - the answering DCE shall accept from the caller - */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, &val, 6, "+A8E:", "(0-6),(0-5),(00-FF)")) - return NULL; - if (*t != ',') - return t; - if ((val = parse_num(&t, 5)) < 0) - return NULL; - if (*t != ',') - return t; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8I(at_state_t *s, const char *t) -{ - /* V.251 6.1 - V.8 CI signal indication */ - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8J(at_state_t *s, const char *t) -{ - /* V.251 6.4 - V.8 negotiation complete */ - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8M(at_state_t *s, const char *t) -{ - /* V.251 5.2 - Send V.8 menu signals */ - /* Syntax: +A8M= */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8R(at_state_t *s, const char *t) -{ - /* V.251 6.6 - V.8bis signal and message reporting */ - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_A8T(at_state_t *s, const char *t) -{ - int val; - - /* V.251 5.3 - Send V.8bis signal and/or message(s) */ - /* Syntax: +A8T=[,<1st message>][,<2nd message>][,][,][,] */ - /* =0 None - =1 Initiating Mre - =2 Initiating MRd - =3 Initiating CRe, low power - =4 Initiating CRe, high power - =5 Initiating CRd - =6 Initiating Esi - =7 Responding MRd, low power - =8 Responding MRd, high power - =9 Responding CRd - =10 Responding Esr - */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, &val, 10, "+A8T:", "(0-10)")) - return NULL; - s->v8bis_signal = val; - if (*t != ',') - return t; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->v8bis_1st_message = val; - if (*t != ',') - return t; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->v8bis_2nd_message = val; - if (*t != ',') - return t; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->v8bis_sig_en = val; - if (*t != ',') - return t; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->v8bis_msg_en = val; - if (*t != ',') - return t; - if ((val = parse_num(&t, 255)) < 0) - return NULL; - s->v8bis_supp_delay = val; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ASTO(at_state_t *s, const char *t) -{ - /* V.250 6.3.15 - Store telephone number */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+ASTO:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAAP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.25 - Automatic answer for eMLPP Service */ - /* TODO: */ - t += 5; - if (!parse_2_out(s, &t, NULL, 65535, NULL, 65535, "+CAAP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CACM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.25 - Accumulated call meter */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CACM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CACSP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.7 - Voice Group or Voice Broadcast Call State Attribute Presentation */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CACSP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAD(at_state_t *s, const char *t) -{ - /* IS-99 5.6.3 - Query analogue or digital service */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAEMLPP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.22 - eMLPP Priority Registration and Interrogation */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CAEMLPP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAHLD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.3 - Leave an ongoing Voice Group or Voice Broadcast Call */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CAHLD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAJOIN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.1 - Accept an incoming Voice Group or Voice Broadcast Call */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CAJOIN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CALA(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.16 - Alarm */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CALA:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CALCC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.6 - List current Voice Group and Voice Broadcast Calls */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CALCC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CALD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.38 - Delete alarm */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CALD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CALM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.20 - Alert sound mode */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CALM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAMM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.26 - Accumulated call meter maximum */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CAMM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CANCHEV(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.8 - NCH Support Indication */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CANCHEV:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAOC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.16 - Advice of Charge */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CAOC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAPD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.39 - Postpone or dismiss an alarm */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CAPD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAPTT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.4 - Talker Access for Voice Group Call */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CAPTT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAREJ(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.2 - Reject an incoming Voice Group or Voice Broadcast Call */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CAREJ:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CAULEV(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.5 - Voice Group Call Uplink Status Presentation */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CAULEV:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CBC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.4 - Battery charge */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, NULL, 1, "+CBC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CBCS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.3.2 - VBS subscriptions and GId status */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CBCS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CBIP(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Base station IP address */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CBST(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.7 - Select bearer service type */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CBST:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CCFC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.11 - Call forwarding number and conditions */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CCFC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CCLK(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.15 - Clock */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CCLK:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CCS(at_state_t *s, const char *t) -{ - /* IS-135 4.1.22 - Compression status */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CCUG(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.10 - Closed user group */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CCUG:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CCWA(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.12 - Call waiting */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CCWA:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CCWE(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.28 - Call Meter maximum event */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CCWE:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CDIP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.9 - Called line identification presentation */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CDIP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CDIS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.8 - Display control */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CDIS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CDV(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Dial command for voice call */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CEER(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.10 - Extended error report */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CEER:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CESP(at_state_t *s, const char *t) -{ - /* GSM07.05 3.2.4 - Enter SMS block mode protocol */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CFCS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.24 - Fast call setup conditions */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CFCS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CFG(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Configuration string */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CFUN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.2 - Set phone functionality */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CFUN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGACT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.10 - PDP context activate or deactivate */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CGACT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGANS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.16 - Manual response to a network request for PDP context activation */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CGANS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGATT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.9 - PS attach or detach */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CGATT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGAUTO(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.15 - Automatic response to a network request for PDP context activation */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CGAUTO:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGCAP(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Request complete capabilities list */ - /* TODO: */ - t += 6; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGCLASS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.17 - GPRS mobile station class (GPRS only) */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGCLASS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGCLOSP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.13 - Configure local Octet Stream PAD parameters (Obsolete) */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGCLOSP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGCLPAD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.12 - Configure local triple-X PAD parameters (GPRS only) (Obsolete) */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGCLPAD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGCMOD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.11 - PDP Context Modify */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CGCMOD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGCS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.3.1 - VGCS subscriptions and GId status */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CGCS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGDATA(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.12 - Enter data state */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CGDATA:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGDCONT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.1 - Define PDP Context */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGDCONT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGDSCONT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.2 - Define Secondary PDP Context */ - /* TODO: */ - t += 9; - if (!parse_out(s, &t, NULL, 1, "+CGDSCONT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGEQMIN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.7 - 3G Quality of Service Profile (Minimum acceptable) */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGEQMIN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGEQNEG(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.8 - 3G Quality of Service Profile (Negotiated) */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGEQNEG:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGEQREQ(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.6 - 3G Quality of Service Profile (Requested) */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGEQREQ:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGEREP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.18 - Packet Domain event reporting */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CGEREP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGMI(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.1 - Request manufacturer identification */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CGMI:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGMM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.2 - Request model identification */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CGMM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGMR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.3 - Request revision identification */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CGMR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGOI(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Request global object identification */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGPADDR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.14 - Show PDP address */ - /* TODO: */ - t += 8; - if (!parse_out(s, &t, NULL, 1, "+CGPADDR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGQMIN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.5 - Quality of Service Profile (Minimum acceptable) */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CGQMIN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGQREQ(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.4 - Quality of Service Profile (Requested) */ - /* TODO: */ - t += 7; - if (!parse_out(s, &t, NULL, 1, "+CGQREQ:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGREG(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.19 - GPRS network registration status */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CGREG:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGSMS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.20 - Select service for MO SMS messages */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CGSMS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGSN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.4 - Request product serial number identification */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CGSN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CGTFT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 10.1.3 - Traffic Flow Template */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CGTFT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHLD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.13 - Call related supplementary services */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHLD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHSA(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.18 - HSCSD non-transparent asymmetry configuration */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHSA:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHSC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.15 - HSCSD current call parameters */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHSC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHSD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.12 - HSCSD device parameters */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHSD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHSN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.14 - HSCSD non-transparent call configuration */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHSN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHSR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.16 - HSCSD parameters report */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHSR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHST(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.13 - HSCSD transparent call configuration */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHST:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHSU(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.17 - HSCSD automatic user initiated upgrading */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHSU:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHUP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.5 - Hangup call */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CHUP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CHV(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Hang-up voice */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CIMI(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.6 - Request international mobile subscriber identity */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CIMI:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CIND(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.9 - Indicator control */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CIND:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CIT(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Command state inactivity timer */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CKPD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.7 - Keypad control */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CKPD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLAC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.37 - List all available AT commands */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLAC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLAE(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.31 - Language Event */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLAE:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLAN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.30 - Set Language */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLAN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLCC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.18 - List current calls */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLCC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLCK(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.4 - Facility lock */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLCK:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLIP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.6 - Calling line identification presentation */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLIP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLIR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.7 - Calling line identification restriction */ - /* TODO: */ - /* Parameter sets the adjustment for outgoing calls: - 0 presentation indicator is used according to the subscription of the CLIR service - 1 CLIR invocation - 2 CLIR suppression */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLIR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CLVL(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.23 - Loudspeaker volume level */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CLVL:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMAR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.36 - Master Reset */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CMAR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMEC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.6 - Mobile Termination control mode */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CMEC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMEE(at_state_t *s, const char *t) -{ - /* GSM07.07 9.1 - Report mobile equipment error */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMER(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.10 - Mobile Termination event reporting */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CMER:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGC(at_state_t *s, const char *t) -{ - /* GSM07.05 3.5.5/4.5 - Send command */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGD(at_state_t *s, const char *t) -{ - /* GSM07.05 3.5.4 - Delete message */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGF(at_state_t *s, const char *t) -{ - /* GSM07.05 3.2.3 - Message Format */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGL(at_state_t *s, const char *t) -{ - /* GSM07.05 3.4.2/4.1 - List messages */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGR(at_state_t *s, const char *t) -{ - /* GSM07.05 3.4.3/4.2 - Read message */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGS(at_state_t *s, const char *t) -{ - /* GSM07.05 3.5.1/4.3 - Send message */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMGW(at_state_t *s, const char *t) -{ - /* GSM07.05 3.5.3/4.4 - Write message to memory */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMIP(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Mobile station IP address */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMM(at_state_t *s, const char *t) -{ - /* IS-135 4.1.23 - Menu map */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMMS(at_state_t *s, const char *t) -{ - /* GSM07.05 3.5.6 - More messages to send */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMOD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.4 - Call mode */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CMOD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMSS(at_state_t *s, const char *t) -{ - /* GSM07.05 3.5.2/4.7 - Send message from storage */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMUT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.24 - Mute control */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CMUT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CNMA(at_state_t *s, const char *t) -{ - /* GSM07.05 3.4.4/4.6 - New message acknowledgement to terminal adapter */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CNMI(at_state_t *s, const char *t) -{ - /* GSM07.05 3.4.1 - New message indications to terminal equipment */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CMUX(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.7 - Multiplexing mode */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CMUX:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CNUM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.1 - Subscriber number */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CNUM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_COLP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.8 - Connected line identification presentation */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+COLP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_COPN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.21 - Read operator names */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+COPN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_COPS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.3 - PLMN selection */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+COPS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_COS(at_state_t *s, const char *t) -{ - /* IS-135 4.1.24 - Originating service */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_COTDI(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 11.1.9 - Originator to Dispatcher Information */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+COTDI:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPAS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.1 - Phone activity status */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPAS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPBF(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.13 - Find phonebook entries */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPBF:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPBR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.12 - Read phonebook entries */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPBR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPBS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.11 - Select phonebook memory storage */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPBS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPBW(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.14 - Write phonebook entry */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPBW:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPIN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.3 - Enter PIN */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPIN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPLS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.20 - Selection of preferred PLMN list */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPLS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPMS(at_state_t *s, const char *t) -{ - /* GSM07.05 3.2.2 - Preferred message storage */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPOL(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.19 - Preferred PLMN list */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPOL:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPPS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.23 - eMLPP subscriptions */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPPS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPROT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.42 - Enter protocol mode */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CPROT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPUC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.27 - Price per unit and currency table */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPUC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPWC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.29 - Power class */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPWC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CPWD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.5 - Change password */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CPWD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CQD(at_state_t *s, const char *t) -{ - /* IS-135 4.1.25 - Query disconnect timer */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.9 - Service reporting control */ - /* TODO: */ - t += 3; - if (!parse_out(s, &t, NULL, 1, "+CR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.11 - Cellular result codes */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, NULL, 1, "+CRC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CREG(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.2 - Network registration */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CREG:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRES(at_state_t *s, const char *t) -{ - /* GSM07.05 3.3.6 - Restore Settings */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CRLP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRLP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.8 - Radio link protocol */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CRLP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRM(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Set rm interface protocol */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRMC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.34 - Ring Melody Control */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CRMC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRMP(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.35 - Ring Melody Playback */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CRMP:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRSL(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.21 - Ringer sound level */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CRSL:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CRSM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.18 - Restricted SIM access */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CRSM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSAS(at_state_t *s, const char *t) -{ - /* GSM07.05 3.3.5 - Save settings */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSCA(at_state_t *s, const char *t) -{ - /* GSM07.05 3.3.1 - Service centre address */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSCB(at_state_t *s, const char *t) -{ - /* GSM07.05 3.3.4 - Select cell broadcast message types */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSCC(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.19 - Secure control command */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSCC:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSCS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.5 - Select TE character set */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSCS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSDF(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.22 - Settings date format */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSDF:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSDH(at_state_t *s, const char *t) -{ - /* GSM07.05 3.3.3 - Show text mode parameters */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSGT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.32 - Set Greeting Text */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSGT:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSIL(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.23 - Silence Command */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSIL:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSIM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.17 - Generic SIM access */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSIM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSMP(at_state_t *s, const char *t) -{ - /* GSM07.05 3.3.2 - Set text mode parameters */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSMS(at_state_t *s, const char *t) -{ - /* GSM07.05 3.2.1 - Select Message Service */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSNS(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.19 - Single numbering scheme */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSNS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSQ(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.5 - Signal quality */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, NULL, 1, "+CSQ:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSS(at_state_t *s, const char *t) -{ - /* IS-135 4.1.28 - Serving system identification */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSSN(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.17 - Supplementary service notifications */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSSN:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSTA(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.1 - Select type of address */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSTA:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSTF(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.24 - Settings time format */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSTF:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CSVM(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.33 - Set Voice Mail Number */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CSVM:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CTA(at_state_t *s, const char *t) -{ - /* IS-135 4.1.29 - MT-Terminated async. Data calls */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CTF(at_state_t *s, const char *t) -{ - /* IS-135 4.1.30 - MT-Terminated FAX calls */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CTFR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.14 - Call deflection */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CTFR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CTZR(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.41 - Time Zone Reporting */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CTZR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CTZU(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.40 - Automatic Time Zone Update */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CTZU:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CUSD(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.15 - Unstructured supplementary service data */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CUSD:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CUUS1(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 7.26 - User to User Signalling Service 1 */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CUUS1:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CV120(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.21 - V.120 rate adaption protocol */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+CV120:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CVHU(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 6.20 - Voice Hangup Control */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CVHU:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CVIB(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 8.22 - Vibrator mode */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+CVIB:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_CXT(at_state_t *s, const char *t) -{ - /* IS-99 5.6 - Cellular extension */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_DR(at_state_t *s, const char *t) -{ - /* V.250 6.6.2 - Data compression reporting */ - /* TODO: */ - t += 3; - if (!parse_out(s, &t, NULL, 1, "+DR:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_DS(at_state_t *s, const char *t) -{ - /* V.250 6.6.1 - Data compression */ - /* TODO: */ - t += 3; - if (!parse_out(s, &t, NULL, 1, "+DS:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_DS44(at_state_t *s, const char *t) -{ - /* V.250 6.6.2 - V.44 data compression */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_EB(at_state_t *s, const char *t) -{ - /* V.250 6.5.2 - Break handling in error control operation */ - /* TODO: */ - t += 3; - if (!parse_out(s, &t, NULL, 1, "+EB:", "")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_EFCS(at_state_t *s, const char *t) -{ - /* V.250 6.5.4 - 32-bit frame check sequence */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 2, "+EFCS:", "(0-2)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_EFRAM(at_state_t *s, const char *t) -{ - /* V.250 6.5.8 - Frame length */ - /* TODO: */ - t += 6; - if (!parse_2_out(s, &t, NULL, 65535, NULL, 65535, "+EFRAM:", "(1-65535),(1-65535)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ER(at_state_t *s, const char *t) -{ - /* V.250 6.5.5 - Error control reporting */ - /* 0 Error control reporting disabled (no +ER intermediate result code transmitted) - 1 Error control reporting enabled (+ER intermediate result code transmitted) */ - /* TODO: */ - t += 3; - if (!parse_out(s, &t, NULL, 1, "+ER:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ES(at_state_t *s, const char *t) -{ - static const int maxes[3] = - { - 7, 4, 9 - }; - int *locations[3]; - - /* V.250 6.5.1 - Error control selection */ - - /* orig_rqst - 0: Direct mode - 1: Initiate call with Buffered mode only - 2: Initiate V.42 without Detection Phase. If Rec. V.8 is in use, this is a request to disable V.42 Detection Phase - 3: Initiate V.42 with Detection Phase - 4: Initiate Altemative Protocol - 5: Initiate Synchronous Mode when connection is completed, immediately after the entire CONNECT result code - is delivered. V.24 circuits 113 and 115 are activated when Data State is entered - 6: Initiate Synchronous Access Mode when connection is completed, and Data State is entered - 7: Initiate Frame Tunnelling Mode when connection is completed, and Data State is entered - - orig_fbk - 0: Error control optional (either LAPM or Alternative acceptable); if error control not established, maintain - DTE-DCE data rate and use V.14 buffered mode with flow control during non-error-control operation - 1: Error control optional (either LAPM or Alternative acceptable); if error control not established, change - DTE-DCE data rate to match line rate and use Direct mode - 2: Error control required (either LAPM or Alternative acceptable); if error control not established, disconnect - 3: Error control required (only LAPM acceptable); if error control not established, disconnect - 4: Error control required (only Altemative protocol acceptable); if error control not established, disconnect - - ans_fbk - 0: Direct mode - 1: Error control disabled, use Buffered mode - 2: Error control optional (either LAPM or Alternative acceptable); if error control not established, maintain - DTE-DCE data rate and use local buffering and flow control during non-error-control operation - 3: Error control optional (either LAPM or Alternative acceptable); if error control not established, change - DTE-DCE data rate to match line rate and use Direct mode - 4: Error control required (either LAPM or Alternative acceptable); if error control not established, disconnect - 5: Error control required (only LAPM acceptable); if error control not established, disconnect - 6: Error control required (only Alternative protocol acceptable); if error control not established, disconnect - 7: Initiate Synchronous Mode when connection is completed, immediately after the entire CONNECT result code - is delivered. V.24 cicuits 113 and 115 are activated when Data State is entered - 8: Initiate Synchronous Access Mode when connection is completed, and Data State is entered - 9: Initiate Frame Tunnelling Mode when connection is completed, and Data State is entered */ - - /* TODO: */ - t += 3; - locations[0] = NULL; - locations[1] = NULL; - locations[2] = NULL; - if (!parse_n_out(s, &t, locations, maxes, 3, "+ES:", "(0-7),(0-4),(0-9)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ESA(at_state_t *s, const char *t) -{ - static const int maxes[8] = - { - 2, 1, 1, 1, 2, 1, 255, 255 - }; - int *locations[8]; - int i; - - /* V.80 8.2 - Synchronous access mode configuration */ - /* TODO: */ - t += 4; - for (i = 0; i < 8; i++) - locations[i] = NULL; - if (!parse_n_out(s, &t, locations, maxes, 8, "+ESA:", "(0-2),(0-1),(0-1),(0-1),(0-2),(0-1),(0-255),(0-255)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ESR(at_state_t *s, const char *t) -{ - /* V.250 6.5.3 - Selective repeat */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ETBM(at_state_t *s, const char *t) -{ - /* V.250 6.5.6 - Call termination buffer management */ - /* TODO: */ - t += 5; - if (!parse_2_out(s, &t, NULL, 2, NULL, 2, "+ETBM:", "(0-2),(0-2),(0-30)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_EWIND(at_state_t *s, const char *t) -{ - /* V.250 6.5.7 - Window size */ - /* TODO: */ - t += 6; - if (!parse_2_out(s, &t, &s->rx_window, 127, &s->tx_window, 127, "+EWIND:", "(1-127),(1-127)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_F34(at_state_t *s, const char *t) -{ - static const int maxes[5] = - { - 14, 14, 2, 14, 14 - }; - int *locations[5]; - int i; - - /* T.31 B.6.1 - Initial V.34 rate controls for FAX */ - /* Syntax: +F34=[][,[][,][,][,p.adaptive_receive, 1, NULL, "0,1")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FBO(at_state_t *s, const char *t) -{ - /* T.32 8.5.3.4 - Phase C data bit order */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FBS(at_state_t *s, const char *t) -{ - /* T.32 8.5.3.2 - Buffer Size, read only parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FBU(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.10 - HDLC Frame Reporting parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCC(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.1 - DCE capabilities parameters */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCL(at_state_t *s, const char *t) -{ - /* T.31 8.5.2 - Carrier loss timeout */ - t += 4; - if (!parse_out(s, &t, &s->carrier_loss_timeout, 255, NULL, "(0-255)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCLASS(at_state_t *s, const char *t) -{ - /* T.31 8.2 - Capabilities identification and control */ - t += 7; - /* T.31 says the reply string should be "0,1.0", however making - it "0,1,1.0" makes things compatible with a lot more software - that may be expecting a pre-T.31 modem. */ - if (!parse_string_list_out(s, &t, &s->fclass_mode, 1, NULL, "0,1,1.0")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCQ(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.3 - Copy quality checking parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCR(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.9 - Capability to receive parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCS(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.3 - Current Session Results parameters */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FCT(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.6 - DTE phase C timeout parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FDD(at_state_t *s, const char *t) -{ - /* T.31 8.5.3 - Double escape character replacement */ - t += 4; - if (!parse_out(s, &t, &s->p.double_escape, 1, NULL, "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FDR(at_state_t *s, const char *t) -{ - /* T.32 8.3.4 - Data reception command */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FDT(at_state_t *s, const char *t) -{ - /* T.32 8.3.3 - Data transmission command */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FEA(at_state_t *s, const char *t) -{ - /* T.32 8.5.3.5 - Phase C received EOL alignment parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FFC(at_state_t *s, const char *t) -{ - /* T.32 8.5.3.6 - Format conversion parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FFD(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.14 - File diagnostic message parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FHS(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.7 - Call termination status parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FIE(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.1 - Procedure interrupt enable parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FIP(at_state_t *s, const char *t) -{ - /* T.32 8.3.6 - Initialize Facsimile Parameters */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FIS(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.2 - Current session parameters */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FIT(at_state_t *s, const char *t) -{ - /* T.31 8.5.4 - DTE inactivity timeout */ - t += 4; - if (!parse_2_out(s, &t, &s->dte_inactivity_timeout, 255, &s->dte_inactivity_action, 1, "+FIT:", "(0-255),(0-1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FKS(at_state_t *s, const char *t) -{ - /* T.32 8.3.5 - Session termination command */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FLI(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.5 - Local ID string parameter, TSI or CSI */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FLO(at_state_t *s, const char *t) -{ - /* T.31 Annex A */ - /* Implement something similar to the V.250 +IFC command */ - /* 0: None. - 1: XON/XOFF. - 2: Hardware (default) */ - t += 4; - span_log(&s->logging, SPAN_LOG_FLOW, "+FLO received\n"); - if (!parse_out(s, &t, &s->dte_dce_flow_control, 2, "+FLO:", "(0-2)")) - return NULL; - s->dce_dte_flow_control = s->dte_dce_flow_control; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FLP(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.7 - Indicate document to poll parameter */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FMI(at_state_t *s, const char *t) -{ - /* T.31 says to duplicate +GMI */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, manufacturer); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FMM(at_state_t *s, const char *t) -{ - /* T.31 says to duplicate +GMM */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, model); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FMR(at_state_t *s, const char *t) -{ - /* T.31 says to duplicate +GMR */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, revision); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FMS(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.9 - Minimum phase C speed parameter */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FND(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.10 - Non-Standard Message Data Indication parameter */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FNR(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.11 - Negotiation message reporting control parameters */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FNS(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.6 - Non-Standard Frame FIF parameter */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FPA(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.13 - Selective polling address parameter */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FPI(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.5 - Local Polling ID String parameter */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FPP(at_state_t *s, const char *t) -{ - /* T.32 8.5.3 - Facsimile packet protocol */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FPR(at_state_t *s, const char *t) -{ - /* T.31 Annex A */ - /* Implement something similar to the V.250 +IPR command */ - t += 4; - if (!parse_out(s, &t, &s->dte_rate, 115200, NULL, "115200")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FPS(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.2 - Page Status parameter */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FPW(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.13 - PassWord parameter (Sending or Polling) */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FRH(at_state_t *s, const char *t) -{ - /* T.31 8.3.6 - HDLC receive */ - if (!process_class1_cmd(s, &t)) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FRM(at_state_t *s, const char *t) -{ - /* T.31 8.3.4 - Facsimile receive */ - if (!process_class1_cmd(s, &t)) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FRQ(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.4 - Receive Quality Thresholds parameters */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FRS(at_state_t *s, const char *t) -{ - /* T.31 8.3.2 - Receive silence */ - if (!process_class1_cmd(s, &t)) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FRY(at_state_t *s, const char *t) -{ - /* T.32 8.5.2.8 - ECM Retry Value parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FSA(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.13 - Subaddress parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FSP(at_state_t *s, const char *t) -{ - /* T.32 8.5.1.8 - Request to poll parameter */ - /* TODO */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FTH(at_state_t *s, const char *t) -{ - /* T.31 8.3.5 - HDLC transmit */ - if (!process_class1_cmd(s, &t)) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FTM(at_state_t *s, const char *t) -{ - /* T.31 8.3.3 - Facsimile transmit */ - if (!process_class1_cmd(s, &t)) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_FTS(at_state_t *s, const char *t) -{ - /* T.31 8.3.1 - Transmit silence */ - if (!process_class1_cmd(s, &t)) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GCAP(at_state_t *s, const char *t) -{ - /* V.250 6.1.9 - Request complete capabilities list */ - t += 5; - /* Response elements - +FCLASS +F (FAX) commands - +MS +M (modulation control) commands +MS and +MR - +MV18S +M (modulation control) commands +MV18S and +MV18R - +ES +E (error control) commands +ES, +EB, +ER, +EFCS, and +ETBM - +DS +D (data compression) commands +DS and +DR */ - /* TODO: make this adapt to the configuration we really have. */ - if (t[0] == '?') - { - at_put_response(s, "+GCAP:+FCLASS"); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GCI(at_state_t *s, const char *t) -{ - /* V.250 6.1.10 - Country of installation, */ - t += 4; - if (!parse_hex_out(s, &t, &s->country_of_installation, 255, "+GCI:", "(00-FF)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GMI(at_state_t *s, const char *t) -{ - /* V.250 6.1.4 - Request manufacturer identification */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, manufacturer); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GMM(at_state_t *s, const char *t) -{ - /* V.250 6.1.5 - Request model identification */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, model); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GMR(at_state_t *s, const char *t) -{ - /* V.250 6.1.6 - Request revision identification */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, revision); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GOI(at_state_t *s, const char *t) -{ - /* V.250 6.1.8 - Request global object identification */ - /* TODO: */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, GLOBAL_OBJECT_IDENTITY); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_GSN(at_state_t *s, const char *t) -{ - /* V.250 6.1.7 - Request product serial number identification */ - /* TODO: */ - t += 4; - if (t[0] == '?') - { - at_put_response(s, SERIAL_NUMBER); - t += 1; - } - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_IBC(at_state_t *s, const char *t) -{ - static const int maxes[13] = - { - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - }; - int *locations[13]; - int i; - - /* V.80 7.9 - Control of in-band control */ - /* TODO: */ - t += 4; - /* 0: In-band control service disabled - 1: In-band control service enabled, 7-bit codes allowed, and top bit insignificant - 2; In-band control service enabled, 7-bit codes allowed, and 8-bit codes available - - Circuits 105, 106, 107, 108, 109, 110, 125, 132, 133, 135, 142 in that order. For each one: - 0: disabled - 1: enabled - - DCE line connect status reports: - 0: disabled - 1: enabled */ - for (i = 0; i < 13; i++) - locations[i] = NULL; - if (!parse_n_out(s, &t, locations, maxes, 13, "+IBC:", "(0-2),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0.1),(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_IBM(at_state_t *s, const char *t) -{ - static const int maxes[3] = - { - 7, 255, 255 - }; - int *locations[3]; - - /* V.80 7.10 - In-band MARK idle reporting control */ - /* TODO: */ - t += 4; - /* Report control - 0: No reports - 1: Report only once when expires - 2: Report each time expires - 3: Report once when expires, and then each time expires - 4: Report only when the Mark-ldle Period ends; T3 = the entire interval - 5: Report the first time when is exceeded, and then once more when the mark idle period ends - 6: Report each time when is exceeded, and then once more when the mark idle period ends; - T3 = entire interval -- N*T2 - 7: report the first time when is exceeded, and then each time is exceeded, and then once - more when the mark idle period ends; T3 = entire mark idle period -- N*T2 - T1 - - T1 in units of 10ms - - T2 in units of 10ms */ - locations[0] = NULL; - locations[1] = NULL; - locations[2] = NULL; - if (!parse_n_out(s, &t, locations, maxes, 3, "+IBM:", "(0-7),(0-255),(0-255)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ICF(at_state_t *s, const char *t) -{ - /* V.250 6.2.11 - DTE-DCE character framing */ - t += 4; - /* Character format - 0: auto detect - 1: 8 data 2 stop - 2: 8 data 1 parity 1 stop - 3: 8 data 1 stop - 4: 7 data 2 stop - 5: 7 data 1 parity 1 stop - 6: 7 data 1 stop - - Parity - 0: Odd - 1: Even - 2: Mark - 3: Space */ - if (!parse_2_out(s, &t, &s->dte_char_format, 6, &s->dte_parity, 3, "+ICF:", "(0-6),(0-3)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ICLOK(at_state_t *s, const char *t) -{ - /* V.250 6.2.14 - Select sync transmit clock source */ - t += 6; - if (!parse_out(s, &t, &s->sync_tx_clock_source, 2, "+ICLOK:", "(0-2)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_IDSR(at_state_t *s, const char *t) -{ - /* V.250 6.2.16 - Select data set ready option */ - t += 5; - if (!parse_out(s, &t, &s->dsr_option, 2, "+IDSR:", "(0-2)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_IFC(at_state_t *s, const char *t) -{ - /* V.250 6.2.12 - DTE-DCE local flow control */ - /* 0: None. - 1: XON/XOFF. - 2: Hardware (default) */ - span_log(&s->logging, SPAN_LOG_FLOW, "+IFC received\n"); - t += 4; - if (!parse_2_out(s, &t, &s->dte_dce_flow_control, 2, &s->dce_dte_flow_control, 2, "+IFC:", "(0-2),(0-2)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ILRR(at_state_t *s, const char *t) -{ - /* V.250 6.2.13 - DTE-DCE local rate reporting */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ILSD(at_state_t *s, const char *t) -{ - /* V.250 6.2.15 - Select long space disconnect option */ - t += 5; - if (!parse_out(s, &t, &s->long_space_disconnect_option, 2, "+ILSD:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_IPR(at_state_t *s, const char *t) -{ - /* V.250 6.2.10 - Fixed DTE rate */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, &s->dte_rate, 115200, "+IPR:", "(115200),(115200)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_IRTS(at_state_t *s, const char *t) -{ - /* V.250 6.2.17 - Select synchronous mode RTS option */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+IRTS:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_ITF(at_state_t *s, const char *t) -{ - /* V.80 8.4 - Transmit flow control thresholds */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MA(at_state_t *s, const char *t) -{ - /* V.250 6.4.2 - Modulation automode control */ - /* TODO: */ - t += 3; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MR(at_state_t *s, const char *t) -{ - /* V.250 6.4.3 - Modulation reporting control */ - /* 0: Disables reporting of modulation connection (+MCR: and +MRR: are not transmitted) - 1: Enables reporting of modulation connection (+MCR: and +MRR: are transmitted) */ - /* TODO: */ - t += 3; - if (!parse_out(s, &t, NULL, 1, "+MR:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MS(at_state_t *s, const char *t) -{ - /* V.250 6.4.1 - Modulation selection */ - /* TODO: */ - t += 3; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MSC(at_state_t *s, const char *t) -{ - /* V.250 6.4.8 - Seamless rate change enable */ - /* 0 Disables V.34 seamless rate change - 1 Enables V.34 seamless rate change */ - /* TODO: */ - t += 4; - if (!parse_out(s, &t, NULL, 1, "+MSC:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MV18AM(at_state_t *s, const char *t) -{ - /* V.250 6.4.6 - V.18 answering message editing */ - /* TODO: */ - t += 7; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MV18P(at_state_t *s, const char *t) -{ - /* V.250 6.4.7 - Order of probes */ - /* 2 Send probe message in 5-bit (Baudot) mode - 3 Send probe message in DTMF mode - 4 Send probe message in EDT mode - 5 Send Rec. V.21 carrier as a probe - 6 Send Rec. V.23 carrier as a probe - 7 Send Bell 103 carrier as a probe */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 7, "+MV18P:", "(2-7)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MV18R(at_state_t *s, const char *t) -{ - /* V.250 6.4.5 - V.18 reporting control */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+MV18R:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_MV18S(at_state_t *s, const char *t) -{ - /* V.250 6.4.4 - V.18 selection */ - /* mode: - 0 Disables V.18 operation - 1 V.18 operation, auto detect mode - 2 V.18 operation, connect in 5-bit (Baudot) mode - 3 V.18 operation, connect in DTMF mode - 4 V.18 operation, connect in EDT mode - 5 V.18 operation, connect in V.21 mode - 6 V.18 operation, connect in V.23 mode - 7 V.18 operation, connect in Bell 103-type mode - - dflt_ans_mode: - 0 Disables V.18 answer operation - 1 No default specified (auto detect) - 2 V.18 operation connect in 5-bit (Baudot) mode - 3 V.18 operation connect in DTMF mode - 4 V.18 operation connect in EDT mode - - fbk_time_enable: - 0 Disable - 1 Enable - - ans_msg_enable - 0 Disable - 1 Enable - - probing_en - 0 Disable probing - 1 Enable probing - 2 Initiate probing */ - /* TODO: */ - t += 6; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PCW(at_state_t *s, const char *t) -{ - /* V.250 6.8.1 - Call waiting enable (V.92 DCE) */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PIG(at_state_t *s, const char *t) -{ - /* V.250 6.8.5 - PCM upstream ignore */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PMH(at_state_t *s, const char *t) -{ - /* V.250 6.8.2 - Modem on hold enable */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PMHF(at_state_t *s, const char *t) -{ - /* V.250 6.8.6 - V.92 Modem on hold hook flash */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PMHR(at_state_t *s, const char *t) -{ - /* V.250 6.8.4 - Initiate modem on hold */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PMHT(at_state_t *s, const char *t) -{ - /* V.250 6.8.3 - Modem on hold timer */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PQC(at_state_t *s, const char *t) -{ - /* V.250 6.8.7 - V.92 Phase 1 and Phase 2 Control */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_PSS(at_state_t *s, const char *t) -{ - /* V.250 6.8.8 - V.92 Use Short Sequence */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SAC(at_state_t *s, const char *t) -{ - /* V.252 3.4 - Audio transmit configuration */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SAM(at_state_t *s, const char *t) -{ - /* V.252 3.5 - Audio receive mode */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SAR(at_state_t *s, const char *t) -{ - /* V.252 5.3 - Audio receive channel indication */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SARR(at_state_t *s, const char *t) -{ - /* V.252 3.9 - Audio indication reporting */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SAT(at_state_t *s, const char *t) -{ - /* V.252 5.4 - Audio transmit channel indication */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SCRR(at_state_t *s, const char *t) -{ - /* V.252 3.11 - Capabilities indication reporting */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SDC(at_state_t *s, const char *t) -{ - /* V.252 3.3 - Data configuration */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SDI(at_state_t *s, const char *t) -{ - /* V.252 5.2 - Data channel identification */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SDR(at_state_t *s, const char *t) -{ - /* V.252 3.8 - Data indication reporting */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SRSC(at_state_t *s, const char *t) -{ - /* V.252 5.1.2 - Remote terminal simultaneous capability indication */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_STC(at_state_t *s, const char *t) -{ - /* V.252 3.1 - Terminal configuration */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_STH(at_state_t *s, const char *t) -{ - /* V.252 3.2 - Close logical channel */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SVC(at_state_t *s, const char *t) -{ - /* V.252 3.6 - Video transmit configuration */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SVM(at_state_t *s, const char *t) -{ - /* V.252 3.7 - Video receive mode */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SVR(at_state_t *s, const char *t) -{ - /* V.252 5.5 - Video receive channel indication */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SVRR(at_state_t *s, const char *t) -{ - /* V.252 3.10 - Video indication reporting */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_SVT(at_state_t *s, const char *t) -{ - /* V.252 5.6 - Video transmit channel indication */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TADR(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.9 - Local V.54 address */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TAL(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.15 - Local analogue loop */ - /* Action - 0 Disable analogue loop - 1 Enable analogue loop - Band - 0 Low frequency band - 1 High frequency band */ - /* TODO: */ - t += 4; - if (!parse_2_out(s, &t, NULL, 1, NULL, 1, "+TAL:", "(0,1),(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TALS(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.6 - Analogue loop status */ - /* 0 Inactive - 1 V.24 circuit 141 invoked - 2 Front panel invoked - 3 Network management system invoked */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 3, "+TALS:", "(0-3)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TDLS(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.7 - Local digital loop status */ - /* 0 Disabled - 1 Enabled, inactive - 2 Front panel invoked - 3 Network management system invoked - 4 Remote invoked */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 3, "+TDLS:", "(0-4)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TE140(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.1 - Enable ckt 140 */ - /* 0 Disabled - 1 Enabled */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TE140:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TE141(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.2 - Enable ckt 141 */ - /* 0 Response is disabled - 1 Response is enabled */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TE141:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TEPAL(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.5 - Enable front panel analogue loop */ - /* 0 Disabled - 1 Enabled */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TEPAL:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TEPDL(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.4 - Enable front panel RDL */ - /* 0 Disabled - 1 Enabled */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TEPDL:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TERDL(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.3 - Enable RDL from remote */ - /* 0 Local DCE will ignore command from remote - 1 Local DCE will obey command from remote */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TERDL:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TLDL(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.13 - Local digital loop */ - /* 0 Stop test - 1 Start test */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+TLDL:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TMO(at_state_t *s, const char *t) -{ - /* V.250 6.9 - V.59 command */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TMODE(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.10 - Set V.54 mode */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TMODE:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TNUM(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.12 - Errored bit and block counts */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TRDL(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.14 - Request remote digital loop */ - /* 0 Stop RDL - 1 Start RDL */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+TRDL:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TRDLS(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.8 - Remote digital loop status */ - /* TODO: */ - t += 6; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TRES(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.17 - Self test result */ - /* 0 No test - 1 Pass - 2 Fail */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, NULL, 1, "+TRES:", "(0-2)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TSELF(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.16 - Self test */ - /* 0 Intrusive full test - 1 Safe partial test */ - /* TODO: */ - t += 6; - if (!parse_out(s, &t, NULL, 1, "+TSELF:", "(0,1)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_TTER(at_state_t *s, const char *t) -{ - /* V.250 6.7.2.11 - Test error rate */ - /* TODO: */ - t += 5; - if (!parse_2_out(s, &t, NULL, 65535, NULL, 65535, "+TTER:", "(0-65535),(0-65535)")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VAC(at_state_t *s, const char *t) -{ - /* V.252 4.1 - Set audio code */ - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VACR(at_state_t *s, const char *t) -{ - /* V.252 6.1 - Audio code report */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VBT(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 C.2.2 - Buffer threshold setting */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VCID(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 C.2.3 - Calling number ID presentation */ - /* TODO: */ - t += 5; - if (!parse_out(s, &t, &s->display_call_info, 1, NULL, "0,1")) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VCIDR(at_state_t *s, const char *t) -{ - /* V.252 6.2 - Caller ID report */ - /* TODO: */ - t += 6; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VDID(at_state_t *s, const char *t) -{ - /* V.253 9.2.4 - DID service */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VDIDR(at_state_t *s, const char *t) -{ - /* V.252 6.2 - DID report */ - /* TODO: */ - t += 6; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VDR(at_state_t *s, const char *t) -{ - /* V.253 10.3.1 - Distinctive ring (ring cadence reporting) */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VDT(at_state_t *s, const char *t) -{ - /* V.253 10.3.2 - Control tone cadence reporting */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VDX(at_state_t *s, const char *t) -{ - /* V.253 10.5.6 - Speakerphone duplex mode */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VEM(at_state_t *s, const char *t) -{ - /* V.253 10.5.7 - Deliver event reports */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VGM(at_state_t *s, const char *t) -{ - /* V.253 10.5.2 - Microphone gain */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VGR(at_state_t *s, const char *t) -{ - /* V.253 10.2.1 - Receive gain selection */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VGS(at_state_t *s, const char *t) -{ - /* V.253 10.5.3 - Speaker gain */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VGT(at_state_t *s, const char *t) -{ - /* V.253 10.2.2 - Volume selection */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VHC(at_state_t *s, const char *t) -{ - /* V.252 4.12 - Telephony port hook control */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VIP(at_state_t *s, const char *t) -{ - /* V.253 10.1.1 - Initialize voice parameters */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VIT(at_state_t *s, const char *t) -{ - /* V.253 10.2.3 - DTE/DCE inactivity timer */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VLS(at_state_t *s, const char *t) -{ - /* V.253 10.2.4 - Analogue source/destination selection */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VNH(at_state_t *s, const char *t) -{ - /* V.253 9.2.5 - Automatic hangup control */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VPH(at_state_t *s, const char *t) -{ - /* V.252 4.11 - Phone hookswitch status */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VPP(at_state_t *s, const char *t) -{ - /* V.253 10.4.2 - Voice packet protocol */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VPR(at_state_t *s, const char *t) -{ - /* IS-101 10.4.3 - Select DTE/DCE interface rate */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VRA(at_state_t *s, const char *t) -{ - /* V.253 10.2.5 - Ringing tone goes away timer */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VRID(at_state_t *s, const char *t) -{ - int val; - - /* Extension of V.253 +VCID, Calling number ID report/repeat */ - t += 5; - val = 0; - if (!parse_out(s, &t, &val, 1, NULL, "0,1")) - return NULL; - if (val == 1) - at_display_call_info(s); - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VRL(at_state_t *s, const char *t) -{ - /* V.253 10.1.2 - Ring local phone */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VRN(at_state_t *s, const char *t) -{ - /* V.253 10.2.6 - Ringing tone never appeared timer */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VRX(at_state_t *s, const char *t) -{ - /* V.253 10.1.3 - Voice receive state */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VSD(at_state_t *s, const char *t) -{ - /* V.253 10.2.7 - Silence detection (QUIET and SILENCE) */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VSID(at_state_t *s, const char *t) -{ - /* Extension of V.253 +VCID, Set calling number ID */ - t += 5; - if (!parse_string_out(s, &t, &s->local_id, NULL)) - return NULL; - if (at_modem_control(s, AT_MODEM_CONTROL_SETID, s->local_id) < 0) - return NULL; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VSM(at_state_t *s, const char *t) -{ - /* V.253 10.2.8 - Compression method selection */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VSP(at_state_t *s, const char *t) -{ - /* V.253 10.5.1 - Voice speakerphone state */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTA(at_state_t *s, const char *t) -{ - /* V.253 10.5.4 - Train acoustic echo-canceller */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTD(at_state_t *s, const char *t) -{ - /* V.253 10.2.9 - Beep tone duration timer */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTER(at_state_t *s, const char *t) -{ - /* V.252 6.4 - Simple telephony event report */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTH(at_state_t *s, const char *t) -{ - /* V.253 10.5.5 - Train line echo-canceller */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTR(at_state_t *s, const char *t) -{ - /* V.253 10.1.4 - Voice duplex state */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTS(at_state_t *s, const char *t) -{ - /* V.253 10.1.5 - DTMF and tone generation in voice */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VTX(at_state_t *s, const char *t) -{ - /* V.253 10.1.6 - Transmit data state */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_VXT(at_state_t *s, const char *t) -{ - /* IS-101 10.1.5 - Translate voice data */ - /* TODO: */ - t += 4; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_W(at_state_t *s, const char *t) -{ - /* TIA-678 5.2.4.1 - Compliance indication */ - /* TODO: */ - t += 2; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WBAG(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.6 Bias Modem Audio Gain */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WCDA(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.2.5 Display Data Link Address */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WCHG(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.2.4 Display Battery Charging Status */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WCID(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.2.1 Display System ID (operator) */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WCLK(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.2.3 Lock/Unlock DCE */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WCPN(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.2.2 Set Personal Identification Number */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WCXF(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.2.6 Display Supported Annex B commands */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WDAC(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.1 Data over Analogue Cellular Command Query */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WDIR(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.8 Phone Number Directory Selection */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WECR(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.3 Enable Cellular Result Codes */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WFON(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.5 Phone Specification */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WKPD(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.7 Keypad Emulation */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WPBA(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.9 Phone Battery Query */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WPTH(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.10 Call Path */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WRLK(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.4 Roam Lockout */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS45(at_state_t *s, const char *t) -{ - /* TIA-678 5.2.4.2 DTE-side stack selection */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS46(at_state_t *s, const char *t) -{ - /* 3GPP TS 27.007 5.9 - PCCA STD-101 [17] select wireless network */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS50(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.1 Normalized Signal Strength */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS51(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.2 Carrier Detect Signal Threshold */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS52(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.3 Normalized Battery Level */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS53(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.4 Normalized Channel Quality */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS54(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.5 Carrier Detect Channel Quality Threshold */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS57(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.7 Antenna Preference */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WS58(at_state_t *s, const char *t) -{ - /* TIA-678 B.3.1.8 Idle Time-out Value */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -static const char *at_cmd_plus_WSTL(at_state_t *s, const char *t) -{ - /* TIA-678 C.5.2 Call Session Time Limit */ - /* TODO: */ - t += 5; - return t; -} -/*- End of function --------------------------------------------------------*/ - -/* - AT command group prefixes: - - +A Call control (network addressing) issues, common, PSTN, ISDN, Rec. X.25, switched digital - +C Digital cellular extensions - +D Data compression, Rec. V.42bis - +E Error control, Rec. V.42 - +F Facsimile, Rec. T.30, etc. - +G Generic issues such as identity and capabilities - +I DTE-DCE interface issues, Rec. V.24, etc. - +M Modulation, Rec. V.32bis, etc. - +S Switched or simultaneous data types - +T Test issues - +V Voice extensions - +W Wireless extensions -*/ - -#include "at_interpreter_dictionary.h" - -static int command_search(const char *u, int *matched) -{ - int i; - int index; - int first; - int last; - int entry; - int ptr; - - entry = 0; - /* Loop over the length of the string to search the trie... */ - for (i = 0, ptr = 0; ptr < COMMAND_TRIE_LEN - 2; i++) - { - /* The character in u we are processing... */ - /* V.250 5.4.1 says upper and lower case are equivalent in commands */ - index = toupper((int) u[i]); - /* Is there a child node for this character? */ - /* Note: First and last could have been packed into one uint16_t, - but space is not that critical, so the other packing is good - enough to make the table reasonable. */ - first = command_trie[ptr++]; - last = command_trie[ptr++]; - entry = command_trie[ptr++]; - if (index < first || index > last) - break; - if ((ptr = command_trie[ptr + index - first]) == 0) - break; - ptr--; - } - *matched = i; - return entry; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) at_modem_control(at_state_t *s, int op, const char *num) -{ - switch (op) - { - case AT_MODEM_CONTROL_ANSWER: - break; - case AT_MODEM_CONTROL_CALL: - break; - case AT_MODEM_CONTROL_HANGUP: - break; - case AT_MODEM_CONTROL_OFFHOOK: - break; - case AT_MODEM_CONTROL_DTR: - break; - case AT_MODEM_CONTROL_RTS: - break; - case AT_MODEM_CONTROL_CTS: - break; - case AT_MODEM_CONTROL_CAR: - break; - case AT_MODEM_CONTROL_RNG: - break; - case AT_MODEM_CONTROL_DSR: - break; - case AT_MODEM_CONTROL_RESTART: - break; - default: - break; - } - /*endswitch*/ - return s->modem_control_handler(s->modem_control_user_data, op, num); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_interpreter(at_state_t *s, const char *cmd, int len) -{ - int i; - int c; - int entry; - int matched; - const char *t; - - if (s->p.echo) - s->at_tx_handler(s->at_tx_user_data, (uint8_t *) cmd, len); - - for (i = 0; i < len; i++) - { - /* The spec says the top bit should be ignored */ - c = *cmd++ & 0x7F; - /* Handle incoming character */ - if (s->line_ptr < 2) - { - /* Look for the initial "at", "AT", "a/" or "A/", and ignore anything before it */ - /* V.250 5.2.1 only shows "at" and "AT" as command prefixes. "At" and "aT" are - not specified, despite 5.4.1 saying upper and lower case are equivalent in - commands. Let's be tolerant and accept them. */ - if (tolower(c) == 'a') - { - s->line_ptr = 0; - s->line[s->line_ptr++] = (char) toupper(c); - } - else if (s->line_ptr == 1) - { - if (tolower(c) == 't') - { - /* We have an "AT" command */ - s->line[s->line_ptr++] = (char) toupper(c); - } - else if (c == '/') - { - /* We have an "A/" command */ - /* TODO: implement "A/" command repeat */ - s->line[s->line_ptr++] = (char) c; - } - else - { - s->line_ptr = 0; - } - } - } - else - { - /* We are beyond the initial AT */ - if (c >= 0x20 && c <= 0x7E) - { - /* Add a new char */ - if (s->line_ptr < (int) (sizeof(s->line) - 1)) - s->line[s->line_ptr++] = (char) toupper(c); - } - else if (c == s->p.s_regs[3]) - { - /* End of command line. Do line validation */ - s->line[s->line_ptr] = '\0'; - if (s->line_ptr > 2) - { - /* The spec says the commands within a command line are executed in order, until - an error is found, or the end of the command line is reached. */ - t = s->line + 2; - while (t && *t) - { - 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) - break; - } - if (t != (const char *) -1) - { - if (t == NULL) - at_put_response_code(s, AT_RESPONSE_CODE_ERROR); - else - at_put_response_code(s, AT_RESPONSE_CODE_OK); - } - } - else if (s->line_ptr == 2) - { - /* It's just an empty "AT" command, return OK. */ - at_put_response_code(s, AT_RESPONSE_CODE_OK); - } - s->line_ptr = 0; - } - else if (c == s->p.s_regs[5]) - { - /* Command line editing character (backspace) */ - if (s->line_ptr > 0) - s->line_ptr--; - } - else - { - /* The spec says control characters, other than those - explicitly handled, should be ignored, and so this - invalid character causes everything buffered - before it to also be ignored. */ - s->line_ptr = 0; - } - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_set_class1_handler(at_state_t *s, at_class1_handler_t handler, void *user_data) -{ - s->class1_handler = handler; - s->class1_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_set_modem_control_handler(at_state_t *s, - at_modem_control_handler_t modem_control_handler, - void *modem_control_user_data) -{ - s->modem_control_handler = modem_control_handler; - s->modem_control_user_data = modem_control_user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) at_set_at_tx_handler(at_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data) -{ - s->at_tx_handler = at_tx_handler; - s->at_tx_user_data = at_tx_user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) at_get_logging_state(at_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(at_state_t *) at_init(at_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data, - at_modem_control_handler_t modem_control_handler, - void *modem_control_user_data) -{ - if (s == NULL) - { - if ((s = (at_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, "AT"); - s->modem_control_handler = modem_control_handler; - s->modem_control_user_data = modem_control_user_data; - s->at_tx_handler = at_tx_handler; - s->at_tx_user_data = at_tx_user_data; - s->call_id = NULL; - s->local_id = NULL; - s->display_call_info = 0; - s->dte_dce_flow_control = 2; - s->dce_dte_flow_control = 2; - at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - s->p = profiles[0]; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) at_release(at_state_t *s) -{ - at_reset_call_info(s); - if (s->local_id) - span_free(s->local_id); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) at_free(at_state_t *s) -{ - int ret; - - ret = at_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/awgn.c b/libs/spandsp/src/awgn.c deleted file mode 100644 index 04edfff3b4..0000000000 --- a/libs/spandsp/src/awgn.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * awgn.c - An additive Gaussian white noise generator - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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 */ - -/* This code is based on some demonstration code in a research - paper somewhere. I can't track down where I got the original from, - so that due recognition can be given. The original had no explicit - copyright notice, and I hope nobody objects to its use here. - - Having a reasonable Gaussian noise generator is pretty important for - telephony testing (in fact, pretty much any DSP testing), and this - one seems to have served me OK. Since the generation of Gaussian - noise is only for test purposes, and not a core system component, - I don't intend to worry excessively about copyright issues, unless - someone worries me. - - The non-core nature of this code also explains why it is unlikely - to ever be optimised. */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/saturated.h" -#include "spandsp/awgn.h" - -#include "spandsp/private/awgn.h" - -/* Random number generator constants */ -#define M1 259200 -#define IA1 7141 -#define IC1 54773 -#define RM1 (1.0/(double) M1) -#define M2 134456 -#define IA2 8121 -#define IC2 28411 -#define RM2 (1.0/(double) M2) -#define M3 243000 -#define IA3 4561 -#define IC3 51349 - -static void ran_init(awgn_state_t *s, int idum) -{ - int j; - - if (idum < 0) - idum = -idum; - s->ix1 = (IC1 + (int32_t) idum)%M1; - s->ix1 = (IA1*s->ix1 + IC1)%M1; - s->ix2 = s->ix1%M2; - s->ix1 = (IA1*s->ix1 + IC1)%M1; - s->ix3 = s->ix1%M3; - for (j = 0; j < 97; j++) - { - s->ix1 = (IA1*s->ix1 + IC1)%M1; - s->ix2 = (IA2*s->ix2 + IC2)%M2; - s->r[j] = (s->ix1 + s->ix2*RM2)*RM1; - } -} -/*- End of function --------------------------------------------------------*/ - -static double ran(awgn_state_t *s) -{ - double temp; - int j; - - /* This produces evenly spread random numbers between 0.0 and 1.0 */ - s->ix1 = (IA1*s->ix1 + IC1)%M1; - s->ix2 = (IA2*s->ix2 + IC2)%M2; - s->ix3 = (IA3*s->ix3 + IC3)%M3; - j = (97*s->ix3)/M3; - if (j > 96 || j < 0) - { - /* Error */ - temp = -1.0; - } - else - { - temp = s->r[j]; - s->r[j] = (s->ix1 + s->ix2*RM2)*RM1; - } - return temp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(awgn_state_t *) awgn_init_dbov(awgn_state_t *s, int idum, float level) -{ - if (s == NULL) - { - if ((s = (awgn_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - - ran_init(s, idum); - - s->rms = pow(10.0, level/20.0)*32768.0; - s->amp2 = 0.0; - s->odd = true; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(awgn_state_t *) awgn_init_dbm0(awgn_state_t *s, int idum, float level) -{ - return awgn_init_dbov(s, idum, level - DBM0_MAX_POWER); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) awgn_release(awgn_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) awgn_free(awgn_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) awgn(awgn_state_t *s) -{ - double r; - double v1; - double v2; - double amp; - - /* The polar method of generating a Gaussian distribution */ - if ((s->odd = !s->odd)) - { - amp = s->amp2; - } - else - { - do - { - v1 = 2.0*ran(s) - 1.0; - v2 = 2.0*ran(s) - 1.0; - r = v1*v1 + v2*v2; - } - while (r >= 1.0); - r = sqrt(-2.0*log(r)/r); - s->amp2 = v1*r; - amp = v2*r; - } - amp *= s->rms; - return fsaturate(amp); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/bell_r2_mf.c b/libs/spandsp/src/bell_r2_mf.c deleted file mode 100644 index fe106ed6d3..0000000000 --- a/libs/spandsp/src/bell_r2_mf.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bell_r2_mf.c - Bell MF and MFC/R2 tone generation and detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/fast_convert.h" -#include "spandsp/queue.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/dtmf.h" -#include "spandsp/bell_r2_mf.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/queue.h" -#include "spandsp/private/tone_generate.h" -#include "spandsp/private/bell_r2_mf.h" - -#if !defined(M_PI) -/* C99 systems may not define M_PI */ -#define M_PI 3.14159265358979323846264338327 -#endif - -/*! - MF tone descriptor. -*/ -typedef struct -{ - int f1; /* First freq */ - int f2; /* Second freq */ - int8_t level1; /* Level of the first freq (dB) */ - int8_t level2; /* Level of the second freq (dB) */ - uint8_t on_time; /* Tone on time (ms) */ - uint8_t off_time; /* Minimum post tone silence (ms) */ -} mf_digit_tones_t; - -int bell_mf_gen_inited = false; -tone_gen_descriptor_t bell_mf_digit_tones[15]; - -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]; - -#if 0 -tone_gen_descriptor_t socotel_mf_digit_tones[18]; -#endif - -/* Bell R1 tone generation specs. - * Power: -7dBm +- 1dB - * Frequency: within +-1.5% - * Mismatch between the start time of a pair of tones: <=6ms. - * Mismatch between the end time of a pair of tones: <=6ms. - * Tone duration: 68+-7ms, except KP which is 100+-7ms. - * Inter-tone gap: 68+-7ms. - */ -static const mf_digit_tones_t bell_mf_tones[] = -{ - { 700, 900, -7, -7, 68, 68}, - { 700, 1100, -7, -7, 68, 68}, - { 900, 1100, -7, -7, 68, 68}, - { 700, 1300, -7, -7, 68, 68}, - { 900, 1300, -7, -7, 68, 68}, - {1100, 1300, -7, -7, 68, 68}, - { 700, 1500, -7, -7, 68, 68}, - { 900, 1500, -7, -7, 68, 68}, - {1100, 1500, -7, -7, 68, 68}, - {1300, 1500, -7, -7, 68, 68}, - { 700, 1700, -7, -7, 68, 68}, /* ST''' - use 'C' */ - { 900, 1700, -7, -7, 68, 68}, /* ST' - use 'A' */ - {1100, 1700, -7, -7, 100, 68}, /* KP - use '*' */ - {1300, 1700, -7, -7, 68, 68}, /* ST'' - use 'B' */ - {1500, 1700, -7, -7, 68, 68}, /* ST - use '#' */ - {0, 0, 0, 0, 0, 0} -}; - -/* The order of the digits here must match the list above */ -static const char bell_mf_tone_codes[] = "1234567890CA*B#"; - -/* R2 tone generation specs. - * Power: -11.5dBm +- 1dB - * Frequency: within +-4Hz - * Mismatch between the start time of a pair of tones: <=1ms. - * Mismatch between the end time of a pair of tones: <=1ms. - */ -static const mf_digit_tones_t r2_mf_fwd_tones[] = -{ - {1380, 1500, -11, -11, 1, 0}, - {1380, 1620, -11, -11, 1, 0}, - {1500, 1620, -11, -11, 1, 0}, - {1380, 1740, -11, -11, 1, 0}, - {1500, 1740, -11, -11, 1, 0}, - {1620, 1740, -11, -11, 1, 0}, - {1380, 1860, -11, -11, 1, 0}, - {1500, 1860, -11, -11, 1, 0}, - {1620, 1860, -11, -11, 1, 0}, - {1740, 1860, -11, -11, 1, 0}, - {1380, 1980, -11, -11, 1, 0}, - {1500, 1980, -11, -11, 1, 0}, - {1620, 1980, -11, -11, 1, 0}, - {1740, 1980, -11, -11, 1, 0}, - {1860, 1980, -11, -11, 1, 0}, - {0, 0, 0, 0, 0, 0} -}; - -static const mf_digit_tones_t r2_mf_back_tones[] = -{ - {1140, 1020, -11, -11, 1, 0}, - {1140, 900, -11, -11, 1, 0}, - {1020, 900, -11, -11, 1, 0}, - {1140, 780, -11, -11, 1, 0}, - {1020, 780, -11, -11, 1, 0}, - { 900, 780, -11, -11, 1, 0}, - {1140, 660, -11, -11, 1, 0}, - {1020, 660, -11, -11, 1, 0}, - { 900, 660, -11, -11, 1, 0}, - { 780, 660, -11, -11, 1, 0}, - {1140, 540, -11, -11, 1, 0}, - {1020, 540, -11, -11, 1, 0}, - { 900, 540, -11, -11, 1, 0}, - { 780, 540, -11, -11, 1, 0}, - { 660, 540, -11, -11, 1, 0}, - {0, 0, 0, 0, 0, 0} -}; - -/* The order of the digits here must match the lists above */ -static const char r2_mf_tone_codes[] = "1234567890BCDEF"; - -#if 0 -static const mf_digit_tones_t socotel_tones[] = -{ - { 700, 900, -11, -11, 1, 0}, - { 700, 1100, -11, -11, 1, 0}, - { 900, 1100, -11, -11, 1, 0}, - { 700, 1300, -11, -11, 1, 0}, - { 900, 1300, -11, -11, 1, 0}, - {1100, 1300, -11, -11, 1, 0}, - { 700, 1500, -11, -11, 1, 0}, - { 900, 1500, -11, -11, 1, 0}, - {1100, 1500, -11, -11, 1, 0}, - {1300, 1500, -11, -11, 1, 0}, - {1500, 1700, -11, -11, 1, 0}, - { 700, 1700, -11, -11, 1, 0}, - { 900, 1700, -11, -11, 1, 0}, - {1300, 1700, -11, -11, 1, 0}, - {1100, 1700, -11, -11, 1, 0}, - {1700, 0, -11, -11, 1, 0}, /* Use 'F' */ - {1900, 0, -11, -11, 1, 0}, /* Use 'G' */ - {0, 0, 0, 0, 0, 0} -}; - -/* The order of the digits here must match the list above */ -static char socotel_mf_tone_codes[] = "1234567890ABCDEFG"; -#endif - -#if defined(SPANDSP_USE_FIXED_POINT) -#define BELL_MF_THRESHOLD 204089 /* -30.5dBm0 */ -#define BELL_MF_TWIST 3.981f /* 6dB */ -#define BELL_MF_RELATIVE_PEAK 12.589f /* 11dB */ -#define BELL_MF_SAMPLES_PER_BLOCK 120 - -#define R2_MF_THRESHOLD 62974 /* -36.5dBm0 */ -#define R2_MF_TWIST 5.012f /* 7dB */ -#define R2_MF_RELATIVE_PEAK 12.589f /* 11dB */ -#define R2_MF_SAMPLES_PER_BLOCK 133 -#else -#define BELL_MF_THRESHOLD 3343803100.0f /* -30.5dBm0 [((120.0*32768.0/1.4142)*10^((-30.5 - DBM0_MAX_SINE_POWER)/20.0))^2 => 3343803100.0] */ -#define BELL_MF_TWIST 3.981f /* 6dB [10^(6/10) => 3.981] */ -#define BELL_MF_RELATIVE_PEAK 12.589f /* 11dB */ -#define BELL_MF_SAMPLES_PER_BLOCK 120 - -#define R2_MF_THRESHOLD 1031766650.0f /* -36.5dBm0 [((133.0*32768.0/1.4142)*10^((-36.5 - DBM0_MAX_SINE_POWER)/20.0))^2 => 1031766650.0] */ -#define R2_MF_TWIST 5.012f /* 7dB */ -#define R2_MF_RELATIVE_PEAK 12.589f /* 11dB */ -#define R2_MF_SAMPLES_PER_BLOCK 133 -#endif - -static goertzel_descriptor_t bell_mf_detect_desc[6]; - -static goertzel_descriptor_t mf_fwd_detect_desc[6]; -static goertzel_descriptor_t mf_back_detect_desc[6]; - -static const int bell_mf_frequencies[] = -{ - 700, 900, 1100, 1300, 1500, 1700 -}; - -/* Use the follow characters for the Bell MF special signals: - KP - use '*' - ST - use '#' - ST' - use 'A' - ST'' - use 'B' - ST''' - use 'C' */ -static const char bell_mf_positions[] = "1247C-358A--69*---0B----#"; - -static const int r2_mf_fwd_frequencies[] = -{ - 1380, 1500, 1620, 1740, 1860, 1980 -}; - -static const int r2_mf_back_frequencies[] = -{ - 1140, 1020, 900, 780, 660, 540 -}; - -/* Use codes '1' to 'F' for the R2 signals 1 to 15, except for signal 'A'. - Use '0' for this, so the codes match the digits 0-9. */ -static const char r2_mf_positions[] = "1247B-358C--69D---0E----F"; - -static void bell_mf_gen_init(void) -{ - int i; - const mf_digit_tones_t *tones; - - if (bell_mf_gen_inited) - return; - i = 0; - tones = bell_mf_tones; - while (tones->on_time) - { - /* Note: The duration of KP is longer than the other signals. */ - tone_gen_descriptor_init(&bell_mf_digit_tones[i++], - tones->f1, - tones->level1, - tones->f2, - tones->level2, - tones->on_time, - tones->off_time, - 0, - 0, - false); - tones++; - } - bell_mf_gen_inited = true; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_tx(bell_mf_tx_state_t *s, int16_t amp[], int max_samples) -{ - int len; - const char *cp; - int digit; - - len = 0; - if (s->tones.current_section >= 0) - { - /* Deal with the fragment left over from last time */ - len = tone_gen(&s->tones, amp, max_samples); - } - while (len < max_samples && (digit = queue_read_byte(&s->queue.queue)) >= 0) - { - /* Step to the next digit */ - if ((cp = strchr(bell_mf_tone_codes, digit)) == NULL) - continue; - tone_gen_init(&s->tones, &bell_mf_digit_tones[cp - bell_mf_tone_codes]); - len += tone_gen(&s->tones, amp + len, max_samples - len); - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_tx_put(bell_mf_tx_state_t *s, const char *digits, int len) -{ - size_t space; - - /* This returns the number of characters that would not fit in the buffer. - The buffer will only be loaded if the whole string of digits will fit, - in which case zero is returned. */ - if (len < 0) - { - if ((len = strlen(digits)) == 0) - return 0; - } - if ((space = queue_free_space(&s->queue.queue)) < (size_t) len) - return len - (int) space; - if (queue_write(&s->queue.queue, (const uint8_t *) digits, len) >= 0) - return 0; - return -1; -} -/*- End of function --------------------------------------------------------*/ - -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 *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - if (!bell_mf_gen_inited) - bell_mf_gen_init(); - tone_gen_init(&s->tones, &bell_mf_digit_tones[0]); - s->current_sample = 0; - queue_init(&s->queue.queue, MAX_BELL_MF_DIGITS, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC); - s->tones.current_section = -1; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_tx_release(bell_mf_tx_state_t *s) -{ - queue_release(&s->queue.queue); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_tx_free(bell_mf_tx_state_t *s) -{ - queue_release(&s->queue.queue); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_tx(r2_mf_tx_state_t *s, int16_t amp[], int samples) -{ - int len; - - if (s->digit == 0) - { - len = samples; - memset(amp, 0, len*sizeof(int16_t)); - } - else - { - len = tone_gen(&s->tone, amp, samples); - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_tx_put(r2_mf_tx_state_t *s, char digit) -{ - char *cp; - - if (digit && (cp = strchr(r2_mf_tone_codes, digit))) - { - if (s->fwd) - tone_gen_init(&s->tone, &r2_mf_fwd_digit_tones[cp - r2_mf_tone_codes]); - else - tone_gen_init(&s->tone, &r2_mf_back_digit_tones[cp - r2_mf_tone_codes]); - s->digit = digit; - } - else - { - s->digit = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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 *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - if (!r2_mf_gen_inited) - { - i = 0; - tones = r2_mf_fwd_tones; - while (tones->on_time) - { - tone_gen_descriptor_init(&r2_mf_fwd_digit_tones[i++], - tones->f1, - tones->level1, - tones->f2, - tones->level2, - tones->on_time, - tones->off_time, - 0, - 0, - (tones->off_time == 0)); - tones++; - } - i = 0; - tones = r2_mf_back_tones; - while (tones->on_time) - { - tone_gen_descriptor_init(&r2_mf_back_digit_tones[i++], - tones->f1, - tones->level1, - tones->f2, - tones->level2, - tones->on_time, - tones->off_time, - 0, - 0, - (tones->off_time == 0)); - tones++; - } - r2_mf_gen_inited = true; - } - s->fwd = fwd; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_tx_release(r2_mf_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_tx_free(r2_mf_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_rx(bell_mf_rx_state_t *s, const int16_t amp[], int samples) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t energy[6]; - int16_t xamp; -#else - float energy[6]; - float xamp; -#endif - int i; - int j; - int sample; - int best; - int second_best; - int limit; - uint8_t hit; - - for (sample = 0; sample < samples; sample = limit) - { - if ((samples - sample) >= (BELL_MF_SAMPLES_PER_BLOCK - s->current_sample)) - limit = sample + (BELL_MF_SAMPLES_PER_BLOCK - s->current_sample); - else - limit = samples; - for (j = sample; j < limit; j++) - { - xamp = goertzel_preadjust_amp(amp[j]); - goertzel_samplex(&s->out[0], xamp); - goertzel_samplex(&s->out[1], xamp); - goertzel_samplex(&s->out[2], xamp); - goertzel_samplex(&s->out[3], xamp); - goertzel_samplex(&s->out[4], xamp); - goertzel_samplex(&s->out[5], xamp); - } - s->current_sample += (limit - sample); - if (s->current_sample < BELL_MF_SAMPLES_PER_BLOCK) - continue; - - /* We are at the end of an MF detection block */ - /* Find the two highest energies. The spec says to look for - two tones and two tones only. Taking this literally -ie - only two tones pass the minimum threshold - doesn't work - well. The sinc function mess, due to rectangular windowing - ensure that! Find the two highest energies and ensure they - are considerably stronger than any of the others. */ - energy[0] = goertzel_result(&s->out[0]); - energy[1] = goertzel_result(&s->out[1]); - if (energy[0] > energy[1]) - { - best = 0; - second_best = 1; - } - else - { - best = 1; - second_best = 0; - } - for (i = 2; i < 6; i++) - { - energy[i] = goertzel_result(&s->out[i]); - if (energy[i] >= energy[best]) - { - second_best = best; - best = i; - } - else if (energy[i] >= energy[second_best]) - { - second_best = i; - } - } - /* Basic signal level and twist tests */ - hit = 0; - if (energy[best] >= BELL_MF_THRESHOLD - && - energy[second_best] >= BELL_MF_THRESHOLD - && - energy[best] < energy[second_best]*BELL_MF_TWIST - && - energy[best]*BELL_MF_TWIST > energy[second_best]) - { - /* Relative peak test */ - hit = 'X'; - for (i = 0; i < 6; i++) - { - if (i != best && i != second_best) - { - if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best]) - { - /* The best two are not clearly the best */ - hit = 0; - break; - } - } - } - } - if (hit) - { - /* Get the values into ascending order */ - if (second_best < best) - { - i = best; - best = second_best; - second_best = i; - } - best = best*5 + second_best - 1; - hit = bell_mf_positions[best]; - /* Look for two successive similar results */ - /* The logic in the next test is: - For KP we need 4 successive identical clean detects, with - two blocks of something different preceeding it. For anything - else we need two successive identical clean detects, with - two blocks of something different preceeding it. */ - if (hit == s->hits[4] - && - hit == s->hits[3] - && - ((hit != '*' && hit != s->hits[2] && hit != s->hits[1]) - || - (hit == '*' && hit == s->hits[2] && hit != s->hits[1] && hit != s->hits[0]))) - { - if (s->current_digits < MAX_BELL_MF_DIGITS) - { - s->digits[s->current_digits++] = (char) hit; - s->digits[s->current_digits] = '\0'; - if (s->digits_callback) - { - s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); - s->current_digits = 0; - } - } - else - { - s->lost_digits++; - } - } - } - s->hits[0] = s->hits[1]; - s->hits[1] = s->hits[2]; - s->hits[2] = s->hits[3]; - s->hits[3] = s->hits[4]; - s->hits[4] = hit; - s->current_sample = 0; - } - if (s->current_digits && s->digits_callback) - { - s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); - s->digits[0] = '\0'; - s->current_digits = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) bell_mf_rx_get(bell_mf_rx_state_t *s, char *buf, int max) -{ - if (max > s->current_digits) - max = s->current_digits; - if (max > 0) - { - memcpy(buf, s->digits, max); - memmove(s->digits, s->digits + max, s->current_digits - max); - s->current_digits -= max; - } - buf[max] = '\0'; - return max; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s, - digits_rx_callback_t callback, - void *user_data) -{ - int i; - static int initialised = false; - - if (s == NULL) - { - if ((s = (bell_mf_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - if (!initialised) - { - 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; - } - s->digits_callback = callback; - s->digits_callback_data = user_data; - - s->hits[0] = - s->hits[1] = - s->hits[2] = - s->hits[3] = - s->hits[4] = 0; - - for (i = 0; i < 6; i++) - goertzel_init(&s->out[i], &bell_mf_detect_desc[i]); - s->current_sample = 0; - s->lost_digits = 0; - s->current_digits = 0; - s->digits[0] = '\0'; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_rx_release(bell_mf_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bell_mf_rx_free(bell_mf_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t energy[6]; - int16_t xamp; -#else - float energy[6]; - float xamp; -#endif - int i; - int j; - int sample; - int best; - int second_best; - int hit; - int hit_digit; - int limit; - - for (sample = 0; sample < samples; sample = limit) - { - if ((samples - sample) >= (R2_MF_SAMPLES_PER_BLOCK - s->current_sample)) - limit = sample + (R2_MF_SAMPLES_PER_BLOCK - s->current_sample); - else - limit = samples; - for (j = sample; j < limit; j++) - { - xamp = goertzel_preadjust_amp(amp[j]); - goertzel_samplex(&s->out[0], xamp); - goertzel_samplex(&s->out[1], xamp); - goertzel_samplex(&s->out[2], xamp); - goertzel_samplex(&s->out[3], xamp); - goertzel_samplex(&s->out[4], xamp); - goertzel_samplex(&s->out[5], xamp); - } - s->current_sample += (limit - sample); - if (s->current_sample < R2_MF_SAMPLES_PER_BLOCK) - continue; - - /* We are at the end of an MF detection block */ - /* Find the two highest energies */ - energy[0] = goertzel_result(&s->out[0]); - energy[1] = goertzel_result(&s->out[1]); - if (energy[0] > energy[1]) - { - best = 0; - second_best = 1; - } - else - { - best = 1; - second_best = 0; - } - - for (i = 2; i < 6; i++) - { - energy[i] = goertzel_result(&s->out[i]); - if (energy[i] >= energy[best]) - { - second_best = best; - best = i; - } - else if (energy[i] >= energy[second_best]) - { - second_best = i; - } - } - /* Basic signal level and twist tests */ - hit = false; - if (energy[best] >= R2_MF_THRESHOLD - && - energy[second_best] >= R2_MF_THRESHOLD - && - energy[best] < energy[second_best]*R2_MF_TWIST - && - energy[best]*R2_MF_TWIST > energy[second_best]) - { - /* Relative peak test */ - hit = true; - for (i = 0; i < 6; i++) - { - if (i != best && i != second_best) - { - if (energy[i]*R2_MF_RELATIVE_PEAK >= energy[second_best]) - { - /* The best two are not clearly the best */ - hit = false; - break; - } - } - } - } - if (hit) - { - /* Get the values into ascending order */ - if (second_best < best) - { - i = best; - best = second_best; - second_best = i; - } - best = best*5 + second_best - 1; - hit_digit = r2_mf_positions[best]; - } - else - { - hit_digit = 0; - } - if (s->current_digit != hit_digit && s->callback) - { - i = (hit_digit) ? -10 : -99; - s->callback(s->callback_data, hit_digit, i, 0); - } - s->current_digit = hit_digit; - s->current_sample = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_rx_get(r2_mf_rx_state_t *s) -{ - return s->current_digit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s, - bool fwd, - tone_report_func_t callback, - void *user_data) -{ - int i; - static int initialised = false; - - if (s == NULL) - { - if ((s = (r2_mf_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - s->fwd = fwd; - - if (!initialised) - { - for (i = 0; i < 6; i++) - { - 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; - } - if (fwd) - { - for (i = 0; i < 6; i++) - goertzel_init(&s->out[i], &mf_fwd_detect_desc[i]); - } - else - { - for (i = 0; i < 6; i++) - goertzel_init(&s->out[i], &mf_back_detect_desc[i]); - } - s->callback = callback; - s->callback_data = user_data; - s->current_digit = 0; - s->current_sample = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_rx_release(r2_mf_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) r2_mf_rx_free(r2_mf_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/bert.c b/libs/spandsp/src/bert.c deleted file mode 100644 index 7a4f9511bb..0000000000 --- a/libs/spandsp/src/bert.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bert.c - Bit error rate tests. - * - * 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#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" - -#include "spandsp/private/logging.h" -#include "spandsp/private/bert.h" - -#define MEASUREMENT_STEP 100 - -static const char *qbf = "VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )" - "ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )"; - -SPAN_DECLARE(const char *) bert_event_to_str(int event) -{ - switch (event) - { - case BERT_REPORT_SYNCED: - return "synced"; - case BERT_REPORT_UNSYNCED: - return "unsync'ed"; - case BERT_REPORT_REGULAR: - return "regular"; - case BERT_REPORT_GT_10_2: - return "error rate > 1 in 10^2"; - case BERT_REPORT_LT_10_2: - return "error rate < 1 in 10^2"; - case BERT_REPORT_LT_10_3: - return "error rate < 1 in 10^3"; - case BERT_REPORT_LT_10_4: - return "error rate < 1 in 10^4"; - case BERT_REPORT_LT_10_5: - return "error rate < 1 in 10^5"; - case BERT_REPORT_LT_10_6: - return "error rate < 1 in 10^6"; - case BERT_REPORT_LT_10_7: - return "error rate < 1 in 10^7"; - } - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bert_get_bit(bert_state_t *s) -{ - int bit; - - if (s->limit && s->tx.bits >= s->limit) - return SIG_STATUS_END_OF_DATA; - bit = 0; - switch (s->pattern_class) - { - case 0: - bit = s->tx.reg & 1; - s->tx.reg = (s->tx.reg >> 1) | ((s->tx.reg & 1) << s->shift2); - break; - case 1: - bit = s->tx.reg & 1; - s->tx.reg = (s->tx.reg >> 1) | (((s->tx.reg ^ (s->tx.reg >> s->shift)) & 1) << s->shift2); - if (s->max_zeros) - { - /* This generator suppresses runs >s->max_zeros */ - if (bit) - { - if (++s->tx.zeros > s->max_zeros) - { - s->tx.zeros = 0; - bit ^= 1; - } - } - else - { - s->tx.zeros = 0; - } - } - bit ^= s->invert; - break; - case 2: - if (s->tx.step_bit == 0) - { - s->tx.step_bit = 7; - s->tx.reg = qbf[s->tx.step++]; - if (s->tx.reg == 0) - { - s->tx.reg = 'V'; - s->tx.step = 1; - } - } - bit = s->tx.reg & 1; - s->tx.reg >>= 1; - s->tx.step_bit--; - break; - } - s->tx.bits++; - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static void assess_error_rate(bert_state_t *s) -{ - int i; - int j; - int sum; - 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; - for (i = 2; i <= 7; i++) - { - if (++s->decade_ptr[i] < 10) - break; - /* This decade has reached 10 snapshots, so we need to touch the next decade */ - s->decade_ptr[i] = 0; - /* Sum the last 10 snapshots from this decade, to see if we overflow into the next decade */ - for (sum = 0, j = 0; j < 10; j++) - sum += s->decade_bad[i][j]; - if (test && sum > 10) - { - /* We overflow into the next decade */ - 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; - } - s->decade_bad[i][0] = 0; - if (i < 7) - s->decade_bad[i + 1][s->decade_ptr[i + 1]] = sum; - } - if (i > 7) - { - if (s->decade_ptr[i] >= 10) - s->decade_ptr[i] = 0; - if (test) - { - 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; - } - } - else - { - s->decade_bad[i][s->decade_ptr[i]] = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) bert_put_bit(bert_state_t *s, int bit) -{ - if (bit < 0) - { - /* Special conditions */ - printf("Status is %s (%d)\n", signal_status_to_str(bit), bit); - return; - } - bit = (bit & 1) ^ s->invert; - s->rx.bits++; - switch (s->pattern_class) - { - case 0: - if (s->rx.resync) - { - s->rx.reg = (s->rx.reg >> 1) | (bit << s->shift2); - s->rx.ref_reg = (s->rx.ref_reg >> 1) | ((s->rx.ref_reg & 1) << s->shift2); - if (s->rx.reg == s->rx.ref_reg) - { - if (++s->rx.resync > s->resync_time) - { - s->rx.resync = 0; - if (s->reporter) - s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results); - } - } - else - { - s->rx.resync = 2; - s->rx.ref_reg = s->rx.master_reg; - } - } - else - { - s->results.total_bits++; - if ((bit ^ s->rx.ref_reg) & 1) - s->results.bad_bits++; - s->rx.ref_reg = (s->rx.ref_reg >> 1) | ((s->rx.ref_reg & 1) << s->shift2); - } - break; - case 1: - if (s->rx.resync) - { - /* If we get a reasonable period for which we correctly predict the - next bit, we must be in sync. */ - /* Don't worry about max. zeros tests when resyncing. - It might just extend the resync time a little. Trying - to include the test might affect robustness. */ - if (bit == (int) ((s->rx.reg >> s->shift) & 1)) - { - if (++s->rx.resync > s->resync_time) - { - s->rx.resync = 0; - if (s->reporter) - s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results); - } - } - else - { - s->rx.resync = 2; - s->rx.reg ^= s->mask; - } - } - else - { - s->results.total_bits++; - if (s->max_zeros) - { - /* This generator suppresses runs >s->max_zeros */ - if ((s->rx.reg & s->mask)) - { - if (++s->rx.zeros > s->max_zeros) - { - s->rx.zeros = 0; - bit ^= 1; - } - } - else - { - s->rx.zeros = 0; - } - } - if (bit != (int) ((s->rx.reg >> s->shift) & 1)) - { - s->results.bad_bits++; - s->rx.resync_bad_bits++; - s->decade_bad[2][s->decade_ptr[2]]++; - } - if (--s->rx.measurement_step <= 0) - { - /* Every hundred bits we need to do the error rate measurement */ - s->rx.measurement_step = MEASUREMENT_STEP; - assess_error_rate(s); - } - if (--s->rx.resync_cnt <= 0) - { - /* Check if there were enough bad bits during this period to - justify a resync. */ - if (s->rx.resync_bad_bits >= (s->rx.resync_len*s->rx.resync_percent)/100) - { - s->rx.resync = 1; - s->results.resyncs++; - if (s->reporter) - s->reporter(s->user_data, BERT_REPORT_UNSYNCED, &s->results); - } - s->rx.resync_cnt = s->rx.resync_len; - s->rx.resync_bad_bits = 0; - } - } - s->rx.reg = (s->rx.reg >> 1) | (((s->rx.reg ^ (s->rx.reg >> s->shift)) & 1) << s->shift2); - break; - case 2: - s->rx.reg = (s->rx.reg >> 1) | (bit << 6); - /* TODO: There is no mechanism for synching yet. This only works if things start in sync. */ - if (++s->rx.step_bit == 7) - { - s->rx.step_bit = 0; - if ((int) s->rx.reg != qbf[s->rx.step]) - { - /* We need to work out the number of actual bad bits here. We need to look at the - error rate, and see it a resync is needed. etc. */ - s->results.bad_bits++; - } - if (qbf[++s->rx.step] == '\0') - s->rx.step = 0; - } - s->results.total_bits++; - break; - } - if (s->report_frequency > 0) - { - if (--s->rx.report_countdown <= 0) - { - if (s->reporter) - s->reporter(s->user_data, BERT_REPORT_REGULAR, &s->results); - s->rx.report_countdown = s->report_frequency; - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bert_result(bert_state_t *s, bert_results_t *results) -{ - results->total_bits = s->results.total_bits; - results->bad_bits = s->results.bad_bits; - results->resyncs = s->results.resyncs; - return sizeof(*results); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data) -{ - s->report_frequency = freq; - s->reporter = reporter; - s->user_data = user_data; - - s->rx.report_countdown = s->report_frequency; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(bert_state_t *) bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent) -{ - int i; - int j; - - if (s == NULL) - { - if ((s = (bert_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - s->pattern = pattern; - s->limit = limit; - s->reporter = NULL; - s->user_data = NULL; - s->report_frequency = 0; - - s->resync_time = 72; - s->invert = 0; - switch (s->pattern) - { - case BERT_PATTERN_ZEROS: - s->tx.reg = 0; - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_ONES: - s->tx.reg = ~((uint32_t) 0); - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_7_TO_1: - s->tx.reg = 0xFEFEFEFE; - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_3_TO_1: - s->tx.reg = 0xEEEEEEEE; - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_1_TO_1: - s->tx.reg = 0xAAAAAAAA; - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_1_TO_3: - s->tx.reg = 0x11111111; - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_1_TO_7: - s->tx.reg = 0x01010101; - s->shift2 = 31; - s->pattern_class = 0; - break; - case BERT_PATTERN_QBF: - s->tx.reg = 0; - s->pattern_class = 2; - break; - case BERT_PATTERN_ITU_O151_23: - s->pattern_class = 1; - s->tx.reg = 0x7FFFFF; - s->mask = 0x20; - s->shift = 5; - s->shift2 = 22; - s->invert = 1; - s->resync_time = 56; - s->max_zeros = 0; - break; - case BERT_PATTERN_ITU_O151_20: - s->pattern_class = 1; - s->tx.reg = 0xFFFFF; - s->mask = 0x8; - s->shift = 3; - s->shift2 = 19; - s->invert = 1; - s->resync_time = 50; - s->max_zeros = 14; - break; - case BERT_PATTERN_ITU_O151_15: - s->pattern_class = 1; - s->tx.reg = 0x7FFF; - s->mask = 0x2; - s->shift = 1; - s->shift2 = 14; - s->invert = 1; - s->resync_time = 40; - s->max_zeros = 0; - break; - case BERT_PATTERN_ITU_O152_11: - s->pattern_class = 1; - s->tx.reg = 0x7FF; - s->mask = 0x4; - s->shift = 2; - s->shift2 = 10; - s->invert = 0; - s->resync_time = 32; - s->max_zeros = 0; - break; - case BERT_PATTERN_ITU_O153_9: - s->pattern_class = 1; - s->tx.reg = 0x1FF; - s->mask = 0x10; - s->shift = 4; - s->shift2 = 8; - s->invert = 0; - s->resync_time = 28; - s->max_zeros = 0; - break; - } - s->tx.bits = 0; - s->tx.step = 0; - s->tx.step_bit = 0; - s->tx.zeros = 0; - - s->rx.reg = s->tx.reg; - s->rx.ref_reg = s->rx.reg; - s->rx.master_reg = s->rx.ref_reg; - s->rx.bits = 0; - s->rx.step = 0; - s->rx.step_bit = 0; - - s->rx.resync = 1; - s->rx.resync_cnt = resync_len; - s->rx.resync_bad_bits = 0; - s->rx.resync_len = resync_len; - s->rx.resync_percent = resync_percent; - - s->results.total_bits = 0; - s->results.bad_bits = 0; - s->results.resyncs = 0; - - s->rx.report_countdown = 0; - - for (i = 0; i < 8; i++) - { - for (j = 0; j < 10; j++) - s->decade_bad[i][j] = 0; - s->decade_ptr[i] = 0; - } - s->error_rate = 8; - s->rx.measurement_step = MEASUREMENT_STEP; - - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "BERT"); - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bert_release(bert_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bert_free(bert_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/bit_operations.c b/libs/spandsp/src/bit_operations.c deleted file mode 100644 index a301c03ec2..0000000000 --- a/libs/spandsp/src/bit_operations.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bit_operations.c - Various bit level operations, such as bit reversal - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 -#include -#include - -#include "spandsp/telephony.h" -#include "spandsp/bit_operations.h" - -SPAN_DECLARE(uint16_t) bit_reverse16(uint16_t x) -{ - x = (x >> 8) | (x << 8); - x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4); - x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2); - return ((x & 0xAAAA) >> 1) | ((x & 0x5555) << 1); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) bit_reverse32(uint32_t x) -{ - x = (x >> 16) | (x << 16); - x = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); - x = ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4); - x = ((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2); - return ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) bit_reverse_4bytes(uint32_t x) -{ - x = ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4); - x = ((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2); - return ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__x86_64__) -SPAN_DECLARE(uint64_t) bit_reverse_8bytes(uint64_t x) -{ - x = ((x & 0xF0F0F0F0F0F0F0F0LLU) >> 4) | ((x & 0x0F0F0F0F0F0F0F0FLLU) << 4); - x = ((x & 0xCCCCCCCCCCCCCCCCLLU) >> 2) | ((x & 0x3333333333333333LLU) << 2); - return ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1) | ((x & 0x5555555555555555LLU) << 1); -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(void) bit_reverse(uint8_t to[], const uint8_t from[], int len) -{ -#if defined(SPANDSP_MISALIGNED_ACCESS_FAILS) - int i; -#else - const uint8_t *y1; - uint8_t *z1; - const uint32_t *y4; - uint32_t *z4; - uint32_t x4; -#if defined(__x86_64__) - const uint64_t *y8; - uint64_t *z8; - uint64_t x8; -#endif -#endif - -#if defined(SPANDSP_MISALIGNED_ACCESS_FAILS) - /* This code works byte by byte, so it works on machines where misalignment - is either desperately slow (its a bit slow on practically any machine, but - some machines make it desparately slow) or fails. */ - for (i = 0; i < len; i++) - to[i] = bit_reverse8(from[i]); -#else - /* This code is this is based on the woolly assumption that the start of the buffers - is memory aligned. If it isn't, the routine will be less efficient on some machines, - but might not work at all on others. */ -#if defined(__x86_64__) - y8 = (const uint64_t *) from; - z8 = (uint64_t *) to; - while (len >= sizeof(uint64_t)) - { - x8 = *y8++; - x8 = ((x8 & 0xF0F0F0F0F0F0F0F0LLU) >> 4) | ((x8 & 0x0F0F0F0F0F0F0F0FLLU) << 4); - x8 = ((x8 & 0xCCCCCCCCCCCCCCCCLLU) >> 2) | ((x8 & 0x3333333333333333LLU) << 2); - *z8++ = ((x8 & 0xAAAAAAAAAAAAAAAALLU) >> 1) | ((x8 & 0x5555555555555555LLU) << 1); - len -= sizeof(uint64_t); - } - y4 = (const uint32_t *) y8; - z4 = (uint32_t *) z8; -#else - y4 = (const uint32_t *) from; - z4 = (uint32_t *) to; -#endif - while (len >= sizeof(uint32_t)) - { - x4 = *y4++; - x4 = ((x4 & 0xF0F0F0F0) >> 4) | ((x4 & 0x0F0F0F0F) << 4); - x4 = ((x4 & 0xCCCCCCCC) >> 2) | ((x4 & 0x33333333) << 2); - *z4++ = ((x4 & 0xAAAAAAAA) >> 1) | ((x4 & 0x55555555) << 1); - len -= sizeof(uint32_t); - } - y1 = (const uint8_t *) y4; - z1 = (uint8_t *) z4; - while (len-- > 0) - *z1++ = bit_reverse8(*y1++); -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) one_bits32(uint32_t x) -{ - x = x - ((x >> 1) & 0x55555555); - /* We now have 16 2-bit counts */ - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - /* We now have 8 4-bit counts */ - x = (x + (x >> 4)) & 0x0F0F0F0F; - /* We now have 4 8-bit counts */ -#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) - /* If multiply is fast */ - return (x*0x01010101) >> 24; -#else - /* If multiply is slow */ - x += (x >> 8); - x += (x >> 16); - return (x & 0x0000003F); -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) make_mask32(uint32_t x) -{ - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return x; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) make_mask16(uint16_t x) -{ - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - return x; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/bitstream.c b/libs/spandsp/src/bitstream.c deleted file mode 100644 index 6c0b9dde4b..0000000000 --- a/libs/spandsp/src/bitstream.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bitstream.c - Bitstream composition and decomposition routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_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" - -SPAN_DECLARE(void) bitstream_put(bitstream_state_t *s, uint8_t **c, uint32_t value, int bits) -{ - value &= ((1 << bits) - 1); - if (s->lsb_first) - { - if (s->residue + bits <= 32) - { - s->bitstream |= (value << s->residue); - s->residue += bits; - } - while (s->residue >= 8) - { - s->residue -= 8; - *(*c)++ = (uint8_t) (s->bitstream & 0xFF); - s->bitstream >>= 8; - } - } - else - { - if (s->residue + bits <= 32) - { - s->bitstream = (s->bitstream << bits) | value; - s->residue += bits; - } - while (s->residue >= 8) - { - s->residue -= 8; - *(*c)++ = (uint8_t) ((s->bitstream >> s->residue) & 0xFF); - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) bitstream_emit(bitstream_state_t *s, uint8_t **c) -{ - uint32_t bitstream; - - if (s->residue > 0) - { - bitstream = s->bitstream & ((1 << s->residue) - 1); - if (s->lsb_first) - *(*c) = (uint8_t) bitstream; - else - *(*c) = (uint8_t) (bitstream << (8 - s->residue)); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) bitstream_flush(bitstream_state_t *s, uint8_t **c) -{ - if (s->residue > 0) - { - bitstream_emit(s, c); - (*c)++; - s->residue = 0; - } - s->bitstream = 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits) -{ - uint32_t x; - - if (s->lsb_first) - { - while (s->residue < bits) - { - s->bitstream |= (((uint32_t) *(*c)++) << s->residue); - s->residue += 8; - } - s->residue -= bits; - x = s->bitstream & ((1 << bits) - 1); - s->bitstream >>= bits; - } - else - { - while (s->residue < bits) - { - s->bitstream = (s->bitstream << 8) | ((uint32_t) *(*c)++); - s->residue += 8; - } - s->residue -= bits; - x = (s->bitstream >> s->residue) & ((1 << bits) - 1); - } - return x; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(bitstream_state_t *) bitstream_init(bitstream_state_t *s, int lsb_first) -{ - if (s == NULL) - { - if ((s = (bitstream_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - s->bitstream = 0; - s->residue = 0; - s->lsb_first = lsb_first; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bitstream_release(bitstream_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) bitstream_free(bitstream_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/complex_filters.c b/libs/spandsp/src/complex_filters.c deleted file mode 100644 index 22cf4ac9b8..0000000000 --- a/libs/spandsp/src/complex_filters.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_filters.c - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/complex.h" -#include "spandsp/complex_filters.h" - -SPAN_DECLARE(filter_t *) filter_create(fspec_t *fs) -{ - int i; - filter_t *fi; - - if ((fi = (filter_t *) span_alloc(sizeof(*fi) + sizeof(float)*(fs->np + 1)))) - { - fi->fs = fs; - fi->sum = 0.0; - /* Moving average filters only */ - fi->ptr = 0; - for (i = 0; i <= fi->fs->np; i++) - fi->v[i] = 0.0; - } - return fi; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) filter_delete(filter_t *fi) -{ - if (fi) - span_free(fi); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) filter_step(filter_t *fi, float x) -{ - return fi->fs->fsf(fi, x); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(cfilter_t *) cfilter_create(fspec_t *fs) -{ - cfilter_t *cfi; - - if ((cfi = (cfilter_t *) span_alloc(sizeof(*cfi)))) - { - if ((cfi->ref = filter_create(fs)) == NULL) - { - span_free(cfi); - return NULL; - } - if ((cfi->imf = filter_create(fs)) == NULL) - { - span_free(cfi->ref); - span_free(cfi); - return NULL; - } - } - return cfi; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) cfilter_delete(cfilter_t *cfi) -{ - if (cfi) - { - filter_delete(cfi->ref); - filter_delete(cfi->imf); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) cfilter_step(cfilter_t *cfi, const complexf_t *z) -{ - complexf_t cc; - - cc.re = filter_step(cfi->ref, z->re); - cc.im = filter_step(cfi->imf, z->im); - return cc; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/complex_vector_float.c b/libs/spandsp/src/complex_vector_float.c deleted file mode 100644 index 710cbef435..0000000000 --- a/libs/spandsp/src/complex_vector_float.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_float.c - Floating complex vector arithmetic routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 "mmx_sse_decs.h" - -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE3) -SPAN_DECLARE(void) cvec_mulf(complexf_t z[], const complexf_t x[], const complexf_t y[], int n) -{ - int i; - __m128 n0; - __m128 n1; - __m128 n2; - __m128 n3; - - if ((i = n & ~1)) - { - i <<= 1; - for (i -= 4; i >= 0; i -= 4) - { - n3 = _mm_loadu_ps((float *) x + i); - n0 = _mm_moveldup_ps(n3); - n1 = _mm_loadu_ps((float *) y + i); - n0 = _mm_mul_ps(n0, n1); - n1 = _mm_shuffle_ps(n1, n1, 0xB1); - n2 = _mm_movehdup_ps(n3); - n2 = _mm_mul_ps(n2, n1); - n0 = _mm_addsub_ps(n0, n2); - _mm_storeu_ps((float *) z + i, n0); - } - } - /* Now deal with the last element, which doesn't fill an SSE2 register */ - switch (n & 1) - { - case 1: - z[n - 1].re = x[n - 1].re*y[n - 1].re - x[n - 1].im*y[n - 1].im; - z[n - 1].im = x[n - 1].re*y[n - 1].im + x[n - 1].im*y[n - 1].re; - } -} -#else -SPAN_DECLARE(void) cvec_mulf(complexf_t z[], const complexf_t x[], const complexf_t y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - { - z[i].re = x[i].re*y[i].re - x[i].im*y[i].im; - z[i].im = x[i].re*y[i].im + x[i].im*y[i].re; - } -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) cvec_mul(complex_t z[], const complex_t x[], const complex_t y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - { - z[i].re = x[i].re*y[i].re - x[i].im*y[i].im; - z[i].im = x[i].re*y[i].im + x[i].im*y[i].re; - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) cvec_mull(complexl_t z[], const complexl_t x[], const complexl_t y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - { - z[i].re = x[i].re*y[i].re - x[i].im*y[i].im; - z[i].im = x[i].re*y[i].im + x[i].im*y[i].re; - } -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(complexf_t) cvec_dot_prodf(const complexf_t x[], const complexf_t y[], int n) -{ - int i; - complexf_t z; - - z = complex_setf(0.0f, 0.0f); - for (i = 0; i < n; i++) - { - z.re += (x[i].re*y[i].re - x[i].im*y[i].im); - z.im += (x[i].re*y[i].im + x[i].im*y[i].re); - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complex_t) cvec_dot_prod(const complex_t x[], const complex_t y[], int n) -{ - int i; - complex_t z; - - z = complex_set(0.0, 0.0); - for (i = 0; i < n; i++) - { - z.re += (x[i].re*y[i].re - x[i].im*y[i].im); - z.im += (x[i].re*y[i].im + x[i].im*y[i].re); - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(complexl_t) cvec_dot_prodl(const complexl_t x[], const complexl_t y[], int n) -{ - int i; - complexl_t z; - - z = complex_setl(0.0L, 0.0L); - for (i = 0; i < n; i++) - { - z.re += (x[i].re*y[i].re - x[i].im*y[i].im); - z.im += (x[i].re*y[i].im + x[i].im*y[i].re); - } - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(complexf_t) cvec_circular_dot_prodf(const complexf_t x[], const complexf_t y[], int n, int pos) -{ - complexf_t z; - complexf_t z1; - - z = cvec_dot_prodf(&x[pos], &y[0], n - pos); - z1 = cvec_dot_prodf(&x[0], &y[n - pos], pos); - z = complex_addf(&z, &z1); - return z; -} -/*- End of function --------------------------------------------------------*/ - -#define LMS_LEAK_RATE 0.9999f - -SPAN_DECLARE(void) cvec_lmsf(const complexf_t x[], complexf_t y[], int n, const complexf_t *error) -{ - int i; - - for (i = 0; i < n; i++) - { - /* Leak a little to tame uncontrolled wandering */ - y[i].re = y[i].re*LMS_LEAK_RATE + (x[i].im*error->im + x[i].re*error->re); - y[i].im = y[i].im*LMS_LEAK_RATE + (x[i].re*error->im - x[i].im*error->re); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) cvec_circular_lmsf(const complexf_t x[], complexf_t y[], int n, int pos, const complexf_t *error) -{ - cvec_lmsf(&x[pos], &y[0], n - pos, error); - cvec_lmsf(&x[0], &y[n - pos], pos, error); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/complex_vector_int.c b/libs/spandsp/src/complex_vector_int.c deleted file mode 100644 index 66a0cd62cd..0000000000 --- a/libs/spandsp/src/complex_vector_int.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_int.c - Integer complex vector arithmetic routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 "mmx_sse_decs.h" - -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" - -SPAN_DECLARE(complexi32_t) cvec_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n) -{ - int i; - complexi32_t z; - - z = complex_seti32(0, 0); - for (i = 0; i < n; i++) - { - z.re += ((int32_t) x[i].re*(int32_t) y[i].re - (int32_t) x[i].im*(int32_t) y[i].im); - z.im += ((int32_t) x[i].re*(int32_t) y[i].im + (int32_t) x[i].im*(int32_t) y[i].re); - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi32_t) cvec_dot_prodi32(const complexi32_t x[], const complexi32_t y[], int n) -{ - int i; - complexi32_t z; - - z = complex_seti32(0, 0); - for (i = 0; i < n; i++) - { - z.re += (x[i].re*y[i].re - x[i].im*y[i].im); - z.im += (x[i].re*y[i].im + x[i].im*y[i].re); - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi32_t) cvec_circular_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n, int pos) -{ - complexi32_t z; - complexi32_t z1; - - z = cvec_dot_prodi16(&x[pos], &y[0], n - pos); - z1 = cvec_dot_prodi16(&x[0], &y[n - pos], pos); - z = complex_addi32(&z, &z1); - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) cvec_lmsi16(const complexi16_t x[], complexi16_t y[], int n, const complexi16_t *error) -{ - int i; - - for (i = 0; i < n; i++) - { - y[i].re += (int16_t) (((int32_t) x[i].im*(int32_t) error->im + (int32_t) x[i].re*(int32_t) error->re) >> 12); - y[i].im += (int16_t) (((int32_t) x[i].re*(int32_t) error->im - (int32_t) x[i].im*(int32_t) error->re) >> 12); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) cvec_circular_lmsi16(const complexi16_t x[], complexi16_t y[], int n, int pos, const complexi16_t *error) -{ - cvec_lmsi16(&x[pos], &y[0], n - pos, error); - cvec_lmsi16(&x[0], &y[n - pos], pos, error); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/crc.c b/libs/spandsp/src/crc.c deleted file mode 100644 index cf4dd0cd0f..0000000000 --- a/libs/spandsp/src/crc.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * crc.c - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif - -#include "spandsp/telephony.h" -#include "spandsp/crc.h" -#include "spandsp/bit_operations.h" - -static const uint32_t crc_itu32_table[] = -{ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -SPAN_DECLARE(uint32_t) crc_itu32_calc(const uint8_t *buf, int len, uint32_t crc) -{ - int i; - - for (i = 0; i < len; i++) - crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_itu32_table[(crc ^ buf[i]) & 0xFF]; - return crc; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) crc_itu32_append(uint8_t *buf, int len) -{ - uint32_t crc; - int new_len; - int i; - - crc = 0xFFFFFFFF; - new_len = len + 4; - for (i = 0; i < len; i++) - crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_itu32_table[(crc ^ buf[i]) & 0xFF]; - crc ^= 0xFFFFFFFF; - buf[i++] = (uint8_t) crc; - buf[i++] = (uint8_t) (crc >> 8); - buf[i++] = (uint8_t) (crc >> 16); - buf[i++] = (uint8_t) (crc >> 24); - return new_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(bool) crc_itu32_check(const uint8_t *buf, int len) -{ - uint32_t crc; - int i; - - crc = 0xFFFFFFFF; - for (i = 0; i < len; i++) - crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_itu32_table[(crc ^ buf[i]) & 0xFF]; - return (crc == 0xDEBB20E3); -} -/*- End of function --------------------------------------------------------*/ - -static const uint16_t crc_itu16_table[] = -{ - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -}; - -SPAN_DECLARE(uint16_t) crc_itu16_calc(const uint8_t *buf, int len, uint16_t crc) -{ - int i; - - for (i = 0; i < len; i++) - crc = (crc >> 8) ^ crc_itu16_table[(crc ^ buf[i]) & 0xFF]; - return crc; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) crc_itu16_bits(uint8_t buf, int len, uint16_t crc) -{ - int i; - - for (i = 0; i < len; i++) - { - if (((buf ^ crc) & 1)) - crc = (crc >> 1) ^ 0x8408; - else - crc = crc >> 1; - buf >>= 1; - } - return crc; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) crc_itu16_append(uint8_t *buf, int len) -{ - uint16_t crc; - int new_len; - int i; - - crc = 0xFFFF; - new_len = len + 2; - for (i = 0; i < len; i++) - crc = (crc >> 8) ^ crc_itu16_table[(crc ^ buf[i]) & 0xFF]; - crc ^= 0xFFFF; - buf[i++] = (uint8_t) crc; - buf[i++] = (uint8_t) (crc >> 8); - return new_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(bool) crc_itu16_check(const uint8_t *buf, int len) -{ - uint16_t crc; - int i; - - crc = 0xFFFF; - for (i = 0; i < len; i++) - crc = (crc >> 8) ^ crc_itu16_table[(crc ^ buf[i]) & 0xFF]; - return (crc & 0xFFFF) == 0xF0B8; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/data_modems.c b/libs/spandsp/src/data_modems.c deleted file mode 100644 index 3c0ee3e9c3..0000000000 --- a/libs/spandsp/src/data_modems.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * data_modems.c - the analogue modem set for data processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2005, 2006, 2008, 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 "floating_fudge.h" -#include -#include -#include -#if defined(LOG_FAX_AUDIO) -#include -#endif - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/dc_restore.h" -#include "spandsp/queue.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/at_interpreter.h" -#include "spandsp/silence_gen.h" -#include "spandsp/fsk.h" -#include "spandsp/v29rx.h" -#include "spandsp/v22bis.h" -#if defined(SPANDSP_SUPPORT_V32BIS) -#include "spandsp/v17tx.h" -#include "spandsp/v17rx.h" -#include "spandsp/modem_echo.h" -#include "spandsp/v32bis.h" -#endif -#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/hdlc.h" -#include "spandsp/v42.h" -#include "spandsp/v42bis.h" -#include "spandsp/v8.h" -#include "spandsp/data_modems.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/at_interpreter.h" -#include "spandsp/private/silence_gen.h" -#include "spandsp/private/power_meter.h" -#include "spandsp/private/fsk.h" -#include "spandsp/private/v22bis.h" -#if defined(SPANDSP_SUPPORT_V32BIS) -#include "spandsp/private/v17tx.h" -#include "spandsp/private/v17rx.h" -#include "spandsp/private/modem_echo.h" -#include "spandsp/private/v32bis.h" -#endif -#if defined(SPANDSP_SUPPORT_V34) -#include "spandsp/private/bitstream.h" -#include "spandsp/private/v34.h" -#endif -#include "spandsp/private/modem_connect_tones.h" -#include "spandsp/private/hdlc.h" -#include "spandsp/private/v42.h" -#include "spandsp/private/v42bis.h" -#include "spandsp/private/v8.h" -#include "spandsp/private/async.h" -#include "spandsp/private/data_modems.h" - -SPAN_DECLARE(const char *) data_modems_modulation_to_str(int modulation_scheme) -{ - switch (modulation_scheme) - { - case DATA_MODEM_NONE: - return "None"; - case DATA_MODEM_FLUSH: - return "Flush"; - case DATA_MODEM_SILENCE: - return "Silence"; - case DATA_MODEM_CED_TONE: - return "CED"; - case DATA_MODEM_CNG_TONE: - return "CNG"; - case DATA_MODEM_V8: - return "V.8"; - case DATA_MODEM_BELL103: - return "B103 duplex"; - case DATA_MODEM_BELL202: - return "B202 duplex"; - case DATA_MODEM_V21: - return "V.21 duplex"; - case DATA_MODEM_V23: - return "V.23 duplex"; - case DATA_MODEM_V22BIS: - return "V.22/V.22bis duplex"; - case DATA_MODEM_V32BIS: - return "V.32/V.32bis duplex"; - case DATA_MODEM_V34: - return "V.34 duplex"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) data_modems_get_logging_state(data_modems_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) data_modems_call_event(data_modems_state_t *s, int event) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Call event %s (%d) received\n", at_call_state_to_str(event), event); - at_call_event(&s->at_state, event); -} -/*- End of function --------------------------------------------------------*/ - -static int async_get_byte(void *user_data) -{ - data_modems_state_t *s; - uint8_t msg[1]; - - s = (data_modems_state_t *) user_data; - s->get_msg(s->user_data, msg, 1); - return msg[0]; -} -/*- End of function --------------------------------------------------------*/ - -static void async_put_byte(void *user_data, int byte) -{ - data_modems_state_t *s; - uint8_t msg[1]; - - s = (data_modems_state_t *) user_data; - msg[0] = byte; - if (byte < 0) - s->put_msg(s->user_data, msg, byte); - /*endif*/ - s->put_msg(s->user_data, msg, 1); -} -/*- End of function --------------------------------------------------------*/ - -static void tone_callback(void *user_data, int tone, int level, int delay) -{ - printf("%s declared (%ddBm0)\n", modem_connect_tone_to_str(tone), level); -} -/*- End of function --------------------------------------------------------*/ - -static void log_supported_modulations(data_modems_state_t *s, int modulation_schemes) -{ - const char *comma; - int i; - - comma = ""; - span_log(&s->logging, SPAN_LOG_FLOW, " "); - for (i = 0; i < 32; i++) - { - if ((modulation_schemes & (1 << i))) - { - span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s%s", comma, v8_modulation_to_str(modulation_schemes & (1 << i))); - comma = ", "; - } - /*endif*/ - } - /*endfor*/ - span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " supported\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void v8_handler(void *user_data, v8_parms_t *result) -{ - data_modems_state_t *s; - - s = (data_modems_state_t *) user_data; - switch (result->status) - { - case V8_STATUS_IN_PROGRESS: - span_log(&s->logging, SPAN_LOG_FLOW, "V.8 negotiation in progress\n"); - return; - case V8_STATUS_V8_OFFERED: - span_log(&s->logging, SPAN_LOG_FLOW, "V.8 offered by the other party\n"); - break; - case V8_STATUS_V8_CALL: - span_log(&s->logging, SPAN_LOG_FLOW, "V.8 call negotiation successful\n"); - break; - case V8_STATUS_NON_V8_CALL: - span_log(&s->logging, SPAN_LOG_FLOW, "Non-V.8 call negotiation successful\n"); - break; - case V8_STATUS_FAILED: - span_log(&s->logging, SPAN_LOG_FLOW, "V.8 call negotiation failed\n"); - return; - default: - span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected V.8 status %d\n", result->status); - break; - } - /*endswitch*/ - - span_log(&s->logging, SPAN_LOG_FLOW, " Modem connect tone '%s' (%d)\n", modem_connect_tone_to_str(result->modem_connect_tone), result->modem_connect_tone); - span_log(&s->logging, SPAN_LOG_FLOW, " Call function '%s' (%d)\n", v8_call_function_to_str(result->call_function), result->call_function); - span_log(&s->logging, SPAN_LOG_FLOW, " Far end modulations 0x%X\n", result->modulations); - log_supported_modulations(s, result->modulations); - span_log(&s->logging, SPAN_LOG_FLOW, " Protocol '%s' (%d)\n", v8_protocol_to_str(result->protocol), result->protocol); - span_log(&s->logging, SPAN_LOG_FLOW, " PSTN access '%s' (%d)\n", v8_pstn_access_to_str(result->pstn_access), result->pstn_access); - span_log(&s->logging, SPAN_LOG_FLOW, " PCM modem availability '%s' (%d)\n", v8_pcm_modem_availability_to_str(result->pcm_modem_availability), result->pcm_modem_availability); - if (result->t66 >= 0) - span_log(&s->logging, SPAN_LOG_FLOW, " T.66 '%s' (%d)\n", v8_t66_to_str(result->t66), result->t66); - /*endif*/ - if (result->nsf >= 0) - span_log(&s->logging, SPAN_LOG_FLOW, " NSF %d\n", result->nsf); - /*endif*/ - - switch (result->status) - { - case V8_STATUS_V8_OFFERED: - /* V.8 mode has been offered. */ - span_log(&s->logging, SPAN_LOG_FLOW, " Offered\n"); - /* We now need to edit the offered list of usable modem modulations to reflect - the set of modulations both ends share */ - //result->call_function = V8_CALL_T30_TX; - result->modulations &= (V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 -#if defined(SPANDSP_SUPPORT_V32BIS) - | V8_MOD_V32 -#endif -#if defined(SPANDSP_SUPPORT_V34) - | V8_MOD_V34 -#endif - | 0); - span_log(&s->logging, SPAN_LOG_FLOW, " Mutual modulations 0x%X\n", result->modulations); - log_supported_modulations(s, result->modulations); - break; - case V8_STATUS_V8_CALL: - span_log(&s->logging, SPAN_LOG_FLOW, " Call\n"); - if (result->call_function == V8_CALL_V_SERIES) - { - /* Negotiations OK */ - if (result->protocol == V8_PROTOCOL_LAPM_V42) - { - } - /*endif*/ - -#if defined(SPANDSP_SUPPORT_V34) - if ((result->modulations & V8_MOD_V34)) - { - s->queued_baud_rate = 2400; - s->queued_bit_rate = 28800; - s->queued_modem = DATA_MODEM_V34; - } - else -#endif -#if defined(SPANDSP_SUPPORT_V32BIS) - if ((result->modulations & V8_MOD_V32)) - { - s->queued_baud_rate = 2400; - s->queued_bit_rate = 14400; - s->queued_modem = DATA_MODEM_V32BIS; - } - else -#endif - if ((result->modulations & V8_MOD_V22)) - { - s->queued_baud_rate = 600; - s->queued_bit_rate = 2400; - s->queued_modem = DATA_MODEM_V22BIS; - } - else if ((result->modulations & V8_MOD_V21)) - { - s->queued_baud_rate = 300; - s->queued_bit_rate = 300; - s->queued_modem = DATA_MODEM_V21; - } - else - { - s->queued_modem = DATA_MODEM_NONE; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, " Negotiated modulation '%s' %d\n", data_modems_modulation_to_str(s->queued_modem), s->queued_modem); - } - /*endif*/ - break; - case V8_STATUS_NON_V8_CALL: - span_log(&s->logging, SPAN_LOG_FLOW, " Non-V.8 call\n"); - s->queued_modem = DATA_MODEM_V22BIS; - break; - default: - span_log(&s->logging, SPAN_LOG_FLOW, " Huh? %d\n", result->status); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) data_modems_set_async_mode(data_modems_state_t *s, - int data_bits, - int parity_bit, - int stop_bits) -{ - async_tx_init(&s->async_tx, - data_bits, - parity_bit, - stop_bits, - s->use_v14, - &async_get_byte, - s); - async_rx_init(&s->async_rx, - data_bits, - parity_bit, - stop_bits, - s->use_v14, - &async_put_byte, - s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which, int baud_rate, int bit_rate) -{ - const fsk_spec_t *fsk_rx_spec; - const fsk_spec_t *fsk_tx_spec; - v8_parms_t v8_parms; - logging_state_t *logging; - int level; - - switch (which) - { - case DATA_MODEM_SILENCE: - s->rx_handler = (span_rx_handler_t) &span_dummy_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &span_dummy_rx_fillin; - s->rx_user_data = NULL; - s->tx_handler = (span_tx_handler_t) &silence_gen; - s->tx_user_data = &s->modems.silence_gen; - silence_gen_init(&s->modems.silence_gen, 0); - break; - case DATA_MODEM_CNG_TONE: - s->rx_handler = (span_rx_handler_t) &modem_connect_tones_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &span_dummy_rx_fillin; - s->rx_user_data = &s->modems.tones.rx; - s->tx_handler = (span_tx_handler_t) &modem_connect_tones_tx; - s->tx_user_data = &s->modems.tones.tx; - modem_connect_tones_rx_init(&s->modems.tones.rx, - MODEM_CONNECT_TONES_FAX_CNG, - tone_callback, - s); - modem_connect_tones_tx_init(&s->modems.tones.tx, MODEM_CONNECT_TONES_FAX_CNG); - break; - case DATA_MODEM_V8: - s->rx_handler = (span_rx_handler_t) &v8_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &span_dummy_rx_fillin; - s->rx_user_data = &s->modems.v8; - s->tx_handler = (span_tx_handler_t) &v8_tx; - s->tx_user_data = &s->modems.v8; - if (s->calling_party) - v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - else - v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - /*endif*/ - v8_parms.send_ci = false; - v8_parms.v92 = -1; - v8_parms.call_function = V8_CALL_V_SERIES; -#if 0 - v8_parms.modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V27TER - | V8_MOD_V29 -#if defined(SPANDSP_SUPPORT_V34) - | V8_MOD_V34HDX -#endif - | 0; - v8_parms.protocol = V8_PROTOCOL_LAPM_V42; -#elif 1 - v8_parms.modulations = V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 -#if defined(SPANDSP_SUPPORT_V32BIS) - | V8_MOD_V32 -#endif -#if defined(SPANDSP_SUPPORT_V34) - | V8_MOD_V34 -#endif - | 0; - v8_parms.protocol = V8_PROTOCOL_LAPM_V42; -#endif - v8_parms.pcm_modem_availability = 0; - v8_parms.pstn_access = 0; - v8_parms.nsf = -1; - v8_parms.t66 = -1; - v8_init(&s->modems.v8, s->calling_party, &v8_parms, v8_handler, (void *) s); - logging = v8_get_logging_state(&s->modems.v8); - level = span_log_get_level(&s->logging); - span_log_set_level(logging, level); - span_log_set_tag(logging, "V.8"); - break; - case DATA_MODEM_BELL103: - s->rx_handler = (span_rx_handler_t) &fsk_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin; - s->rx_user_data = &s->modems.fsk.rx; - s->tx_handler = (span_tx_handler_t) &fsk_tx; - s->tx_user_data = &s->modems.fsk.tx; - if (s->calling_party) - { - fsk_rx_spec = &preset_fsk_specs[FSK_BELL103CH2]; - fsk_tx_spec = &preset_fsk_specs[FSK_BELL103CH1]; - } - else - { - fsk_rx_spec = &preset_fsk_specs[FSK_BELL103CH1]; - fsk_tx_spec = &preset_fsk_specs[FSK_BELL103CH2]; - } - /*endif*/ - fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data); - fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data); - break; - case DATA_MODEM_V21: - s->rx_handler = (span_rx_handler_t) &fsk_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin; - s->rx_user_data = &s->modems.fsk.rx; - s->tx_handler = (span_tx_handler_t) &fsk_tx; - s->tx_user_data = &s->modems.fsk.tx; - if (s->calling_party) - { - fsk_rx_spec = &preset_fsk_specs[FSK_V21CH2]; - fsk_tx_spec = &preset_fsk_specs[FSK_V21CH1]; - } - else - { - fsk_rx_spec = &preset_fsk_specs[FSK_V21CH1]; - fsk_tx_spec = &preset_fsk_specs[FSK_V21CH2]; - } - /*endif*/ - fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data); - fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data); - break; - case DATA_MODEM_BELL202: - s->rx_handler = (span_rx_handler_t) &fsk_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin; - s->rx_user_data = &s->modems.fsk.rx; - s->tx_handler = (span_tx_handler_t) &fsk_tx; - s->tx_user_data = &s->modems.fsk.tx; - fsk_rx_spec = &preset_fsk_specs[FSK_BELL202]; - fsk_tx_spec = &preset_fsk_specs[FSK_BELL202]; - fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data); - fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data); - break; - case DATA_MODEM_V23: - s->rx_handler = (span_rx_handler_t) &fsk_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &fsk_rx_fillin; - s->rx_user_data = &s->modems.fsk.rx; - s->tx_handler = (span_tx_handler_t) &fsk_tx; - s->tx_user_data = &s->modems.fsk.tx; - if (s->calling_party) - { - fsk_rx_spec = &preset_fsk_specs[FSK_V23CH2]; - fsk_tx_spec = &preset_fsk_specs[FSK_V23CH1]; - } - else - { - fsk_rx_spec = &preset_fsk_specs[FSK_V23CH1]; - fsk_tx_spec = &preset_fsk_specs[FSK_V23CH2]; - } - /*endif*/ - fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data); - fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data); - break; - case DATA_MODEM_V22BIS: - s->rx_handler = (span_rx_handler_t) &v22bis_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &v22bis_rx_fillin; - s->rx_user_data = &s->modems.v22bis; - s->tx_handler = (span_tx_handler_t) &v22bis_tx; - s->tx_user_data = &s->modems.v22bis; - v22bis_init(&s->modems.v22bis, bit_rate, 0, s->calling_party, s->get_bit, s->get_user_data, s->put_bit, s->put_user_data); - logging = v22bis_get_logging_state(&s->modems.v22bis); - level = span_log_get_level(&s->logging); - span_log_set_level(logging, level); - span_log_set_tag(logging, "V.22bis"); - break; -#if defined(SPANDSP_SUPPORT_V32BIS) - case DATA_MODEM_V32BIS: - s->rx_handler = (span_rx_handler_t) &v32bis_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &v32bis_rx_fillin; - s->rx_user_data = &s->modems.v32bis; - s->tx_handler = (span_tx_handler_t) &v32bis_tx; - s->tx_user_data = &s->modems.v32bis; - v32bis_init(&s->modems.v32bis, bit_rate, s->calling_party, s->get_bit, s->get_user_data, s->put_bit, s->put_user_data); - logging = v32bis_get_logging_state(&s->modems.v32bis); - level = span_log_get_level(&s->logging); - span_log_set_level(logging, level); - span_log_set_tag(logging, "V.32bis"); - break; -#endif -#if defined(SPANDSP_SUPPORT_V34) - case DATA_MODEM_V34: - s->rx_handler = (span_rx_handler_t) &v34_rx; - s->rx_fillin_handler = (span_rx_fillin_handler_t) &v34_rx_fillin; - s->rx_user_data = &s->modems.v34; - s->tx_handler = (span_tx_handler_t) &v34_tx; - s->tx_user_data = &s->modems.v34; - v34_init(&s->modems.v34, baud_rate, bit_rate, s->calling_party, true, s->get_bit, s->get_user_data, s->put_bit, s->put_user_data); - logging = v34_get_logging_state(&s->modems.v34); - level = span_log_get_level(&s->logging); - span_log_set_level(logging, level); - span_log_set_tag(logging, "V.34"); - break; -#endif - } - /*endswitch*/ - s->current_modem = which; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) data_modems_rx(data_modems_state_t *s, const int16_t amp[], int len) -{ - int res; - - if (s->rx_handler == NULL) - return len; - /*endif*/ - res = s->rx_handler(s->rx_user_data, amp, len); - if (s->current_modem != s->queued_modem) - data_modems_set_modem_type(s, s->queued_modem, s->queued_baud_rate, s->queued_bit_rate); - /*endif*/ - return res; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) data_modems_rx_fillin(data_modems_state_t *s, int len) -{ - if (s->rx_fillin_handler == NULL) - return len; - /*endif*/ - return s->rx_fillin_handler(s->rx_user_data, len); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) data_modems_tx(data_modems_state_t *s, int16_t amp[], int max_len) -{ - int len; - - for (len = 0; len < max_len; ) - { - if (s->tx_handler == NULL) - break; - /*endif*/ - len += s->tx_handler(s->tx_user_data, &[len], max_len - len); - } - /*endfor*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int data_modems_control_handler(void *user_data, int op, const char *num) -{ - data_modems_state_t *s; - - s = (data_modems_state_t *) user_data; - switch (op) - { - case AT_MODEM_CONTROL_CALL: - s->call_samples = 0; - break; - case AT_MODEM_CONTROL_ANSWER: - s->call_samples = 0; - break; - case AT_MODEM_CONTROL_ONHOOK: - if (s->at_state.rx_signal_present) - { - s->at_state.rx_data_bytes = 0; - } - /*endif*/ - break; - case AT_MODEM_CONTROL_RESTART: - return 0; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - return 0; - } - /*endswitch*/ - return s->modem_control_handler(s, s->modem_control_user_data, op, num); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) data_modems_set_at_tx_handler(data_modems_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data) -{ - at_set_at_tx_handler(&s->at_state, at_tx_handler, at_tx_user_data); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) data_modems_restart(data_modems_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(data_modems_state_t *) data_modems_init(data_modems_state_t *s, - bool calling_party, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data, - data_modems_control_handler_t modem_control_handler, - void *modem_control_user_data, - put_msg_func_t put_msg, - get_msg_func_t get_msg, - void *user_data) -{ - if (at_tx_handler == NULL || modem_control_handler == NULL) - return NULL; - /*endif*/ - - if (s == NULL) - { - if ((s = (data_modems_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "Modem"); - - dc_restore_init(&s->dc_restore); - - s->modem_control_handler = modem_control_handler; - s->modem_control_user_data = modem_control_user_data; - - s->put_msg = put_msg; - s->get_msg = get_msg; - s->user_data = user_data; - - v42bis_init(&s->v42bis, 3, 512, 6, NULL, s, 512, put_msg, s, 512); - v42_init(&s->v42, true, true, NULL, (put_msg_func_t) v42bis_decompress, &s->v42bis); - - data_modems_set_async_mode(s, 8, 1, 1); - - at_init(&s->at_state, at_tx_handler, at_tx_user_data, data_modems_control_handler, s); - - s->get_bit = async_tx_get_bit; - s->get_user_data = &s->async_tx; - s->put_bit = async_rx_put_bit; - s->put_user_data = &s->async_rx; - - s->calling_party = calling_party; - - data_modems_set_modem_type(s, DATA_MODEM_V8, 0, 0); - s->queued_modem = s->current_modem; - - s->rx_signal_present = false; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) data_modems_release(data_modems_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) data_modems_free(data_modems_state_t *s) -{ - if (s) - span_free(s); - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/dds_float.c b/libs/spandsp/src/dds_float.c deleted file mode 100644 index 45e5411f9c..0000000000 --- a/libs/spandsp/src/dds_float.c +++ /dev/null @@ -1,2203 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_dds.c - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" - -#define SLENK 11 -#define SINELEN (1 << SLENK) - -/* Precreating this table allows it to be in const memory, which might - have some performance advantage. */ -static const float sine_table[SINELEN] = -{ - 0.00000000f, - 0.00306796f, - 0.00613588f, - 0.00920375f, - 0.01227154f, - 0.01533921f, - 0.01840673f, - 0.02147408f, - 0.02454123f, - 0.02760815f, - 0.03067480f, - 0.03374117f, - 0.03680722f, - 0.03987293f, - 0.04293826f, - 0.04600318f, - 0.04906767f, - 0.05213170f, - 0.05519524f, - 0.05825826f, - 0.06132074f, - 0.06438263f, - 0.06744392f, - 0.07050457f, - 0.07356456f, - 0.07662386f, - 0.07968244f, - 0.08274026f, - 0.08579731f, - 0.08885355f, - 0.09190896f, - 0.09496350f, - 0.09801714f, - 0.10106986f, - 0.10412163f, - 0.10717242f, - 0.11022221f, - 0.11327095f, - 0.11631863f, - 0.11936521f, - 0.12241068f, - 0.12545498f, - 0.12849811f, - 0.13154003f, - 0.13458071f, - 0.13762012f, - 0.14065824f, - 0.14369503f, - 0.14673047f, - 0.14976453f, - 0.15279719f, - 0.15582840f, - 0.15885814f, - 0.16188639f, - 0.16491312f, - 0.16793829f, - 0.17096189f, - 0.17398387f, - 0.17700422f, - 0.18002290f, - 0.18303989f, - 0.18605515f, - 0.18906866f, - 0.19208040f, - 0.19509032f, - 0.19809841f, - 0.20110463f, - 0.20410897f, - 0.20711138f, - 0.21011184f, - 0.21311032f, - 0.21610680f, - 0.21910124f, - 0.22209362f, - 0.22508391f, - 0.22807208f, - 0.23105811f, - 0.23404196f, - 0.23702361f, - 0.24000302f, - 0.24298018f, - 0.24595505f, - 0.24892761f, - 0.25189782f, - 0.25486566f, - 0.25783110f, - 0.26079412f, - 0.26375468f, - 0.26671276f, - 0.26966833f, - 0.27262136f, - 0.27557182f, - 0.27851969f, - 0.28146494f, - 0.28440754f, - 0.28734746f, - 0.29028468f, - 0.29321916f, - 0.29615089f, - 0.29907983f, - 0.30200595f, - 0.30492923f, - 0.30784964f, - 0.31076715f, - 0.31368174f, - 0.31659338f, - 0.31950203f, - 0.32240768f, - 0.32531029f, - 0.32820984f, - 0.33110631f, - 0.33399965f, - 0.33688985f, - 0.33977688f, - 0.34266072f, - 0.34554132f, - 0.34841868f, - 0.35129276f, - 0.35416353f, - 0.35703096f, - 0.35989504f, - 0.36275572f, - 0.36561300f, - 0.36846683f, - 0.37131719f, - 0.37416406f, - 0.37700741f, - 0.37984721f, - 0.38268343f, - 0.38551605f, - 0.38834505f, - 0.39117038f, - 0.39399204f, - 0.39680999f, - 0.39962420f, - 0.40243465f, - 0.40524131f, - 0.40804416f, - 0.41084317f, - 0.41363831f, - 0.41642956f, - 0.41921689f, - 0.42200027f, - 0.42477968f, - 0.42755509f, - 0.43032648f, - 0.43309382f, - 0.43585708f, - 0.43861624f, - 0.44137127f, - 0.44412214f, - 0.44686884f, - 0.44961133f, - 0.45234959f, - 0.45508359f, - 0.45781330f, - 0.46053871f, - 0.46325978f, - 0.46597650f, - 0.46868882f, - 0.47139674f, - 0.47410021f, - 0.47679923f, - 0.47949376f, - 0.48218377f, - 0.48486925f, - 0.48755016f, - 0.49022648f, - 0.49289819f, - 0.49556526f, - 0.49822767f, - 0.50088538f, - 0.50353838f, - 0.50618665f, - 0.50883014f, - 0.51146885f, - 0.51410274f, - 0.51673180f, - 0.51935599f, - 0.52197529f, - 0.52458968f, - 0.52719913f, - 0.52980362f, - 0.53240313f, - 0.53499762f, - 0.53758708f, - 0.54017147f, - 0.54275078f, - 0.54532499f, - 0.54789406f, - 0.55045797f, - 0.55301671f, - 0.55557023f, - 0.55811853f, - 0.56066158f, - 0.56319934f, - 0.56573181f, - 0.56825895f, - 0.57078075f, - 0.57329717f, - 0.57580819f, - 0.57831380f, - 0.58081396f, - 0.58330865f, - 0.58579786f, - 0.58828155f, - 0.59075970f, - 0.59323230f, - 0.59569930f, - 0.59816071f, - 0.60061648f, - 0.60306660f, - 0.60551104f, - 0.60794978f, - 0.61038281f, - 0.61281008f, - 0.61523159f, - 0.61764731f, - 0.62005721f, - 0.62246128f, - 0.62485949f, - 0.62725182f, - 0.62963824f, - 0.63201874f, - 0.63439328f, - 0.63676186f, - 0.63912444f, - 0.64148101f, - 0.64383154f, - 0.64617601f, - 0.64851440f, - 0.65084668f, - 0.65317284f, - 0.65549285f, - 0.65780669f, - 0.66011434f, - 0.66241578f, - 0.66471098f, - 0.66699992f, - 0.66928259f, - 0.67155895f, - 0.67382900f, - 0.67609270f, - 0.67835004f, - 0.68060100f, - 0.68284555f, - 0.68508367f, - 0.68731534f, - 0.68954054f, - 0.69175926f, - 0.69397146f, - 0.69617713f, - 0.69837625f, - 0.70056879f, - 0.70275474f, - 0.70493408f, - 0.70710678f, - 0.70927283f, - 0.71143220f, - 0.71358487f, - 0.71573083f, - 0.71787005f, - 0.72000251f, - 0.72212819f, - 0.72424708f, - 0.72635916f, - 0.72846439f, - 0.73056277f, - 0.73265427f, - 0.73473888f, - 0.73681657f, - 0.73888732f, - 0.74095113f, - 0.74300795f, - 0.74505779f, - 0.74710061f, - 0.74913639f, - 0.75116513f, - 0.75318680f, - 0.75520138f, - 0.75720885f, - 0.75920919f, - 0.76120239f, - 0.76318842f, - 0.76516727f, - 0.76713891f, - 0.76910334f, - 0.77106052f, - 0.77301045f, - 0.77495311f, - 0.77688847f, - 0.77881651f, - 0.78073723f, - 0.78265060f, - 0.78455660f, - 0.78645521f, - 0.78834643f, - 0.79023022f, - 0.79210658f, - 0.79397548f, - 0.79583690f, - 0.79769084f, - 0.79953727f, - 0.80137617f, - 0.80320753f, - 0.80503133f, - 0.80684755f, - 0.80865618f, - 0.81045720f, - 0.81225059f, - 0.81403633f, - 0.81581441f, - 0.81758481f, - 0.81934752f, - 0.82110251f, - 0.82284978f, - 0.82458930f, - 0.82632106f, - 0.82804505f, - 0.82976123f, - 0.83146961f, - 0.83317016f, - 0.83486287f, - 0.83654773f, - 0.83822471f, - 0.83989379f, - 0.84155498f, - 0.84320824f, - 0.84485357f, - 0.84649094f, - 0.84812034f, - 0.84974177f, - 0.85135519f, - 0.85296060f, - 0.85455799f, - 0.85614733f, - 0.85772861f, - 0.85930182f, - 0.86086694f, - 0.86242396f, - 0.86397286f, - 0.86551362f, - 0.86704625f, - 0.86857071f, - 0.87008699f, - 0.87159509f, - 0.87309498f, - 0.87458665f, - 0.87607009f, - 0.87754529f, - 0.87901223f, - 0.88047089f, - 0.88192126f, - 0.88336334f, - 0.88479710f, - 0.88622253f, - 0.88763962f, - 0.88904836f, - 0.89044872f, - 0.89184071f, - 0.89322430f, - 0.89459949f, - 0.89596625f, - 0.89732458f, - 0.89867447f, - 0.90001589f, - 0.90134885f, - 0.90267332f, - 0.90398929f, - 0.90529676f, - 0.90659570f, - 0.90788612f, - 0.90916798f, - 0.91044129f, - 0.91170603f, - 0.91296219f, - 0.91420976f, - 0.91544872f, - 0.91667906f, - 0.91790078f, - 0.91911385f, - 0.92031828f, - 0.92151404f, - 0.92270113f, - 0.92387953f, - 0.92504924f, - 0.92621024f, - 0.92736253f, - 0.92850608f, - 0.92964090f, - 0.93076696f, - 0.93188427f, - 0.93299280f, - 0.93409255f, - 0.93518351f, - 0.93626567f, - 0.93733901f, - 0.93840353f, - 0.93945922f, - 0.94050607f, - 0.94154407f, - 0.94257320f, - 0.94359346f, - 0.94460484f, - 0.94560733f, - 0.94660091f, - 0.94758559f, - 0.94856135f, - 0.94952818f, - 0.95048607f, - 0.95143502f, - 0.95237501f, - 0.95330604f, - 0.95422810f, - 0.95514117f, - 0.95604525f, - 0.95694034f, - 0.95782641f, - 0.95870347f, - 0.95957151f, - 0.96043052f, - 0.96128049f, - 0.96212140f, - 0.96295327f, - 0.96377607f, - 0.96458979f, - 0.96539444f, - 0.96619000f, - 0.96697647f, - 0.96775384f, - 0.96852209f, - 0.96928124f, - 0.97003125f, - 0.97077214f, - 0.97150389f, - 0.97222650f, - 0.97293995f, - 0.97364425f, - 0.97433938f, - 0.97502535f, - 0.97570213f, - 0.97636973f, - 0.97702814f, - 0.97767736f, - 0.97831737f, - 0.97894818f, - 0.97956977f, - 0.98018214f, - 0.98078528f, - 0.98137919f, - 0.98196387f, - 0.98253930f, - 0.98310549f, - 0.98366242f, - 0.98421009f, - 0.98474850f, - 0.98527764f, - 0.98579751f, - 0.98630810f, - 0.98680940f, - 0.98730142f, - 0.98778414f, - 0.98825757f, - 0.98872169f, - 0.98917651f, - 0.98962202f, - 0.99005821f, - 0.99048508f, - 0.99090264f, - 0.99131086f, - 0.99170975f, - 0.99209931f, - 0.99247953f, - 0.99285041f, - 0.99321195f, - 0.99356414f, - 0.99390697f, - 0.99424045f, - 0.99456457f, - 0.99487933f, - 0.99518473f, - 0.99548076f, - 0.99576741f, - 0.99604470f, - 0.99631261f, - 0.99657115f, - 0.99682030f, - 0.99706007f, - 0.99729046f, - 0.99751146f, - 0.99772307f, - 0.99792529f, - 0.99811811f, - 0.99830154f, - 0.99847558f, - 0.99864022f, - 0.99879546f, - 0.99894129f, - 0.99907773f, - 0.99920476f, - 0.99932238f, - 0.99943060f, - 0.99952942f, - 0.99961882f, - 0.99969882f, - 0.99976941f, - 0.99983058f, - 0.99988235f, - 0.99992470f, - 0.99995764f, - 0.99998118f, - 0.99999529f, - 1.00000000f, - 0.99999529f, - 0.99998118f, - 0.99995764f, - 0.99992470f, - 0.99988235f, - 0.99983058f, - 0.99976941f, - 0.99969882f, - 0.99961882f, - 0.99952942f, - 0.99943060f, - 0.99932238f, - 0.99920476f, - 0.99907773f, - 0.99894129f, - 0.99879546f, - 0.99864022f, - 0.99847558f, - 0.99830154f, - 0.99811811f, - 0.99792529f, - 0.99772307f, - 0.99751146f, - 0.99729046f, - 0.99706007f, - 0.99682030f, - 0.99657115f, - 0.99631261f, - 0.99604470f, - 0.99576741f, - 0.99548076f, - 0.99518473f, - 0.99487933f, - 0.99456457f, - 0.99424045f, - 0.99390697f, - 0.99356414f, - 0.99321195f, - 0.99285041f, - 0.99247953f, - 0.99209931f, - 0.99170975f, - 0.99131086f, - 0.99090264f, - 0.99048508f, - 0.99005821f, - 0.98962202f, - 0.98917651f, - 0.98872169f, - 0.98825757f, - 0.98778414f, - 0.98730142f, - 0.98680940f, - 0.98630810f, - 0.98579751f, - 0.98527764f, - 0.98474850f, - 0.98421009f, - 0.98366242f, - 0.98310549f, - 0.98253930f, - 0.98196387f, - 0.98137919f, - 0.98078528f, - 0.98018214f, - 0.97956977f, - 0.97894818f, - 0.97831737f, - 0.97767736f, - 0.97702814f, - 0.97636973f, - 0.97570213f, - 0.97502535f, - 0.97433938f, - 0.97364425f, - 0.97293995f, - 0.97222650f, - 0.97150389f, - 0.97077214f, - 0.97003125f, - 0.96928124f, - 0.96852209f, - 0.96775384f, - 0.96697647f, - 0.96619000f, - 0.96539444f, - 0.96458979f, - 0.96377607f, - 0.96295327f, - 0.96212140f, - 0.96128049f, - 0.96043052f, - 0.95957151f, - 0.95870347f, - 0.95782641f, - 0.95694034f, - 0.95604525f, - 0.95514117f, - 0.95422810f, - 0.95330604f, - 0.95237501f, - 0.95143502f, - 0.95048607f, - 0.94952818f, - 0.94856135f, - 0.94758559f, - 0.94660091f, - 0.94560733f, - 0.94460484f, - 0.94359346f, - 0.94257320f, - 0.94154407f, - 0.94050607f, - 0.93945922f, - 0.93840353f, - 0.93733901f, - 0.93626567f, - 0.93518351f, - 0.93409255f, - 0.93299280f, - 0.93188427f, - 0.93076696f, - 0.92964090f, - 0.92850608f, - 0.92736253f, - 0.92621024f, - 0.92504924f, - 0.92387953f, - 0.92270113f, - 0.92151404f, - 0.92031828f, - 0.91911385f, - 0.91790078f, - 0.91667906f, - 0.91544872f, - 0.91420976f, - 0.91296219f, - 0.91170603f, - 0.91044129f, - 0.90916798f, - 0.90788612f, - 0.90659570f, - 0.90529676f, - 0.90398929f, - 0.90267332f, - 0.90134885f, - 0.90001589f, - 0.89867447f, - 0.89732458f, - 0.89596625f, - 0.89459949f, - 0.89322430f, - 0.89184071f, - 0.89044872f, - 0.88904836f, - 0.88763962f, - 0.88622253f, - 0.88479710f, - 0.88336334f, - 0.88192126f, - 0.88047089f, - 0.87901223f, - 0.87754529f, - 0.87607009f, - 0.87458665f, - 0.87309498f, - 0.87159509f, - 0.87008699f, - 0.86857071f, - 0.86704625f, - 0.86551362f, - 0.86397286f, - 0.86242396f, - 0.86086694f, - 0.85930182f, - 0.85772861f, - 0.85614733f, - 0.85455799f, - 0.85296060f, - 0.85135519f, - 0.84974177f, - 0.84812034f, - 0.84649094f, - 0.84485357f, - 0.84320824f, - 0.84155498f, - 0.83989379f, - 0.83822471f, - 0.83654773f, - 0.83486287f, - 0.83317016f, - 0.83146961f, - 0.82976123f, - 0.82804505f, - 0.82632106f, - 0.82458930f, - 0.82284978f, - 0.82110251f, - 0.81934752f, - 0.81758481f, - 0.81581441f, - 0.81403633f, - 0.81225059f, - 0.81045720f, - 0.80865618f, - 0.80684755f, - 0.80503133f, - 0.80320753f, - 0.80137617f, - 0.79953727f, - 0.79769084f, - 0.79583690f, - 0.79397548f, - 0.79210658f, - 0.79023022f, - 0.78834643f, - 0.78645521f, - 0.78455660f, - 0.78265060f, - 0.78073723f, - 0.77881651f, - 0.77688847f, - 0.77495311f, - 0.77301045f, - 0.77106052f, - 0.76910334f, - 0.76713891f, - 0.76516727f, - 0.76318842f, - 0.76120239f, - 0.75920919f, - 0.75720885f, - 0.75520138f, - 0.75318680f, - 0.75116513f, - 0.74913639f, - 0.74710061f, - 0.74505779f, - 0.74300795f, - 0.74095113f, - 0.73888732f, - 0.73681657f, - 0.73473888f, - 0.73265427f, - 0.73056277f, - 0.72846439f, - 0.72635916f, - 0.72424708f, - 0.72212819f, - 0.72000251f, - 0.71787005f, - 0.71573083f, - 0.71358487f, - 0.71143220f, - 0.70927283f, - 0.70710678f, - 0.70493408f, - 0.70275474f, - 0.70056879f, - 0.69837625f, - 0.69617713f, - 0.69397146f, - 0.69175926f, - 0.68954054f, - 0.68731534f, - 0.68508367f, - 0.68284555f, - 0.68060100f, - 0.67835004f, - 0.67609270f, - 0.67382900f, - 0.67155895f, - 0.66928259f, - 0.66699992f, - 0.66471098f, - 0.66241578f, - 0.66011434f, - 0.65780669f, - 0.65549285f, - 0.65317284f, - 0.65084668f, - 0.64851440f, - 0.64617601f, - 0.64383154f, - 0.64148101f, - 0.63912444f, - 0.63676186f, - 0.63439328f, - 0.63201874f, - 0.62963824f, - 0.62725182f, - 0.62485949f, - 0.62246128f, - 0.62005721f, - 0.61764731f, - 0.61523159f, - 0.61281008f, - 0.61038281f, - 0.60794978f, - 0.60551104f, - 0.60306660f, - 0.60061648f, - 0.59816071f, - 0.59569930f, - 0.59323230f, - 0.59075970f, - 0.58828155f, - 0.58579786f, - 0.58330865f, - 0.58081396f, - 0.57831380f, - 0.57580819f, - 0.57329717f, - 0.57078075f, - 0.56825895f, - 0.56573181f, - 0.56319934f, - 0.56066158f, - 0.55811853f, - 0.55557023f, - 0.55301671f, - 0.55045797f, - 0.54789406f, - 0.54532499f, - 0.54275078f, - 0.54017147f, - 0.53758708f, - 0.53499762f, - 0.53240313f, - 0.52980362f, - 0.52719913f, - 0.52458968f, - 0.52197529f, - 0.51935599f, - 0.51673180f, - 0.51410274f, - 0.51146885f, - 0.50883014f, - 0.50618665f, - 0.50353838f, - 0.50088538f, - 0.49822767f, - 0.49556526f, - 0.49289819f, - 0.49022648f, - 0.48755016f, - 0.48486925f, - 0.48218377f, - 0.47949376f, - 0.47679923f, - 0.47410021f, - 0.47139674f, - 0.46868882f, - 0.46597650f, - 0.46325978f, - 0.46053871f, - 0.45781330f, - 0.45508359f, - 0.45234959f, - 0.44961133f, - 0.44686884f, - 0.44412214f, - 0.44137127f, - 0.43861624f, - 0.43585708f, - 0.43309382f, - 0.43032648f, - 0.42755509f, - 0.42477968f, - 0.42200027f, - 0.41921689f, - 0.41642956f, - 0.41363831f, - 0.41084317f, - 0.40804416f, - 0.40524131f, - 0.40243465f, - 0.39962420f, - 0.39680999f, - 0.39399204f, - 0.39117038f, - 0.38834505f, - 0.38551605f, - 0.38268343f, - 0.37984721f, - 0.37700741f, - 0.37416406f, - 0.37131719f, - 0.36846683f, - 0.36561300f, - 0.36275572f, - 0.35989504f, - 0.35703096f, - 0.35416353f, - 0.35129276f, - 0.34841868f, - 0.34554132f, - 0.34266072f, - 0.33977688f, - 0.33688985f, - 0.33399965f, - 0.33110631f, - 0.32820984f, - 0.32531029f, - 0.32240768f, - 0.31950203f, - 0.31659338f, - 0.31368174f, - 0.31076715f, - 0.30784964f, - 0.30492923f, - 0.30200595f, - 0.29907983f, - 0.29615089f, - 0.29321916f, - 0.29028468f, - 0.28734746f, - 0.28440754f, - 0.28146494f, - 0.27851969f, - 0.27557182f, - 0.27262136f, - 0.26966833f, - 0.26671276f, - 0.26375468f, - 0.26079412f, - 0.25783110f, - 0.25486566f, - 0.25189782f, - 0.24892761f, - 0.24595505f, - 0.24298018f, - 0.24000302f, - 0.23702361f, - 0.23404196f, - 0.23105811f, - 0.22807208f, - 0.22508391f, - 0.22209362f, - 0.21910124f, - 0.21610680f, - 0.21311032f, - 0.21011184f, - 0.20711138f, - 0.20410897f, - 0.20110463f, - 0.19809841f, - 0.19509032f, - 0.19208040f, - 0.18906866f, - 0.18605515f, - 0.18303989f, - 0.18002290f, - 0.17700422f, - 0.17398387f, - 0.17096189f, - 0.16793829f, - 0.16491312f, - 0.16188639f, - 0.15885814f, - 0.15582840f, - 0.15279719f, - 0.14976453f, - 0.14673047f, - 0.14369503f, - 0.14065824f, - 0.13762012f, - 0.13458071f, - 0.13154003f, - 0.12849811f, - 0.12545498f, - 0.12241068f, - 0.11936521f, - 0.11631863f, - 0.11327095f, - 0.11022221f, - 0.10717242f, - 0.10412163f, - 0.10106986f, - 0.09801714f, - 0.09496350f, - 0.09190896f, - 0.08885355f, - 0.08579731f, - 0.08274026f, - 0.07968244f, - 0.07662386f, - 0.07356456f, - 0.07050457f, - 0.06744392f, - 0.06438263f, - 0.06132074f, - 0.05825826f, - 0.05519524f, - 0.05213170f, - 0.04906767f, - 0.04600318f, - 0.04293826f, - 0.03987293f, - 0.03680722f, - 0.03374117f, - 0.03067480f, - 0.02760815f, - 0.02454123f, - 0.02147408f, - 0.01840673f, - 0.01533921f, - 0.01227154f, - 0.00920375f, - 0.00613588f, - 0.00306796f, - 0.00000000f, - -0.00306796f, - -0.00613588f, - -0.00920375f, - -0.01227154f, - -0.01533921f, - -0.01840673f, - -0.02147408f, - -0.02454123f, - -0.02760815f, - -0.03067480f, - -0.03374117f, - -0.03680722f, - -0.03987293f, - -0.04293826f, - -0.04600318f, - -0.04906767f, - -0.05213170f, - -0.05519524f, - -0.05825826f, - -0.06132074f, - -0.06438263f, - -0.06744392f, - -0.07050457f, - -0.07356456f, - -0.07662386f, - -0.07968244f, - -0.08274026f, - -0.08579731f, - -0.08885355f, - -0.09190896f, - -0.09496350f, - -0.09801714f, - -0.10106986f, - -0.10412163f, - -0.10717242f, - -0.11022221f, - -0.11327095f, - -0.11631863f, - -0.11936521f, - -0.12241068f, - -0.12545498f, - -0.12849811f, - -0.13154003f, - -0.13458071f, - -0.13762012f, - -0.14065824f, - -0.14369503f, - -0.14673047f, - -0.14976453f, - -0.15279719f, - -0.15582840f, - -0.15885814f, - -0.16188639f, - -0.16491312f, - -0.16793829f, - -0.17096189f, - -0.17398387f, - -0.17700422f, - -0.18002290f, - -0.18303989f, - -0.18605515f, - -0.18906866f, - -0.19208040f, - -0.19509032f, - -0.19809841f, - -0.20110463f, - -0.20410897f, - -0.20711138f, - -0.21011184f, - -0.21311032f, - -0.21610680f, - -0.21910124f, - -0.22209362f, - -0.22508391f, - -0.22807208f, - -0.23105811f, - -0.23404196f, - -0.23702361f, - -0.24000302f, - -0.24298018f, - -0.24595505f, - -0.24892761f, - -0.25189782f, - -0.25486566f, - -0.25783110f, - -0.26079412f, - -0.26375468f, - -0.26671276f, - -0.26966833f, - -0.27262136f, - -0.27557182f, - -0.27851969f, - -0.28146494f, - -0.28440754f, - -0.28734746f, - -0.29028468f, - -0.29321916f, - -0.29615089f, - -0.29907983f, - -0.30200595f, - -0.30492923f, - -0.30784964f, - -0.31076715f, - -0.31368174f, - -0.31659338f, - -0.31950203f, - -0.32240768f, - -0.32531029f, - -0.32820984f, - -0.33110631f, - -0.33399965f, - -0.33688985f, - -0.33977688f, - -0.34266072f, - -0.34554132f, - -0.34841868f, - -0.35129276f, - -0.35416353f, - -0.35703096f, - -0.35989504f, - -0.36275572f, - -0.36561300f, - -0.36846683f, - -0.37131719f, - -0.37416406f, - -0.37700741f, - -0.37984721f, - -0.38268343f, - -0.38551605f, - -0.38834505f, - -0.39117038f, - -0.39399204f, - -0.39680999f, - -0.39962420f, - -0.40243465f, - -0.40524131f, - -0.40804416f, - -0.41084317f, - -0.41363831f, - -0.41642956f, - -0.41921689f, - -0.42200027f, - -0.42477968f, - -0.42755509f, - -0.43032648f, - -0.43309382f, - -0.43585708f, - -0.43861624f, - -0.44137127f, - -0.44412214f, - -0.44686884f, - -0.44961133f, - -0.45234959f, - -0.45508359f, - -0.45781330f, - -0.46053871f, - -0.46325978f, - -0.46597650f, - -0.46868882f, - -0.47139674f, - -0.47410021f, - -0.47679923f, - -0.47949376f, - -0.48218377f, - -0.48486925f, - -0.48755016f, - -0.49022648f, - -0.49289819f, - -0.49556526f, - -0.49822767f, - -0.50088538f, - -0.50353838f, - -0.50618665f, - -0.50883014f, - -0.51146885f, - -0.51410274f, - -0.51673180f, - -0.51935599f, - -0.52197529f, - -0.52458968f, - -0.52719913f, - -0.52980362f, - -0.53240313f, - -0.53499762f, - -0.53758708f, - -0.54017147f, - -0.54275078f, - -0.54532499f, - -0.54789406f, - -0.55045797f, - -0.55301671f, - -0.55557023f, - -0.55811853f, - -0.56066158f, - -0.56319934f, - -0.56573181f, - -0.56825895f, - -0.57078075f, - -0.57329717f, - -0.57580819f, - -0.57831380f, - -0.58081396f, - -0.58330865f, - -0.58579786f, - -0.58828155f, - -0.59075970f, - -0.59323230f, - -0.59569930f, - -0.59816071f, - -0.60061648f, - -0.60306660f, - -0.60551104f, - -0.60794978f, - -0.61038281f, - -0.61281008f, - -0.61523159f, - -0.61764731f, - -0.62005721f, - -0.62246128f, - -0.62485949f, - -0.62725182f, - -0.62963824f, - -0.63201874f, - -0.63439328f, - -0.63676186f, - -0.63912444f, - -0.64148101f, - -0.64383154f, - -0.64617601f, - -0.64851440f, - -0.65084668f, - -0.65317284f, - -0.65549285f, - -0.65780669f, - -0.66011434f, - -0.66241578f, - -0.66471098f, - -0.66699992f, - -0.66928259f, - -0.67155895f, - -0.67382900f, - -0.67609270f, - -0.67835004f, - -0.68060100f, - -0.68284555f, - -0.68508367f, - -0.68731534f, - -0.68954054f, - -0.69175926f, - -0.69397146f, - -0.69617713f, - -0.69837625f, - -0.70056879f, - -0.70275474f, - -0.70493408f, - -0.70710678f, - -0.70927283f, - -0.71143220f, - -0.71358487f, - -0.71573083f, - -0.71787005f, - -0.72000251f, - -0.72212819f, - -0.72424708f, - -0.72635916f, - -0.72846439f, - -0.73056277f, - -0.73265427f, - -0.73473888f, - -0.73681657f, - -0.73888732f, - -0.74095113f, - -0.74300795f, - -0.74505779f, - -0.74710061f, - -0.74913639f, - -0.75116513f, - -0.75318680f, - -0.75520138f, - -0.75720885f, - -0.75920919f, - -0.76120239f, - -0.76318842f, - -0.76516727f, - -0.76713891f, - -0.76910334f, - -0.77106052f, - -0.77301045f, - -0.77495311f, - -0.77688847f, - -0.77881651f, - -0.78073723f, - -0.78265060f, - -0.78455660f, - -0.78645521f, - -0.78834643f, - -0.79023022f, - -0.79210658f, - -0.79397548f, - -0.79583690f, - -0.79769084f, - -0.79953727f, - -0.80137617f, - -0.80320753f, - -0.80503133f, - -0.80684755f, - -0.80865618f, - -0.81045720f, - -0.81225059f, - -0.81403633f, - -0.81581441f, - -0.81758481f, - -0.81934752f, - -0.82110251f, - -0.82284978f, - -0.82458930f, - -0.82632106f, - -0.82804505f, - -0.82976123f, - -0.83146961f, - -0.83317016f, - -0.83486287f, - -0.83654773f, - -0.83822471f, - -0.83989379f, - -0.84155498f, - -0.84320824f, - -0.84485357f, - -0.84649094f, - -0.84812034f, - -0.84974177f, - -0.85135519f, - -0.85296060f, - -0.85455799f, - -0.85614733f, - -0.85772861f, - -0.85930182f, - -0.86086694f, - -0.86242396f, - -0.86397286f, - -0.86551362f, - -0.86704625f, - -0.86857071f, - -0.87008699f, - -0.87159509f, - -0.87309498f, - -0.87458665f, - -0.87607009f, - -0.87754529f, - -0.87901223f, - -0.88047089f, - -0.88192126f, - -0.88336334f, - -0.88479710f, - -0.88622253f, - -0.88763962f, - -0.88904836f, - -0.89044872f, - -0.89184071f, - -0.89322430f, - -0.89459949f, - -0.89596625f, - -0.89732458f, - -0.89867447f, - -0.90001589f, - -0.90134885f, - -0.90267332f, - -0.90398929f, - -0.90529676f, - -0.90659570f, - -0.90788612f, - -0.90916798f, - -0.91044129f, - -0.91170603f, - -0.91296219f, - -0.91420976f, - -0.91544872f, - -0.91667906f, - -0.91790078f, - -0.91911385f, - -0.92031828f, - -0.92151404f, - -0.92270113f, - -0.92387953f, - -0.92504924f, - -0.92621024f, - -0.92736253f, - -0.92850608f, - -0.92964090f, - -0.93076696f, - -0.93188427f, - -0.93299280f, - -0.93409255f, - -0.93518351f, - -0.93626567f, - -0.93733901f, - -0.93840353f, - -0.93945922f, - -0.94050607f, - -0.94154407f, - -0.94257320f, - -0.94359346f, - -0.94460484f, - -0.94560733f, - -0.94660091f, - -0.94758559f, - -0.94856135f, - -0.94952818f, - -0.95048607f, - -0.95143502f, - -0.95237501f, - -0.95330604f, - -0.95422810f, - -0.95514117f, - -0.95604525f, - -0.95694034f, - -0.95782641f, - -0.95870347f, - -0.95957151f, - -0.96043052f, - -0.96128049f, - -0.96212140f, - -0.96295327f, - -0.96377607f, - -0.96458979f, - -0.96539444f, - -0.96619000f, - -0.96697647f, - -0.96775384f, - -0.96852209f, - -0.96928124f, - -0.97003125f, - -0.97077214f, - -0.97150389f, - -0.97222650f, - -0.97293995f, - -0.97364425f, - -0.97433938f, - -0.97502535f, - -0.97570213f, - -0.97636973f, - -0.97702814f, - -0.97767736f, - -0.97831737f, - -0.97894818f, - -0.97956977f, - -0.98018214f, - -0.98078528f, - -0.98137919f, - -0.98196387f, - -0.98253930f, - -0.98310549f, - -0.98366242f, - -0.98421009f, - -0.98474850f, - -0.98527764f, - -0.98579751f, - -0.98630810f, - -0.98680940f, - -0.98730142f, - -0.98778414f, - -0.98825757f, - -0.98872169f, - -0.98917651f, - -0.98962202f, - -0.99005821f, - -0.99048508f, - -0.99090264f, - -0.99131086f, - -0.99170975f, - -0.99209931f, - -0.99247953f, - -0.99285041f, - -0.99321195f, - -0.99356414f, - -0.99390697f, - -0.99424045f, - -0.99456457f, - -0.99487933f, - -0.99518473f, - -0.99548076f, - -0.99576741f, - -0.99604470f, - -0.99631261f, - -0.99657115f, - -0.99682030f, - -0.99706007f, - -0.99729046f, - -0.99751146f, - -0.99772307f, - -0.99792529f, - -0.99811811f, - -0.99830154f, - -0.99847558f, - -0.99864022f, - -0.99879546f, - -0.99894129f, - -0.99907773f, - -0.99920476f, - -0.99932238f, - -0.99943060f, - -0.99952942f, - -0.99961882f, - -0.99969882f, - -0.99976941f, - -0.99983058f, - -0.99988235f, - -0.99992470f, - -0.99995764f, - -0.99998118f, - -0.99999529f, - -1.00000000f, - -0.99999529f, - -0.99998118f, - -0.99995764f, - -0.99992470f, - -0.99988235f, - -0.99983058f, - -0.99976941f, - -0.99969882f, - -0.99961882f, - -0.99952942f, - -0.99943060f, - -0.99932238f, - -0.99920476f, - -0.99907773f, - -0.99894129f, - -0.99879546f, - -0.99864022f, - -0.99847558f, - -0.99830154f, - -0.99811811f, - -0.99792529f, - -0.99772307f, - -0.99751146f, - -0.99729046f, - -0.99706007f, - -0.99682030f, - -0.99657115f, - -0.99631261f, - -0.99604470f, - -0.99576741f, - -0.99548076f, - -0.99518473f, - -0.99487933f, - -0.99456457f, - -0.99424045f, - -0.99390697f, - -0.99356414f, - -0.99321195f, - -0.99285041f, - -0.99247953f, - -0.99209931f, - -0.99170975f, - -0.99131086f, - -0.99090264f, - -0.99048508f, - -0.99005821f, - -0.98962202f, - -0.98917651f, - -0.98872169f, - -0.98825757f, - -0.98778414f, - -0.98730142f, - -0.98680940f, - -0.98630810f, - -0.98579751f, - -0.98527764f, - -0.98474850f, - -0.98421009f, - -0.98366242f, - -0.98310549f, - -0.98253930f, - -0.98196387f, - -0.98137919f, - -0.98078528f, - -0.98018214f, - -0.97956977f, - -0.97894818f, - -0.97831737f, - -0.97767736f, - -0.97702814f, - -0.97636973f, - -0.97570213f, - -0.97502535f, - -0.97433938f, - -0.97364425f, - -0.97293995f, - -0.97222650f, - -0.97150389f, - -0.97077214f, - -0.97003125f, - -0.96928124f, - -0.96852209f, - -0.96775384f, - -0.96697647f, - -0.96619000f, - -0.96539444f, - -0.96458979f, - -0.96377607f, - -0.96295327f, - -0.96212140f, - -0.96128049f, - -0.96043052f, - -0.95957151f, - -0.95870347f, - -0.95782641f, - -0.95694034f, - -0.95604525f, - -0.95514117f, - -0.95422810f, - -0.95330604f, - -0.95237501f, - -0.95143502f, - -0.95048607f, - -0.94952818f, - -0.94856135f, - -0.94758559f, - -0.94660091f, - -0.94560733f, - -0.94460484f, - -0.94359346f, - -0.94257320f, - -0.94154407f, - -0.94050607f, - -0.93945922f, - -0.93840353f, - -0.93733901f, - -0.93626567f, - -0.93518351f, - -0.93409255f, - -0.93299280f, - -0.93188427f, - -0.93076696f, - -0.92964090f, - -0.92850608f, - -0.92736253f, - -0.92621024f, - -0.92504924f, - -0.92387953f, - -0.92270113f, - -0.92151404f, - -0.92031828f, - -0.91911385f, - -0.91790078f, - -0.91667906f, - -0.91544872f, - -0.91420976f, - -0.91296219f, - -0.91170603f, - -0.91044129f, - -0.90916798f, - -0.90788612f, - -0.90659570f, - -0.90529676f, - -0.90398929f, - -0.90267332f, - -0.90134885f, - -0.90001589f, - -0.89867447f, - -0.89732458f, - -0.89596625f, - -0.89459949f, - -0.89322430f, - -0.89184071f, - -0.89044872f, - -0.88904836f, - -0.88763962f, - -0.88622253f, - -0.88479710f, - -0.88336334f, - -0.88192126f, - -0.88047089f, - -0.87901223f, - -0.87754529f, - -0.87607009f, - -0.87458665f, - -0.87309498f, - -0.87159509f, - -0.87008699f, - -0.86857071f, - -0.86704625f, - -0.86551362f, - -0.86397286f, - -0.86242396f, - -0.86086694f, - -0.85930182f, - -0.85772861f, - -0.85614733f, - -0.85455799f, - -0.85296060f, - -0.85135519f, - -0.84974177f, - -0.84812034f, - -0.84649094f, - -0.84485357f, - -0.84320824f, - -0.84155498f, - -0.83989379f, - -0.83822471f, - -0.83654773f, - -0.83486287f, - -0.83317016f, - -0.83146961f, - -0.82976123f, - -0.82804505f, - -0.82632106f, - -0.82458930f, - -0.82284978f, - -0.82110251f, - -0.81934752f, - -0.81758481f, - -0.81581441f, - -0.81403633f, - -0.81225059f, - -0.81045720f, - -0.80865618f, - -0.80684755f, - -0.80503133f, - -0.80320753f, - -0.80137617f, - -0.79953727f, - -0.79769084f, - -0.79583690f, - -0.79397548f, - -0.79210658f, - -0.79023022f, - -0.78834643f, - -0.78645521f, - -0.78455660f, - -0.78265060f, - -0.78073723f, - -0.77881651f, - -0.77688847f, - -0.77495311f, - -0.77301045f, - -0.77106052f, - -0.76910334f, - -0.76713891f, - -0.76516727f, - -0.76318842f, - -0.76120239f, - -0.75920919f, - -0.75720885f, - -0.75520138f, - -0.75318680f, - -0.75116513f, - -0.74913639f, - -0.74710061f, - -0.74505779f, - -0.74300795f, - -0.74095113f, - -0.73888732f, - -0.73681657f, - -0.73473888f, - -0.73265427f, - -0.73056277f, - -0.72846439f, - -0.72635916f, - -0.72424708f, - -0.72212819f, - -0.72000251f, - -0.71787005f, - -0.71573083f, - -0.71358487f, - -0.71143220f, - -0.70927283f, - -0.70710678f, - -0.70493408f, - -0.70275474f, - -0.70056879f, - -0.69837625f, - -0.69617713f, - -0.69397146f, - -0.69175926f, - -0.68954054f, - -0.68731534f, - -0.68508367f, - -0.68284555f, - -0.68060100f, - -0.67835004f, - -0.67609270f, - -0.67382900f, - -0.67155895f, - -0.66928259f, - -0.66699992f, - -0.66471098f, - -0.66241578f, - -0.66011434f, - -0.65780669f, - -0.65549285f, - -0.65317284f, - -0.65084668f, - -0.64851440f, - -0.64617601f, - -0.64383154f, - -0.64148101f, - -0.63912444f, - -0.63676186f, - -0.63439328f, - -0.63201874f, - -0.62963824f, - -0.62725182f, - -0.62485949f, - -0.62246128f, - -0.62005721f, - -0.61764731f, - -0.61523159f, - -0.61281008f, - -0.61038281f, - -0.60794978f, - -0.60551104f, - -0.60306660f, - -0.60061648f, - -0.59816071f, - -0.59569930f, - -0.59323230f, - -0.59075970f, - -0.58828155f, - -0.58579786f, - -0.58330865f, - -0.58081396f, - -0.57831380f, - -0.57580819f, - -0.57329717f, - -0.57078075f, - -0.56825895f, - -0.56573181f, - -0.56319934f, - -0.56066158f, - -0.55811853f, - -0.55557023f, - -0.55301671f, - -0.55045797f, - -0.54789406f, - -0.54532499f, - -0.54275078f, - -0.54017147f, - -0.53758708f, - -0.53499762f, - -0.53240313f, - -0.52980362f, - -0.52719913f, - -0.52458968f, - -0.52197529f, - -0.51935599f, - -0.51673180f, - -0.51410274f, - -0.51146885f, - -0.50883014f, - -0.50618665f, - -0.50353838f, - -0.50088538f, - -0.49822767f, - -0.49556526f, - -0.49289819f, - -0.49022648f, - -0.48755016f, - -0.48486925f, - -0.48218377f, - -0.47949376f, - -0.47679923f, - -0.47410021f, - -0.47139674f, - -0.46868882f, - -0.46597650f, - -0.46325978f, - -0.46053871f, - -0.45781330f, - -0.45508359f, - -0.45234959f, - -0.44961133f, - -0.44686884f, - -0.44412214f, - -0.44137127f, - -0.43861624f, - -0.43585708f, - -0.43309382f, - -0.43032648f, - -0.42755509f, - -0.42477968f, - -0.42200027f, - -0.41921689f, - -0.41642956f, - -0.41363831f, - -0.41084317f, - -0.40804416f, - -0.40524131f, - -0.40243465f, - -0.39962420f, - -0.39680999f, - -0.39399204f, - -0.39117038f, - -0.38834505f, - -0.38551605f, - -0.38268343f, - -0.37984721f, - -0.37700741f, - -0.37416406f, - -0.37131719f, - -0.36846683f, - -0.36561300f, - -0.36275572f, - -0.35989504f, - -0.35703096f, - -0.35416353f, - -0.35129276f, - -0.34841868f, - -0.34554132f, - -0.34266072f, - -0.33977688f, - -0.33688985f, - -0.33399965f, - -0.33110631f, - -0.32820984f, - -0.32531029f, - -0.32240768f, - -0.31950203f, - -0.31659338f, - -0.31368174f, - -0.31076715f, - -0.30784964f, - -0.30492923f, - -0.30200595f, - -0.29907983f, - -0.29615089f, - -0.29321916f, - -0.29028468f, - -0.28734746f, - -0.28440754f, - -0.28146494f, - -0.27851969f, - -0.27557182f, - -0.27262136f, - -0.26966833f, - -0.26671276f, - -0.26375468f, - -0.26079412f, - -0.25783110f, - -0.25486566f, - -0.25189782f, - -0.24892761f, - -0.24595505f, - -0.24298018f, - -0.24000302f, - -0.23702361f, - -0.23404196f, - -0.23105811f, - -0.22807208f, - -0.22508391f, - -0.22209362f, - -0.21910124f, - -0.21610680f, - -0.21311032f, - -0.21011184f, - -0.20711138f, - -0.20410897f, - -0.20110463f, - -0.19809841f, - -0.19509032f, - -0.19208040f, - -0.18906866f, - -0.18605515f, - -0.18303989f, - -0.18002290f, - -0.17700422f, - -0.17398387f, - -0.17096189f, - -0.16793829f, - -0.16491312f, - -0.16188639f, - -0.15885814f, - -0.15582840f, - -0.15279719f, - -0.14976453f, - -0.14673047f, - -0.14369503f, - -0.14065824f, - -0.13762012f, - -0.13458071f, - -0.13154003f, - -0.12849811f, - -0.12545498f, - -0.12241068f, - -0.11936521f, - -0.11631863f, - -0.11327095f, - -0.11022221f, - -0.10717242f, - -0.10412163f, - -0.10106986f, - -0.09801714f, - -0.09496350f, - -0.09190896f, - -0.08885355f, - -0.08579731f, - -0.08274026f, - -0.07968244f, - -0.07662386f, - -0.07356456f, - -0.07050457f, - -0.06744392f, - -0.06438263f, - -0.06132074f, - -0.05825826f, - -0.05519524f, - -0.05213170f, - -0.04906767f, - -0.04600318f, - -0.04293826f, - -0.03987293f, - -0.03680722f, - -0.03374117f, - -0.03067480f, - -0.02760815f, - -0.02454123f, - -0.02147408f, - -0.01840673f, - -0.01533921f, - -0.01227154f, - -0.00920375f, - -0.00613588f, - -0.00306796f -}; - -SPAN_DECLARE(float) dds_phase_to_radians(uint32_t phase) -{ - return phase*2.0f*3.1415926f/(65536.0f*65536.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) dds_phase_ratef(float frequency) -{ - return (int32_t) (frequency*65536.0f*65536.0f/SAMPLE_RATE); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_frequencyf(int32_t phase_rate) -{ - return (float) phase_rate*(float) SAMPLE_RATE/(65536.0f*65536.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_scaling_dbm0f(float level) -{ - return powf(10.0f, (level - DBM0_MAX_SINE_POWER)/20.0f)*32767.0f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_scaling_dbovf(float level) -{ - return powf(10.0f, (level - DBOV_MAX_SINE_POWER)/20.0f)*32767.0f; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ float dds_lookupx(uint32_t phase) -{ - return sine_table[phase >> (32 - SLENK)]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_lookupf(uint32_t phase) -{ - return dds_lookupx(phase); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_offsetf(uint32_t phase_acc, int32_t phase_offset) -{ - return dds_lookupx(phase_acc + phase_offset); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) dds_advancef(uint32_t *phase_acc, int32_t phase_rate) -{ - *phase_acc += phase_rate; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) ddsf(uint32_t *phase_acc, int32_t phase_rate) -{ - float amp; - - amp = dds_lookupx(*phase_acc); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_modf(uint32_t *phase_acc, int32_t phase_rate, float scale, int32_t phase) -{ - float amp; - - amp = dds_lookupx(*phase_acc + phase)*scale; - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) dds_lookup_complexf(uint32_t phase) -{ - return complex_setf(dds_lookupx(phase + (1 << 30)), dds_lookupx(phase)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) dds_complexf(uint32_t *phase_acc, int32_t phase_rate) -{ - complexf_t amp; - - amp = complex_setf(dds_lookupx(*phase_acc + (1 << 30)), dds_lookupx(*phase_acc)); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) dds_complex_modf(uint32_t *phase_acc, int32_t phase_rate, float scale, int32_t phase) -{ - complexf_t amp; - - amp = complex_setf(dds_lookupx(*phase_acc + phase + (1 << 30))*scale, - dds_lookupx(*phase_acc + phase)*scale); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/dds_int.c b/libs/spandsp/src/dds_int.c deleted file mode 100644 index 3f1734b88b..0000000000 --- a/libs/spandsp/src/dds_int.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dds.c - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" - -/* In a A-law or u-law channel, a fairly coarse step sine table is adequate to keep the spectral - mess due to the DDS at a similar level to the spectral mess due to the A-law or u-law - compression. */ -#define SLENK 8 -#define DDS_STEPS (1 << SLENK) -#define DDS_SHIFT (32 - 2 - SLENK) - -/* This is a simple set of direct digital synthesis (DDS) functions to generate sine - waves. This version uses a 256 entry sin/cos table to cover one quadrant. */ - -static const int16_t sine_table[DDS_STEPS + 1] = -{ - 0, - 201, - 402, - 603, - 804, - 1005, - 1206, - 1407, - 1608, - 1809, - 2009, - 2210, - 2410, - 2611, - 2811, - 3012, - 3212, - 3412, - 3612, - 3811, - 4011, - 4210, - 4410, - 4609, - 4808, - 5007, - 5205, - 5404, - 5602, - 5800, - 5998, - 6195, - 6393, - 6590, - 6786, - 6983, - 7179, - 7375, - 7571, - 7767, - 7962, - 8157, - 8351, - 8545, - 8739, - 8933, - 9126, - 9319, - 9512, - 9704, - 9896, - 10087, - 10278, - 10469, - 10659, - 10849, - 11039, - 11228, - 11417, - 11605, - 11793, - 11980, - 12167, - 12353, - 12539, - 12725, - 12910, - 13094, - 13279, - 13462, - 13645, - 13828, - 14010, - 14191, - 14372, - 14553, - 14732, - 14912, - 15090, - 15269, - 15446, - 15623, - 15800, - 15976, - 16151, - 16325, - 16499, - 16673, - 16846, - 17018, - 17189, - 17360, - 17530, - 17700, - 17869, - 18037, - 18204, - 18371, - 18537, - 18703, - 18868, - 19032, - 19195, - 19357, - 19519, - 19680, - 19841, - 20000, - 20159, - 20317, - 20475, - 20631, - 20787, - 20942, - 21096, - 21250, - 21403, - 21554, - 21705, - 21856, - 22005, - 22154, - 22301, - 22448, - 22594, - 22739, - 22884, - 23027, - 23170, - 23311, - 23452, - 23592, - 23731, - 23870, - 24007, - 24143, - 24279, - 24413, - 24547, - 24680, - 24811, - 24942, - 25072, - 25201, - 25329, - 25456, - 25582, - 25708, - 25832, - 25955, - 26077, - 26198, - 26319, - 26438, - 26556, - 26674, - 26790, - 26905, - 27019, - 27133, - 27245, - 27356, - 27466, - 27575, - 27683, - 27790, - 27896, - 28001, - 28105, - 28208, - 28310, - 28411, - 28510, - 28609, - 28706, - 28803, - 28898, - 28992, - 29085, - 29177, - 29268, - 29358, - 29447, - 29534, - 29621, - 29706, - 29791, - 29874, - 29956, - 30037, - 30117, - 30195, - 30273, - 30349, - 30424, - 30498, - 30571, - 30643, - 30714, - 30783, - 30852, - 30919, - 30985, - 31050, - 31113, - 31176, - 31237, - 31297, - 31356, - 31414, - 31470, - 31526, - 31580, - 31633, - 31685, - 31736, - 31785, - 31833, - 31880, - 31926, - 31971, - 32014, - 32057, - 32098, - 32137, - 32176, - 32213, - 32250, - 32285, - 32318, - 32351, - 32382, - 32412, - 32441, - 32469, - 32495, - 32521, - 32545, - 32567, - 32589, - 32609, - 32628, - 32646, - 32663, - 32678, - 32692, - 32705, - 32717, - 32728, - 32737, - 32745, - 32752, - 32757, - 32761, - 32765, - 32766, - 32767 -}; - -SPAN_DECLARE(int32_t) dds_phase_rate(float frequency) -{ - return (int32_t) (frequency*65536.0f*65536.0f/SAMPLE_RATE); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) dds_frequency(int32_t phase_rate) -{ - return (float) phase_rate*(float) SAMPLE_RATE/(65536.0f*65536.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) dds_scaling_dbm0(float level) -{ - return (int16_t) (powf(10.0f, (level - DBM0_MAX_SINE_POWER)/20.0f)*32767.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) dds_scaling_dbov(float level) -{ - return (int16_t) (powf(10.0f, (level - DBOV_MAX_SINE_POWER)/20.0f)*32767.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase) -{ - uint32_t step; - int16_t amp; - - phase >>= DDS_SHIFT; - step = phase & (DDS_STEPS - 1); - if ((phase & DDS_STEPS)) - step = DDS_STEPS - step; - amp = sine_table[step]; - if ((phase & (2*DDS_STEPS))) - amp = -amp; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) dds_offset(uint32_t phase_acc, int32_t phase_offset) -{ - return dds_lookup(phase_acc + phase_offset); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) dds_advance(uint32_t *phase_acc, int32_t phase_rate) -{ - *phase_acc += phase_rate; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) dds(uint32_t *phase_acc, int32_t phase_rate) -{ - int16_t amp; - - amp = dds_lookup(*phase_acc); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) dds_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase) -{ - int16_t amp; - - amp = (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi_t) dds_lookup_complexi(uint32_t phase) -{ - return complex_seti(dds_lookup(phase + (1 << 30)), dds_lookup(phase)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi_t) dds_complexi(uint32_t *phase_acc, int32_t phase_rate) -{ - complexi_t amp; - - amp = complex_seti(dds_lookup(*phase_acc + (1 << 30)), dds_lookup(*phase_acc)); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi_t) dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase) -{ - complexi_t amp; - - amp = complex_seti(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15, - ((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi16_t) dds_lookup_complexi16(uint32_t phase) -{ - return complex_seti16(dds_lookup(phase + (1 << 30)), dds_lookup(phase)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi16_t) dds_complexi16(uint32_t *phase_acc, int32_t phase_rate) -{ - complexi16_t amp; - - amp = complex_seti16(dds_lookup(*phase_acc + (1 << 30)), dds_lookup(*phase_acc)); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi16_t) dds_complexi16_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase) -{ - complexi16_t amp; - - amp = complex_seti16((int16_t) (((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15), - (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15)); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi32_t) dds_lookup_complexi32(uint32_t phase) -{ - return complex_seti32(dds_lookup(phase + (1 << 30)), dds_lookup(phase)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi32_t) dds_complexi32(uint32_t *phase_acc, int32_t phase_rate) -{ - complexi32_t amp; - - amp = complex_seti32(dds_lookup(*phase_acc + (1 << 30)), dds_lookup(*phase_acc)); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase) -{ - complexi32_t amp; - - amp = complex_seti32(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15, - ((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15); - *phase_acc += phase_rate; - return amp; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/dtmf.c b/libs/spandsp/src/dtmf.c deleted file mode 100644 index 1ff725ff22..0000000000 --- a/libs/spandsp/src/dtmf.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dtmf.c - DTMF generation and detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001-2003, 2005, 2006 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/fast_convert.h" -#include "spandsp/queue.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/dtmf.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/queue.h" -#include "spandsp/private/tone_generate.h" -#include "spandsp/private/dtmf.h" - -#define DEFAULT_DTMF_TX_LEVEL -10 -#define DEFAULT_DTMF_TX_ON_TIME 50 -#define DEFAULT_DTMF_TX_OFF_TIME 55 - -#if defined(SPANDSP_USE_FIXED_POINT) -/* 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 68.251f /* 10*log(((32768.0/128.0)^2)*DTMF_SAMPLES_PER_BLOCK) */ -#define DTMF_SAMPLES_PER_BLOCK 102 -#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) */ -#define DTMF_SAMPLES_PER_BLOCK 102 -#endif - -static const float dtmf_row[] = -{ - 697.0f, 770.0f, 852.0f, 941.0f -}; -static const float dtmf_col[] = -{ - 1209.0f, 1336.0f, 1477.0f, 1633.0f -}; - -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 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) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t row_energy[4]; - int32_t col_energy[4]; - int16_t xamp; - float famp; -#else - float row_energy[4]; - float col_energy[4]; - float xamp; - float famp; -#endif - float v1; - int i; - int j; - int sample; - int best_row; - int best_col; - int limit; - uint8_t hit; - - for (sample = 0; sample < samples; sample = limit) - { - /* The block length is optimised to meet the DTMF specs. */ - if ((samples - sample) >= (DTMF_SAMPLES_PER_BLOCK - s->current_sample)) - limit = sample + (DTMF_SAMPLES_PER_BLOCK - s->current_sample); - else - limit = samples; - /* The following unrolled loop takes only 35% (rough estimate) of the - time of a rolled loop on the machine on which it was developed */ - for (j = sample; j < limit; j++) - { - xamp = amp[j]; - if (s->filter_dialtone) - { - famp = xamp; - /* Sharp notches applied at 350Hz and 440Hz - the two common dialtone frequencies. - These are rather high Q, to achieve the required narrowness, without using lots of - sections. */ - v1 = 0.98356f*famp + 1.8954426f*s->z350[0] - 0.9691396f*s->z350[1]; - famp = v1 - 1.9251480f*s->z350[0] + s->z350[1]; - s->z350[1] = s->z350[0]; - s->z350[0] = v1; - - v1 = 0.98456f*famp + 1.8529543f*s->z440[0] - 0.9691396f*s->z440[1]; - famp = v1 - 1.8819938f*s->z440[0] + s->z440[1]; - s->z440[1] = s->z440[0]; - s->z440[0] = v1; - xamp = famp; - } - xamp = goertzel_preadjust_amp(xamp); -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy += ((int32_t) xamp*xamp); -#else - s->energy += xamp*xamp; -#endif - goertzel_samplex(&s->row_out[0], xamp); - goertzel_samplex(&s->col_out[0], xamp); - goertzel_samplex(&s->row_out[1], xamp); - goertzel_samplex(&s->col_out[1], xamp); - goertzel_samplex(&s->row_out[2], xamp); - goertzel_samplex(&s->col_out[2], xamp); - goertzel_samplex(&s->row_out[3], xamp); - goertzel_samplex(&s->col_out[3], xamp); - } - if (s->duration < INT_MAX - (limit - sample)) - s->duration += (limit - sample); - s->current_sample += (limit - sample); - if (s->current_sample < DTMF_SAMPLES_PER_BLOCK) - continue; - - /* We are at the end of a DTMF detection block */ - /* Find the peak row and the peak column */ - row_energy[0] = goertzel_result(&s->row_out[0]); - best_row = 0; - col_energy[0] = goertzel_result(&s->col_out[0]); - best_col = 0; - for (i = 1; i < 4; i++) - { - row_energy[i] = goertzel_result(&s->row_out[i]); - if (row_energy[i] > row_energy[best_row]) - best_row = i; - col_energy[i] = goertzel_result(&s->col_out[i]); - if (col_energy[i] > col_energy[best_col]) - best_col = i; - } - hit = 0; - /* Basic signal level test and the twist test */ - if (row_energy[best_row] >= s->threshold - && - col_energy[best_col] >= s->threshold) - { - if (col_energy[best_col] < row_energy[best_row]*s->reverse_twist - && - col_energy[best_col]*s->normal_twist > row_energy[best_row]) - { - /* Relative peak test ... */ - for (i = 0; i < 4; i++) - { - if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) - || - (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) - { - break; - } - } - /* ... and fraction of total energy test */ - if (i >= 4 - && - (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->energy) - { - /* Got a hit */ - hit = dtmf_positions[(best_row << 2) + best_col]; - } - } - if (span_log_test(&s->logging, SPAN_LOG_FLOW)) - { - /* Log information about the quality of the signal, to aid analysis of detection problems */ - /* Logging at this point filters the total no-hoper frames out of the log, and leaves - anything which might feasibly be a DTMF digit. The log will then contain a list of the - total, row and coloumn power levels for detailed analysis of detection problems. */ - span_log(&s->logging, - SPAN_LOG_FLOW, - "Potentially '%c' - total %.2fdB, row %.2fdB, col %.2fdB, duration %d - %s\n", - dtmf_positions[(best_row << 2) + best_col], - log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER, - log10f(row_energy[best_row]/DTMF_TO_TOTAL_ENERGY)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER, - log10f(col_energy[best_col]/DTMF_TO_TOTAL_ENERGY)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER, - s->duration, - (hit) ? "hit" : "miss"); - } - } - /* The logic in the next test should ensure the following for different successive hit patterns: - -----ABB = start of digit B. - ----B-BB = start of digit B - ----A-BB = start of digit B - BBBBBABB = still in digit B. - BBBBBB-- = end of digit B - BBBBBBC- = end of digit B - BBBBACBB = B ends, then B starts again. - BBBBBBCC = B ends, then C starts. - BBBBBCDD = B ends, then D starts. - This can work with: - - Back to back differing digits. Back-to-back digits should - not happen. The spec. says there should be a gap between digits. - However, many real phones do not impose a gap, and rolling across - the keypad can produce little or no gap. - - It tolerates nasty phones that give a very wobbly start to a digit. - - VoIP can give sample slips. The phase jumps that produces will cause - the block it is in to give no detection. This logic will ride over a - single missed block, and not falsely declare a second digit. If the - hiccup happens in the wrong place on a minimum length digit, however - we would still fail to detect that digit. Could anything be done to - deal with that? Packet loss is clearly a no-go zone. - Note this is only relevant to VoIP using A-law, u-law or similar. - Low bit rate codecs scramble DTMF too much for it to be recognised, - and often slip in units larger than a sample. */ - if (hit != s->in_digit && s->last_hit != s->in_digit) - { - /* We have two successive indications that something has changed. */ - /* To declare digit on, the hits must agree. Otherwise we declare tone off. */ - hit = (hit && hit == s->last_hit) ? hit : 0; - if (s->realtime_callback) - { - /* Avoid reporting multiple no digit conditions on flaky hits */ - if (s->in_digit || hit) - { - i = (s->in_digit && !hit) ? -99 : lfastrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER); - s->realtime_callback(s->realtime_callback_data, hit, i, s->duration); - s->duration = 0; - } - } - else - { - if (hit) - { - if (s->current_digits < MAX_DTMF_DIGITS) - { - s->digits[s->current_digits++] = (char) hit; - s->digits[s->current_digits] = '\0'; - if (s->digits_callback) - { - s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); - s->current_digits = 0; - } - } - else - { - s->lost_digits++; - } - } - } - s->in_digit = hit; - } - s->last_hit = hit; - s->energy = FP_SCALE(0.0f); - s->current_sample = 0; - } - if (s->current_digits && s->digits_callback) - { - s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); - s->digits[0] = '\0'; - s->current_digits = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_rx_fillin(dtmf_rx_state_t *s, int samples) -{ - int i; - - /* Restart any Goertzel and energy gathering operation we might be in the middle of. */ - for (i = 0; i < 4; i++) - { - goertzel_reset(&s->row_out[i]); - goertzel_reset(&s->col_out[i]); - } - 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. */ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_rx_status(dtmf_rx_state_t *s) -{ - if (s->in_digit) - return s->in_digit; - if (s->last_hit) - return 'x'; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) dtmf_rx_get(dtmf_rx_state_t *s, char *buf, int max) -{ - if (max > s->current_digits) - max = s->current_digits; - if (max > 0) - { - memcpy(buf, s->digits, max); - memmove(s->digits, s->digits + max, s->current_digits - max); - s->current_digits -= max; - } - buf[max] = '\0'; - return max; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s, - tone_report_func_t callback, - void *user_data) -{ - s->realtime_callback = callback; - s->realtime_callback_data = user_data; - s->duration = 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) dtmf_rx_parms(dtmf_rx_state_t *s, - int filter_dialtone, - float twist, - float reverse_twist, - float threshold) -{ - float x; - - if (filter_dialtone >= 0) - { - s->z350[0] = 0.0f; - s->z350[1] = 0.0f; - s->z440[0] = 0.0f; - s->z440[1] = 0.0f; - s->filter_dialtone = filter_dialtone; - } - if (twist >= 0) - s->normal_twist = powf(10.0f, twist/10.0f); - if (reverse_twist >= 0) - 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; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) dtmf_rx_get_logging_state(dtmf_rx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, - digits_rx_callback_t callback, - void *user_data) -{ - int i; - - if (s == NULL) - { - if ((s = (dtmf_rx_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, "DTMF"); - s->digits_callback = callback; - s->digits_callback_data = user_data; - s->realtime_callback = NULL; - s->realtime_callback_data = NULL; - s->filter_dialtone = false; - s->normal_twist = DTMF_NORMAL_TWIST; - s->reverse_twist = DTMF_REVERSE_TWIST; - s->threshold = DTMF_THRESHOLD; - - s->in_digit = 0; - s->last_hit = 0; - - 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); - } - 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]); - } - s->energy = FP_SCALE(0.0f); - s->current_sample = 0; - s->lost_digits = 0; - s->current_digits = 0; - s->digits[0] = '\0'; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_rx_release(dtmf_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_rx_free(dtmf_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void dtmf_tx_initialise(void) -{ - int row; - int col; - - if (dtmf_tx_inited) - return; - for (row = 0; row < 4; row++) - { - for (col = 0; col < 4; col++) - { - tone_gen_descriptor_init(&dtmf_digit_tones[row*4 + col], - (int) dtmf_row[row], - DEFAULT_DTMF_TX_LEVEL, - (int) dtmf_col[col], - DEFAULT_DTMF_TX_LEVEL, - DEFAULT_DTMF_TX_ON_TIME, - DEFAULT_DTMF_TX_OFF_TIME, - 0, - 0, - false); - } - } - dtmf_tx_inited = true; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_tx(dtmf_tx_state_t *s, int16_t amp[], int max_samples) -{ - int len; - const char *cp; - int digit; - - len = 0; - if (s->tones.current_section >= 0) - { - /* Deal with the fragment left over from last time */ - len = tone_gen(&s->tones, amp, max_samples); - } - - while (len < max_samples) - { - /* Step to the next digit */ - if ((digit = queue_read_byte(&s->queue.queue)) < 0) - { - /* See if we can get some more digits */ - if (s->callback == NULL) - break; - s->callback(s->callback_data); - if ((digit = queue_read_byte(&s->queue.queue)) < 0) - break; - } - if (digit == 0) - continue; - if ((cp = strchr(dtmf_positions, digit)) == NULL) - continue; - tone_gen_init(&s->tones, &dtmf_digit_tones[cp - dtmf_positions]); - s->tones.tone[0].gain = s->low_level; - s->tones.tone[1].gain = s->high_level; - s->tones.duration[0] = s->on_time; - s->tones.duration[1] = s->off_time; - len += tone_gen(&s->tones, amp + len, max_samples - len); - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_tx_put(dtmf_tx_state_t *s, const char *digits, int len) -{ - size_t space; - - /* This returns the number of characters that would not fit in the buffer. - The buffer will only be loaded if the whole string of digits will fit, - in which case zero is returned. */ - if (len < 0) - { - if ((len = strlen(digits)) == 0) - return 0; - } - if ((space = queue_free_space(&s->queue.queue)) < (size_t) len) - return len - (int) space; - if (queue_write(&s->queue.queue, (const uint8_t *) digits, len) >= 0) - return 0; - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) dtmf_tx_set_level(dtmf_tx_state_t *s, int level, int twist) -{ - s->low_level = dds_scaling_dbm0f((float) level); - s->high_level = dds_scaling_dbm0f((float) (level + twist)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) dtmf_tx_set_timing(dtmf_tx_state_t *s, int on_time, int off_time) -{ - s->on_time = ((on_time >= 0) ? on_time : DEFAULT_DTMF_TX_ON_TIME)*SAMPLE_RATE/1000; - s->off_time = ((off_time >= 0) ? off_time : DEFAULT_DTMF_TX_OFF_TIME)*SAMPLE_RATE/1000; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s, - digits_tx_callback_t callback, - void *user_data) -{ - if (s == NULL) - { - if ((s = (dtmf_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - if (!dtmf_tx_inited) - dtmf_tx_initialise(); - s->callback = callback; - s->callback_data = user_data; - tone_gen_init(&s->tones, &dtmf_digit_tones[0]); - dtmf_tx_set_level(s, DEFAULT_DTMF_TX_LEVEL, 0); - dtmf_tx_set_timing(s, -1, -1); - queue_init(&s->queue.queue, MAX_DTMF_DIGITS, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC); - s->tones.current_section = -1; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_tx_release(dtmf_tx_state_t *s) -{ - queue_release(&s->queue.queue); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) dtmf_tx_free(dtmf_tx_state_t *s) -{ - dtmf_tx_release(s); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/echo.c b/libs/spandsp/src/echo.c deleted file mode 100644 index 70c1730bc7..0000000000 --- a/libs/spandsp/src/echo.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * echo.c - An echo cancellor, suitable for electrical and acoustic - * cancellation. This code does not currently comply with - * any relevant standards (e.g. G.164/5/7/8). One day.... - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 2003 Steve Underwood - * - * Based on a bit from here, a bit from there, eye of toad, - * ear of bat, etc - plus, of course, my own 2 cents. - * - * 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 */ - -/* TODO: - Finish the echo suppressor option, however nasty suppression may be. - Add an option to reintroduce side tone at -24dB under appropriate conditions. - Improve double talk detector (iterative!) -*/ - -/* We need to differentiate between transmitted energy which will train the echo - canceller well (voice, white noise, and other broadband sources) and energy - which will train it badly (supervisory tones, DTMF, whistles, and other - narrowband sources). There are many ways this might be done. This canceller uses - a method based on the autocorrelation qualities of the transmitted signal. A rather - peaky autocorrelation function is a clear sign of a narrowband signal. We only need - perform the autocorrelation at well spaced intervals, so the compute load is not too - great. Multiple successive autocorrelation functions with a similar peaky shape are a - clear indication of a stationary narrowband signal. Using TKEO, it should be possible to - greatly reduce the compute requirement for narrowband detection. */ - -/* The FIR taps must be adapted as 32 bit values, to get the necessary finesse - in the adaption process. However, they are applied as 16 bit values (bits 30-15 - of the 32 bit values) in the FIR. For the working 16 bit values, we need 4 sets. - - 3 of the 16 bit sets are used on a rotating basis. Normally the canceller steps - round these 3 sets at regular intervals. Any time we detect double talk, we can go - back to the set from two steps ago with reasonable assurance it is a well adapted - set. We cannot just go back one step, as we may have rotated the sets just before - double talk or tone was detected, and that set may already be somewhat corrupted. - - When narrowband energy is detected we need to continue adapting to it, to echo - cancel it. However, the adaption will almost certainly be going astray. Broadband - (or even complex sequences of narrowband) energy will normally lead to a well - trained cancellor, with taps matching the impulse response of the channel. - For stationary narrowband energy, there is usually has an infinite number of - alternative tap sets which will cancel it well. A previously well trained set of - taps will tend to drift amongst the alternatives. When broadband energy resumes, the - taps may be a total mismatch for the signal, and could even amplify rather than - attenuate the echo. The solution is to use a fourth set of 16 bit taps. When we first - detect the narrowband energy we save the oldest of the group of three sets, but do - not change back to an older set. We let the canceller cancel, and it adaption drift - while the narrowband energy is present. When we detect the narrowband energy has ceased, - we switch to using the fourth set of taps which was saved. - - When we revert to an older set of taps, we must replace both the 16 bit and 32 bit - working tap sets. The saved 16 bit values are good enough to also be used as a replacement - for the 32 bit values. We loose the fractions, but they should soon settle down in a - reasonable way. */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/saturated.h" -#include "spandsp/dc_restore.h" -#include "spandsp/bit_operations.h" -#include "spandsp/echo.h" - -#include "spandsp/private/echo.h" - -#if !defined(NULL) -#define NULL (void *) 0 -#endif - -#define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */ - -#define MIN_TX_POWER_FOR_ADAPTION 64*64 -#define MIN_RX_POWER_FOR_ADAPTION 64*64 - -static int narrowband_detect(echo_can_state_t *ec) -{ - int k; - int i; - float temp; - float scale; - float sf[128]; - float f_acf[128]; - int32_t acf[28]; - int score; - int len = 32; - int alen = 9; - - k = ec->curr_pos; - for (i = 0; i < len; i++) - { - sf[i] = ec->fir_state.history[k++]; - if (k >= 256) - k = 0; - } - for (k = 0; k < alen; k++) - { - temp = 0; - for (i = k; i < len; i++) - temp += sf[i]*sf[i - k]; - f_acf[k] = temp; - } - scale = 0x1FFFFFFF/f_acf[0]; - for (k = 0; k < alen; k++) - acf[k] = (int32_t) (f_acf[k]*scale); - score = 0; - for (i = 0; i < 9; i++) - { - if (ec->last_acf[i] >= 0 && acf[i] >= 0) - { - if ((ec->last_acf[i] >> 1) < acf[i] && acf[i] < (ec->last_acf[i] << 1)) - score++; - } - else if (ec->last_acf[i] < 0 && acf[i] < 0) - { - if ((ec->last_acf[i] >> 1) > acf[i] && acf[i] > (ec->last_acf[i] << 1)) - score++; - } - } - memcpy(ec->last_acf, acf, alen*sizeof(ec->last_acf[0])); - return score; -} - -static __inline__ void lms_adapt(echo_can_state_t *ec, int factor) -{ - int i; - -#if 0 - mmx_t *mmx_taps; - mmx_t *mmx_coeffs; - mmx_t *mmx_hist; - mmx_t mmx; - - mmx.w[0] = - mmx.w[1] = - mmx.w[2] = - mmx.w[3] = factor; - mmx_hist = (mmx_t *) &fir->history[fir->curr_pos]; - mmx_taps = (mmx_t *) &fir->taps; - mmx_coeffs = (mmx_t *) fir->coeffs; - i = fir->taps; - movq_m2r(mmx, mm0); - while (i > 0) - { - movq_m2r(mmx_hist[0], mm1); - movq_m2r(mmx_taps[0], mm0); - movq_m2r(mmx_taps[1], mm1); - movq_r2r(mm1, mm2); - pmulhw(mm0, mm1); - pmullw(mm0, mm2); - - pmaddwd_r2r(mm1, mm0); - pmaddwd_r2r(mm3, mm2); - paddd_r2r(mm0, mm4); - paddd_r2r(mm2, mm4); - movq_r2m(mm0, mmx_taps[0]); - movq_r2m(mm1, mmx_taps[0]); - movq_r2m(mm2, mmx_coeffs[0]); - mmx_taps += 2; - mmx_coeffs += 1; - mmx_hist += 1; - i -= 4; - ) - emms(); -#elif 0 - /* Update the FIR taps */ - for (i = ec->taps - 1; i >= 0; i--) - { - /* Leak to avoid the coefficients drifting beyond the ability of the - adaption process to bring them back under control. */ - ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23); - ec->fir_taps32[i] += (ec->fir_state.history[i + ec->curr_pos]*factor); - ec->latest_correction = (ec->fir_state.history[i + ec->curr_pos]*factor); - ec->fir_taps16[ec->tap_set][i] = ec->fir_taps32[i] >> 15; - } -#else - int offset1; - int offset2; - - /* Update the FIR taps */ - offset2 = ec->curr_pos; - offset1 = ec->taps - offset2; - for (i = ec->taps - 1; i >= offset1; i--) - { - ec->fir_taps32[i] += (ec->fir_state.history[i - offset1]*factor); - ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15); - } - for ( ; i >= 0; i--) - { - ec->fir_taps32[i] += (ec->fir_state.history[i + offset2]*factor); - ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15); - } -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(echo_can_state_t *) echo_can_init(int len, int adaption_mode) -{ - echo_can_state_t *ec; - int i; - int j; - - 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 *) span_alloc(ec->taps*sizeof(int32_t))) == NULL) - { - 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 *) span_alloc(ec->taps*sizeof(int16_t))) == NULL) - { - for (j = 0; j < i; j++) - 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)); - } - fir16_create(&ec->fir_state, - ec->fir_taps16[0], - ec->taps); - ec->rx_power_threshold = 10000000; - ec->geigel_max = 0; - ec->geigel_lag = 0; - ec->dtd_onset = false; - ec->tap_set = 0; - ec->tap_rotate_counter = 1600; - ec->cng_level = 1000; - echo_can_adaption_mode(ec, adaption_mode); - return ec; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) echo_can_release(echo_can_state_t *ec) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) echo_can_free(echo_can_state_t *ec) -{ - int i; - - fir16_free(&ec->fir_state); - span_free(ec->fir_taps32); - for (i = 0; i < 4; i++) - span_free(ec->fir_taps16[i]); - span_free(ec); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode) -{ - ec->adaption_mode = adaption_mode; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) echo_can_flush(echo_can_state_t *ec) -{ - int i; - - for (i = 0; i < 4; i++) - ec->tx_power[i] = 0; - for (i = 0; i < 3; i++) - ec->rx_power[i] = 0; - ec->clean_rx_power = 0; - ec->nonupdate_dwell = 0; - - fir16_flush(&ec->fir_state); - ec->fir_state.curr_pos = ec->taps - 1; - memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t)); - for (i = 0; i < 4; i++) - memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t)); - - ec->curr_pos = ec->taps - 1; - - ec->supp_test1 = 0; - ec->supp_test2 = 0; - ec->supp1 = 0; - ec->supp2 = 0; - ec->vad = 0; - ec->cng_level = 1000; - ec->cng_filter = 0; - - ec->geigel_max = 0; - ec->geigel_lag = 0; - ec->dtd_onset = false; - ec->tap_set = 0; - ec->tap_rotate_counter = 1600; - - ec->latest_correction = 0; - - memset(ec->last_acf, 0, sizeof(ec->last_acf)); - ec->narrowband_count = 0; - ec->narrowband_score = 0; -} -/*- End of function --------------------------------------------------------*/ - -int sample_no = 0; - -SPAN_DECLARE(void) echo_can_snapshot(echo_can_state_t *ec) -{ - memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps*sizeof(int16_t)); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t echo_can_hpf(int32_t coeff[2], int16_t amp) -{ - int32_t z; - - /* - Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required - otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta) - only real axis. Some chip sets (like Si labs) don't need - this, but something like a $10 X100P card does. Any DC really slows - down convergence. - - Note: removes some low frequency from the signal, this reduces - the speech quality when listening to samples through headphones - but may not be obvious through a telephone handset. - - Note that the 3dB frequency in radians is approx Beta, e.g. for - Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz. - - This is one of the classic DC removal filters, adjusted to provide sufficient - bass rolloff to meet the above requirement to protect hybrids from things that - upset them. The difference between successive samples produces a lousy HPF, and - then a suitably placed pole flattens things out. The final result is a nicely - rolled off bass end. The filtering is implemented with extended fractional - precision, which noise shapes things, giving very clean DC removal. - - Make sure the gain of the HPF is 1.0. The first can still saturate a little under - impulse conditions, and it might roll to 32768 and need clipping on sustained peak - level signals. However, the scale of such clipping is small, and the error due to - any saturation should not markedly affect the downstream processing. */ - z = amp << 15; - z -= (z >> 4); - coeff[0] += z - (coeff[0] >> 3) - coeff[1]; - coeff[1] = z; - z = coeff[0] >> 15; - - return saturate16(z); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx) -{ - int32_t echo_value; - int clean_rx; - int nsuppr; - int score; - int i; - -sample_no++; - if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) - rx = echo_can_hpf(ec->rx_hpf, rx); - - ec->latest_correction = 0; - /* Evaluate the echo - i.e. apply the FIR filter */ - /* Assume the gain of the FIR does not exceed unity. Exceeding unity - would seem like a rather poor thing for an echo cancellor to do :) - This means we can compute the result with a total disregard for - overflows. 16bits x 16bits -> 31bits, so no overflow can occur in - any multiply. While accumulating we may overflow and underflow the - 32 bit scale often. However, if the gain does not exceed unity, - everything should work itself out, and the final result will be - OK, without any saturation logic. */ - /* Overflow is very much possible here, and we do nothing about it because - of the compute costs */ - /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound - bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems - best */ - echo_value = fir16(&ec->fir_state, tx); - - /* And the answer is..... */ - clean_rx = rx - echo_value; -printf("echo is %" PRId32 "\n", echo_value); - /* That was the easy part. Now we need to adapt! */ - if (ec->nonupdate_dwell > 0) - ec->nonupdate_dwell--; - - /* Calculate short term power levels using very simple single pole IIRs */ - /* TODO: Is the nasty modulus approach the fastest, or would a real - tx*tx power calculation actually be faster? Using the squares - makes the numbers grow a lot! */ - ec->tx_power[3] += ((abs(tx) - ec->tx_power[3]) >> 5); - ec->tx_power[2] += ((tx*tx - ec->tx_power[2]) >> 8); - ec->tx_power[1] += ((tx*tx - ec->tx_power[1]) >> 5); - ec->tx_power[0] += ((tx*tx - ec->tx_power[0]) >> 3); - ec->rx_power[1] += ((rx*rx - ec->rx_power[1]) >> 6); - ec->rx_power[0] += ((rx*rx - ec->rx_power[0]) >> 3); - ec->clean_rx_power += ((clean_rx*clean_rx - ec->clean_rx_power) >> 6); - - score = 0; - /* If there is very little being transmitted, any attempt to train is - futile. We would either be training on the far end's noise or signal, - the channel's own noise, or our noise. Either way, this is hardly good - training, so don't do it (avoid trouble). */ - if (ec->tx_power[0] > MIN_TX_POWER_FOR_ADAPTION) - { - /* If the received power is very low, either we are sending very little or - we are already well adapted. There is little point in trying to improve - the adaption under these circumstances, so don't do it (reduce the - compute load). */ - if (ec->tx_power[1] > ec->rx_power[0]) - { - /* There is no (or little) far-end speech. */ - if (ec->nonupdate_dwell == 0) - { - if (++ec->narrowband_count >= 160) - { - ec->narrowband_count = 0; - score = narrowband_detect(ec); -printf("Do the narrowband test %d at %d\n", score, ec->curr_pos); - if (score > 6) - { - if (ec->narrowband_score == 0) - memcpy(ec->fir_taps16[3], ec->fir_taps16[(ec->tap_set + 1)%3], ec->taps*sizeof(int16_t)); - ec->narrowband_score += score; - } - else - { - if (ec->narrowband_score > 200) - { -printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no); - memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[3], ec->taps*sizeof(int16_t)); - memcpy(ec->fir_taps16[(ec->tap_set - 1)%3], ec->fir_taps16[3], ec->taps*sizeof(int16_t)); - for (i = 0; i < ec->taps; i++) - ec->fir_taps32[i] = ec->fir_taps16[3][i] << 15; - ec->tap_rotate_counter = 1600; - } - ec->narrowband_score = 0; - } - } - ec->dtd_onset = false; - if (--ec->tap_rotate_counter <= 0) - { -printf("Rotate to %d at %d\n", ec->tap_set, sample_no); - ec->tap_rotate_counter = 1600; - ec->tap_set++; - if (ec->tap_set > 2) - ec->tap_set = 0; - ec->fir_state.coeffs = ec->fir_taps16[ec->tap_set]; - } - /* ... and we are not in the dwell time from previous speech. */ - if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && ec->narrowband_score == 0) - { - //nsuppr = saturate16((clean_rx << 16)/ec->tx_power[1]); - //nsuppr = clean_rx/ec->tx_power[1]; - /* If a sudden surge in signal level (e.g. the onset of a tone - burst) cause an abnormally high instantaneous to average - signal power ratio, we could kick the adaption badly in the - wrong direction. This is because the tx_power takes too long - to react and rise. We need to stop too rapid adaption to the - new signal. We normalise to a value derived from the - instantaneous signal if it exceeds the peak by too much. */ - nsuppr = clean_rx; - /* Divide isn't very quick, but the "where is the top bit" and shift - instructions are single cycle. */ - if (tx > 4*ec->tx_power[3]) - i = top_bit(tx) - 8; - else - i = top_bit(ec->tx_power[3]) - 8; - if (i > 0) - nsuppr >>= i; - lms_adapt(ec, nsuppr); - } - } - //printf("%10d %10d %10d %10d %10d\n", rx, clean_rx, nsuppr, ec->tx_power[1], ec->rx_power[1]); - //printf("%.4f\n", (float) ec->rx_power[1]/(float) ec->clean_rx_power); - } - else - { - if (!ec->dtd_onset) - { -printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no); - memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[(ec->tap_set + 1)%3], ec->taps*sizeof(int16_t)); - memcpy(ec->fir_taps16[(ec->tap_set - 1)%3], ec->fir_taps16[(ec->tap_set + 1)%3], ec->taps*sizeof(int16_t)); - 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->nonupdate_dwell = NONUPDATE_DWELL_TIME; - } - } - - if (ec->rx_power[1]) - ec->vad = (8000*ec->clean_rx_power)/ec->rx_power[1]; - else - ec->vad = 0; - if (ec->rx_power[1] > 2048*2048 && ec->clean_rx_power > 4*ec->rx_power[1]) - { - /* The EC seems to be making things worse, instead of better. Zap it! */ - memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t)); - for (i = 0; i < 4; i++) - memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t)); - } - -#if defined(XYZZY) - if ((ec->adaption_mode & ECHO_CAN_USE_SUPPRESSOR)) - { - ec->supp_test1 += (ec->fir_state.history[ec->curr_pos] - ec->fir_state.history[(ec->curr_pos - 7) & ec->tap_mask]); - ec->supp_test2 += (ec->fir_state.history[(ec->curr_pos - 24) & ec->tap_mask] - ec->fir_state.history[(ec->curr_pos - 31) & ec->tap_mask]); - if (ec->supp_test1 > 42 && ec->supp_test2 > 42) - supp_change = 25; - else - supp_change = 50; - supp = supp_change + k1*ec->supp1 + k2*ec->supp2; - ec->supp2 = ec->supp1; - ec->supp1 = supp; - clean_rx *= (1 - supp); - } -#endif - - if ((ec->adaption_mode & ECHO_CAN_USE_NLP)) - { - /* Non-linear processor - a fancy way to say "zap small signals, to avoid - residual echo due to (uLaw/ALaw) non-linearity in the channel.". */ - if (ec->rx_power[1] < 30000000) - { - if (!ec->cng) - { - ec->cng_level = ec->clean_rx_power; - ec->cng = true; - } - if ((ec->adaption_mode & ECHO_CAN_USE_CNG)) - { - /* Very elementary comfort noise generation */ - /* Just random numbers rolled off very vaguely Hoth-like */ - ec->cng_rndnum = 1664525U*ec->cng_rndnum + 1013904223U; - ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5*ec->cng_filter) >> 3; - clean_rx = (ec->cng_filter*ec->cng_level) >> 17; - /* TODO: A better CNG, with more accurate (tracking) spectral shaping! */ - } - else - { - clean_rx = 0; - } -//clean_rx = -16000; - } - else - { - ec->cng = false; - } - } - else - { - ec->cng = false; - } - -printf("Narrowband score %4d %5d at %d\n", ec->narrowband_score, score, sample_no); - /* Roll around the rolling buffer */ - if (ec->curr_pos <= 0) - ec->curr_pos = ec->taps; - ec->curr_pos--; - return (int16_t) clean_rx; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx) -{ - if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) - tx = echo_can_hpf(ec->tx_hpf, tx); - return tx; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/fax.c b/libs/spandsp/src/fax.c deleted file mode 100644 index b34bb8231e..0000000000 --- a/libs/spandsp/src/fax.c +++ /dev/null @@ -1,530 +0,0 @@ -//#define LOG_FAX_AUDIO -/* - * SpanDSP - a series of DSP components for telephony - * - * fax.c - Analogue line ITU T.30 FAX transfer processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2005, 2006 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 "floating_fudge.h" -#include -#include -#include -#if defined(LOG_FAX_AUDIO) -#include -#endif -#include - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/queue.h" -#include "spandsp/dc_restore.h" -#include "spandsp/vector_int.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/hdlc.h" -#include "spandsp/silence_gen.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/fsk.h" -#include "spandsp/modem_connect_tones.h" -#include "spandsp/v8.h" -#include "spandsp/v29tx.h" -#include "spandsp/v29rx.h" -#include "spandsp/v27ter_tx.h" -#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" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" - -#include "spandsp/t30_fcf.h" -#include "spandsp/t35.h" -#include "spandsp/t30.h" -#include "spandsp/t30_api.h" -#include "spandsp/t30_logging.h" - -#include "spandsp/fax_modems.h" -#include "spandsp/fax.h" - -#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" -#include "spandsp/private/v27ter_rx.h" -#include "spandsp/private/v29tx.h" -#include "spandsp/private/v29rx.h" -#include "spandsp/private/hdlc.h" -#include "spandsp/private/fax_modems.h" -#include "spandsp/private/timezone.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" -#include "spandsp/private/t30.h" -#include "spandsp/private/fax.h" - -#define HDLC_FRAMING_OK_THRESHOLD 8 - -static void tone_detected(void *user_data, int tone, int level, int delay) -{ - t30_state_t *s; - - s = (t30_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level); -} -/*- End of function --------------------------------------------------------*/ - -static void v8_handler(void *user_data, v8_parms_t *result) -{ - fax_state_t *s; - - s = (fax_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "V.8 report received\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_underflow_handler(void *user_data) -{ - t30_state_t *s; - - s = (t30_state_t *) user_data; - t30_front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_rx(fax_state_t *s, int16_t *amp, int len) -{ - int i; - -#if defined(LOG_FAX_AUDIO) - if (s->modems.audio_rx_log >= 0) - write(s->modems.audio_rx_log, amp, len*sizeof(int16_t)); -#endif - for (i = 0; i < len; i++) - amp[i] = dc_restore(&s->modems.dc_restore, amp[i]); - /*endfor*/ - if (s->modems.rx_handler) - s->modems.rx_handler(s->modems.rx_user_data, amp, len); - /*endif*/ - t30_timer_update(&s->t30, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_rx_fillin(fax_state_t *s, int len) -{ - /* To mitigate the effect of lost packets on a packet network we should - try to sustain the status quo. If there is no receive modem running, keep - things that way. If there is a receive modem running, try to sustain its - operation, without causing a phase hop, or letting its adaptive functions - diverge. */ -#if defined(LOG_FAX_AUDIO) - if (s->modems.audio_rx_log >= 0) - { - int i; -#if defined(_MSC_VER) - int16_t *amp = (int16_t *) _alloca(sizeof(int16_t)*len); -#else - int16_t amp[len]; -#endif - - vec_zeroi16(amp, len); - write(s->modems.audio_rx_log, amp, len*sizeof(int16_t)); - } - /*endif*/ -#endif - /* Call the fillin function of the current modem (if there is one). */ - s->modems.rx_fillin_handler(s->modems.rx_fillin_user_data, len); - t30_timer_update(&s->t30, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len) -{ - int len; -#if defined(LOG_FAX_AUDIO) - int required_len; - - required_len = max_len; -#endif - len = 0; - while (s->modems.transmit && (len += s->modems.tx_handler(s->modems.tx_user_data, &[len], max_len - len)) < max_len) - { - /* 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*/ - } - /*endwhile*/ - if (s->modems.transmit_on_idle) - { - /* 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(&[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; -} -/*- End of function --------------------------------------------------------*/ - -static void fax_set_rx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) -{ - fax_state_t *s; - fax_modems_state_t *t; - - s = (fax_state_t *) user_data; - t = &s->modems; - span_log(&s->logging, SPAN_LOG_FLOW, "Set rx type %d\n", type); - if (t->current_rx_type == type) - return; - /*endif*/ - t->current_rx_type = type; - t->rx_bit_rate = bit_rate; - 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); - break; - case T30_MODEM_V17: - fax_modems_start_fast_modem(t, FAX_MODEM_V17_RX, bit_rate, short_train, use_hdlc); - break; - case T30_MODEM_V27TER: - fax_modems_start_fast_modem(t, FAX_MODEM_V27TER_RX, bit_rate, short_train, use_hdlc); - break; - case T30_MODEM_V29: - fax_modems_start_fast_modem(t, FAX_MODEM_V29_RX, bit_rate, short_train, use_hdlc); - break; - case T30_MODEM_DONE: - span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); - /* Fall through */ - default: - fax_modems_set_rx_handler(t, (span_rx_handler_t) &span_dummy_rx, s, (span_rx_fillin_handler_t) &span_dummy_rx_fillin, s); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) -{ - fax_state_t *s; - fax_modems_state_t *t; - int tone; - - s = (fax_state_t *) user_data; - t = &s->modems; - span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); - if (t->current_tx_type == type) - return; - /*endif*/ - 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; - 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; - break; - case T30_MODEM_V21: - fax_modems_start_slow_modem(t, FAX_MODEM_V21_TX); - /* The spec says 1s +-15% of preamble. So, the minimum is 32 octets. */ - fax_modems_hdlc_tx_flags(t, 32); - /* Pause before switching from phase C, as per T.30 5.3.2.2. If we omit this, the receiver - might not see the carrier fall between the high speed and low speed sections. In practice, - a 75ms gap before any V.21 transmission is harmless, adds little to the overall length of - a call, and ensures the receiving end is ready. */ - 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; - break; - case T30_MODEM_V17: - silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - /* For any fast modem, set 200ms of preamble flags */ - fax_modems_hdlc_tx_flags(t, bit_rate/(8*5)); - 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; - break; - case T30_MODEM_V27TER: - silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - /* For any fast modem, set 200ms of preamble flags */ - fax_modems_hdlc_tx_flags(t, bit_rate/(8*5)); - 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; - break; - case T30_MODEM_V29: - silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - /* For any fast modem, set 200ms of preamble flags */ - fax_modems_hdlc_tx_flags(t, bit_rate/(8*5)); - 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; - break; - case T30_MODEM_DONE: - span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); - /* Fall through */ - default: - 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; - break; - } - /*endswitch*/ - t->tx_bit_rate = bit_rate; - t->current_tx_type = type; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_set_transmit_on_idle(fax_state_t *s, int transmit_on_idle) -{ - s->modems.transmit_on_idle = transmit_on_idle; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_set_tep_mode(fax_state_t *s, int use_tep) -{ - fax_modems_set_tep_mode(&s->modems, use_tep); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t30_state_t *) fax_get_t30_state(fax_state_t *s) -{ - return &s->t30; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) fax_get_logging_state(fax_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_restart(fax_state_t *s, bool calling_party) -{ - v8_parms_t v8_parms; - - fax_modems_restart(&s->modems); - v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - v8_parms.call_function = V8_CALL_T30_RX; - v8_parms.modulations = V8_MOD_V21; - if (s->t30.supported_modems & T30_SUPPORT_V27TER) - v8_parms.modulations |= V8_MOD_V27TER; - /*endif*/ - if (s->t30.supported_modems & T30_SUPPORT_V29) - v8_parms.modulations |= V8_MOD_V29; - /*endif*/ - if (s->t30.supported_modems & T30_SUPPORT_V17) - v8_parms.modulations |= V8_MOD_V17; - /*endif*/ - if (s->t30.supported_modems & T30_SUPPORT_V34HDX) - v8_parms.modulations |= V8_MOD_V34HDX; - /*endif*/ - v8_parms.protocol = V8_PROTOCOL_NONE; - v8_parms.pcm_modem_availability = 0; - v8_parms.pstn_access = 0; - v8_parms.nsf = -1; - v8_parms.t66 = -1; - v8_restart(&s->v8, calling_party, &v8_parms); - t30_restart(&s->t30, calling_party); -#if defined(LOG_FAX_AUDIO) - { - char buf[100 + 1]; - struct tm *tm; - time_t now; - - time(&now); - tm = localtime(&now); - sprintf(buf, - "/tmp/fax-rx-audio-%p-%02d%02d%02d%02d%02d%02d", - s, - tm->tm_year%100, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - s->modems.audio_rx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666); - sprintf(buf, - "/tmp/fax-tx-audio-%p-%02d%02d%02d%02d%02d%02d", - s, - tm->tm_year%100, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - s->modems.audio_tx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666); - } -#endif - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(fax_state_t *) fax_init(fax_state_t *s, bool calling_party) -{ - v8_parms_t v8_parms; - - if (s == NULL) - { - if ((s = (fax_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - 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, - t30_hdlc_accept, - hdlc_underflow_handler, - t30_non_ecm_put_bit, - t30_non_ecm_get_bit, - tone_detected, - &s->t30); - t30_init(&s->t30, - calling_party, - fax_set_rx_type, - (void *) s, - fax_set_tx_type, - (void *) s, - fax_modems_hdlc_tx_frame, - (void *) &s->modems); - t30_set_supported_modems(&s->t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); - v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - v8_parms.call_function = V8_CALL_T30_RX; - v8_parms.modulations = V8_MOD_V21; - if (s->t30.supported_modems & T30_SUPPORT_V27TER) - v8_parms.modulations |= V8_MOD_V27TER; - /*endif*/ - if (s->t30.supported_modems & T30_SUPPORT_V29) - v8_parms.modulations |= V8_MOD_V29; - /*endif*/ - if (s->t30.supported_modems & T30_SUPPORT_V17) - v8_parms.modulations |= V8_MOD_V17; - /*endif*/ - if (s->t30.supported_modems & T30_SUPPORT_V34HDX) - v8_parms.modulations |= V8_MOD_V34HDX; - /*endif*/ - v8_parms.protocol = V8_PROTOCOL_NONE; - v8_parms.pcm_modem_availability = 0; - v8_parms.pstn_access = 0; - v8_parms.nsf = -1; - v8_parms.t66 = -1; - v8_init(&s->v8, calling_party, &v8_parms, v8_handler, s); - fax_restart(s, calling_party); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_release(fax_state_t *s) -{ - t30_release(&s->t30); - v8_release(&s->v8); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_free(fax_state_t *s) -{ - fax_release(s); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/fax_modems.c b/libs/spandsp/src/fax_modems.c deleted file mode 100644 index 0b405cc246..0000000000 --- a/libs/spandsp/src/fax_modems.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_modems.c - the analogue modem set for fax processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2005, 2006, 2008, 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 "floating_fudge.h" -#include -#include -#include -#if defined(LOG_FAX_AUDIO) -#include -#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" -#include "spandsp/complex.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/crc.h" -#include "spandsp/hdlc.h" -#include "spandsp/silence_gen.h" -#include "spandsp/fsk.h" -#include "spandsp/v29tx.h" -#include "spandsp/v29rx.h" -#include "spandsp/v27ter_tx.h" -#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" -#include "spandsp/private/v27ter_rx.h" -#include "spandsp/private/v29tx.h" -#include "spandsp/private/v29rx.h" -#include "spandsp/private/modem_connect_tones.h" -#include "spandsp/private/hdlc.h" -#include "spandsp/private/fax_modems.h" - -#define HDLC_FRAMING_OK_THRESHOLD 5 - -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 this is a good frame report - i.e. not a status report, or a bad frame - we can - say the current signal source is valid. */ - if (len >= 0 && ok) - s->rx_frame_received = true; - /*endif*/ - if (s->hdlc_accept) - s->hdlc_accept(s->hdlc_accept_user_data, msg, len, ok); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - - if (len == -1) - hdlc_tx_restart(&s->hdlc_tx); - else - hdlc_tx_frame(&s->hdlc_tx, msg, len); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_hdlc_tx_flags(fax_modems_state_t *s, int flags) -{ - hdlc_tx_flags(&s->hdlc_tx, flags); -} -/*- End of function --------------------------------------------------------*/ - -static void v17_rx_status_handler(void *user_data, int status) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->fast_modems.v17_rx)); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &v17_rx, &s->fast_modems.v17_rx, (span_rx_fillin_handler_t) &v17_rx_fillin, &s->fast_modems.v17_rx); - v17_rx_set_modem_status_handler(&s->fast_modems.v17_rx, NULL, s); - break; - } - /*endswitch*/ - s->fast_modems.v17_rx.put_bit(s->fast_modems.v17_rx.put_bit_user_data, status); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - v17_rx(&s->fast_modems.v17_rx, amp, len); - fsk_rx(&s->v21_rx, amp, len); - if (s->rx_frame_received) - { - /* We have received something, and the fast modem has not trained. We must be receiving valid V.21 */ - span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_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); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - v17_rx_fillin(&s->fast_modems.v17_rx, len); - fsk_rx_fillin(&s->v21_rx, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void v27ter_rx_status_handler(void *user_data, int status) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->fast_modems.v27ter_rx)); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &v27ter_rx, &s->fast_modems.v27ter_rx, (span_rx_fillin_handler_t) &v27ter_rx_fillin, &s->fast_modems.v27ter_rx); - v27ter_rx_set_modem_status_handler(&s->fast_modems.v27ter_rx, NULL, s); - break; - } - /*endswitch*/ - s->fast_modems.v27ter_rx.put_bit(s->fast_modems.v27ter_rx.put_bit_user_data, status); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - v27ter_rx(&s->fast_modems.v27ter_rx, amp, len); - fsk_rx(&s->v21_rx, amp, len); - if (s->rx_frame_received) - { - /* We have received something, and the fast modem has not trained. We must be receiving valid V.21 */ - span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_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); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - v27ter_rx_fillin(&s->fast_modems.v27ter_rx, len); - fsk_rx_fillin(&s->v21_rx, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void v29_rx_status_handler(void *user_data, int status) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->fast_modems.v29_rx)); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &v29_rx, &s->fast_modems.v29_rx, (span_rx_fillin_handler_t) &v29_rx_fillin, &s->fast_modems.v29_rx); - v29_rx_set_modem_status_handler(&s->fast_modems.v29_rx, NULL, s); - break; - } - /*endswitch*/ - s->fast_modems.v29_rx.put_bit(s->fast_modems.v29_rx.put_bit_user_data, status); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - v29_rx(&s->fast_modems.v29_rx, amp, len); - fsk_rx(&s->v21_rx, amp, len); - if (s->rx_frame_received) - { - /* We have received something, and the fast modem has not trained. We must be receiving valid V.21 */ - span_log(&s->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_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); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len) -{ - fax_modems_state_t *s; - - s = (fax_modems_state_t *) user_data; - v29_rx_fillin(&s->fast_modems.v29_rx, len); - fsk_rx_fillin(&s->v21_rx, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_start_slow_modem(fax_modems_state_t *s, int which) -{ - switch (which) - { - case FAX_MODEM_V21_RX: - 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); - //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); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &modem_connect_tones_rx, &s->connect_rx, (span_rx_fillin_handler_t) &modem_connect_tones_rx_fillin, &s->connect_rx); - break; - case FAX_MODEM_CNG_TONE_RX: - modem_connect_tones_rx_init(&s->connect_rx, MODEM_CONNECT_TONES_FAX_CNG, s->tone_callback, s->tone_callback_user_data); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &modem_connect_tones_rx, &s->connect_rx, (span_rx_fillin_handler_t) &modem_connect_tones_rx_fillin, &s->connect_rx); - break; - case FAX_MODEM_V21_TX: - fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &fsk_tx, &s->v21_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - case FAX_MODEM_CED_TONE_TX: - modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CED); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &modem_connect_tones_tx, &s->connect_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - case FAX_MODEM_CNG_TONE_TX: - modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &modem_connect_tones_tx, &s->connect_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - } - /*endswitch*/ - s->rx_frame_received = false; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, int bit_rate, int short_train, int hdlc_mode) -{ - put_bit_func_t put_bit; - get_bit_func_t get_bit; - void *get_bit_user_data; - void *put_bit_user_data; - - s->bit_rate = bit_rate; - if (hdlc_mode) - { - get_bit = (get_bit_func_t) hdlc_tx_get_bit; - 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 - { - get_bit = s->get_bit; - get_bit_user_data = s->get_bit_user_data; - put_bit = s->put_bit; - put_bit_user_data = s->put_bit_user_data; - } - /*endif*/ - - /* If we change modems we need to do a complete reinitialisation of the modem, because - the modems use overlapping memory. */ - if (s->fast_modem != which) - { - s->current_rx_type = which; - s->short_train = false; - s->fast_modem = which; - switch (s->fast_modem) - { - case FAX_MODEM_V27TER_RX: - v27ter_rx_init(&s->fast_modems.v27ter_rx, s->bit_rate, 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_init(&s->fast_modems.v29_rx, s->bit_rate, put_bit, put_bit_user_data); - v29_rx_signal_cutoff(&s->fast_modems.v29_rx, -45.5f); - 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); - break; - case FAX_MODEM_V17_RX: - v17_rx_init(&s->fast_modems.v17_rx, s->bit_rate, put_bit, put_bit_user_data); - v17_rx_set_modem_status_handler(&s->fast_modems.v17_rx, v17_rx_status_handler, s); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &fax_modems_v17_v21_rx, s, (span_rx_fillin_handler_t) &fax_modems_v17_v21_rx_fillin, s); - break; - case FAX_MODEM_V27TER_TX: - v27ter_tx_init(&s->fast_modems.v27ter_tx, s->bit_rate, s->use_tep, get_bit, get_bit_user_data); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &v27ter_tx, &s->fast_modems.v27ter_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - case FAX_MODEM_V29_TX: - v29_tx_init(&s->fast_modems.v29_tx, s->bit_rate, s->use_tep, get_bit, get_bit_user_data); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &v29_tx, &s->fast_modems.v29_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - case FAX_MODEM_V17_TX: - v17_tx_init(&s->fast_modems.v17_tx, s->bit_rate, s->use_tep, get_bit, get_bit_user_data); - 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*/ - } - else - { - s->short_train = short_train; - switch (s->fast_modem) - { - case FAX_MODEM_V27TER_RX: - 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_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); - break; - case FAX_MODEM_V17_RX: - v17_rx_restart(&s->fast_modems.v17_rx, s->bit_rate, s->short_train); - v17_rx_set_put_bit(&s->fast_modems.v17_rx, put_bit, put_bit_user_data); - v17_rx_set_modem_status_handler(&s->fast_modems.v17_rx, v17_rx_status_handler, s); - fax_modems_set_rx_handler(s, (span_rx_handler_t) &fax_modems_v17_v21_rx, s, (span_rx_fillin_handler_t) &fax_modems_v17_v21_rx_fillin, s); - break; - case FAX_MODEM_V27TER_TX: - v27ter_tx_restart(&s->fast_modems.v27ter_tx, s->bit_rate, s->use_tep); - v27ter_tx_set_get_bit(&s->fast_modems.v27ter_tx, get_bit, get_bit_user_data); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &v27ter_tx, &s->fast_modems.v27ter_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - case FAX_MODEM_V29_TX: - v29_tx_restart(&s->fast_modems.v29_tx, s->bit_rate, s->use_tep); - v29_tx_set_get_bit(&s->fast_modems.v29_tx, get_bit, get_bit_user_data); - fax_modems_set_tx_handler(s, (span_tx_handler_t) &v29_tx, &s->fast_modems.v29_tx); - fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); - break; - case FAX_MODEM_V17_TX: - v17_tx_restart(&s->fast_modems.v17_tx, s->bit_rate, s->use_tep, s->short_train); - v17_tx_set_get_bit(&s->fast_modems.v17_tx, get_bit, get_bit_user_data); - 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 --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_set_put_bit(fax_modems_state_t *s, put_bit_func_t put_bit, void *user_data) -{ - s->put_bit = put_bit; - s->put_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_set_get_bit(fax_modems_state_t *s, get_bit_func_t get_bit, void *user_data) -{ - s->get_bit = get_bit; - s->get_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_set_rx_handler(fax_modems_state_t *s, - span_rx_handler_t rx_handler, - void *rx_user_data, - span_rx_fillin_handler_t rx_fillin_handler, - void *rx_fillin_user_data) -{ - if (s->deferred_rx_handler_updates) - { - /* Only update the actual handlers if they are not currently sidelined to dummy targets */ - if (s->rx_handler != span_dummy_rx) - s->rx_handler = rx_handler; - /*endif*/ - s->base_rx_handler = rx_handler; - - if (s->rx_fillin_handler != span_dummy_rx_fillin) - s->rx_fillin_handler = rx_fillin_handler; - /*endif*/ - s->base_rx_fillin_handler = rx_fillin_handler; - } - else - { - s->rx_handler = rx_handler; - s->rx_fillin_handler = rx_fillin_handler; - } - /*endif*/ - s->rx_user_data = rx_user_data; - s->rx_fillin_user_data = rx_fillin_user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_set_rx_active(fax_modems_state_t *s, int active) -{ - s->rx_handler = (active) ? s->base_rx_handler : span_dummy_rx; - s->rx_fillin_handler = (active) ? s->base_rx_fillin_handler : span_dummy_rx_fillin; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_set_tx_handler(fax_modems_state_t *s, span_tx_handler_t handler, void *user_data) -{ - s->tx_handler = handler; - s->tx_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fax_modems_set_next_tx_handler(fax_modems_state_t *s, span_tx_handler_t handler, void *user_data) -{ - s->next_tx_handler = handler; - s->next_tx_user_data = user_data; -} -/*- 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; - } - /*endif*/ - /* 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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) fax_modems_get_logging_state(fax_modems_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_restart(fax_modems_state_t *s) -{ - s->current_tx_type = -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, - int use_tep, - hdlc_frame_handler_t hdlc_accept, - hdlc_underflow_handler_t hdlc_tx_underflow, - put_bit_func_t non_ecm_put_bit, - get_bit_func_t non_ecm_get_bit, - tone_report_func_t tone_callback, - void *user_data) -{ - if (s == NULL) - { - if ((s = (fax_modems_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*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) - { - modem_connect_tones_rx_init(&s->connect_rx, - MODEM_CONNECT_TONES_FAX_CNG, - s->tone_callback, - s->tone_callback_user_data); - } - /*endif*/ - dc_restore_init(&s->dc_restore); - - s->get_bit = non_ecm_get_bit; - s->get_bit_user_data = user_data; - s->put_bit = non_ecm_put_bit; - s->put_bit_user_data = user_data; - - s->hdlc_accept = hdlc_accept; - s->hdlc_accept_user_data = user_data; - - hdlc_rx_init(&s->hdlc_rx, false, true, 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_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; - s->rx_fillin_user_data = NULL; - s->tx_handler = (span_tx_handler_t) &silence_gen; - s->tx_user_data = &s->silence_gen; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_release(fax_modems_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fax_modems_free(fax_modems_state_t *s) -{ - if (s) - span_free(s); - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/faxfont.h b/libs/spandsp/src/faxfont.h deleted file mode 100644 index 08ed46ad9d..0000000000 --- a/libs/spandsp/src/faxfont.h +++ /dev/null @@ -1,4642 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * faxfont.h - a simple fixed pitch font for FAX headers - * - * 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. - */ - -#if !defined(_FAXFONT_H_) -#define _FAXFONT_H_ - -static const uint32_t header_font[256][16] = -{ - { /* 0 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 1 */ - 0x0, - 0x0, - 0x3FFC, - 0xC003, - 0xCC33, - 0xC003, - 0xC003, - 0xCFF3, - 0xC3C3, - 0xC003, - 0xC003, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 2 */ - 0x0, - 0x0, - 0x3FFC, - 0xFFFF, - 0xF3CF, - 0xFFFF, - 0xFFFF, - 0xF00F, - 0xFC3F, - 0xFFFF, - 0xFFFF, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 3 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x1E78, - 0x7FFE, - 0x7FFE, - 0x7FFE, - 0x7FFE, - 0x1FF8, - 0x7E0, - 0x180, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 4 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x180, - 0x7E0, - 0x1FF8, - 0x7FFE, - 0x1FF8, - 0x7E0, - 0x180, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 5 */ - 0x0, - 0x0, - 0x0, - 0x3C0, - 0xFF0, - 0xFF0, - 0x7C3E, - 0x7C3E, - 0x7C3E, - 0x63C6, - 0x3C0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 6 */ - 0x0, - 0x0, - 0x0, - 0x180, - 0x7E0, - 0x1FF8, - 0x7FFE, - 0x7FFE, - 0x1FF8, - 0x180, - 0x180, - 0x7E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 7 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0xFF0, - 0xFF0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 8 */ - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFC3F, - 0xF00F, - 0xF00F, - 0xFC3F, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - }, - { /* 9 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFF0, - 0x3C3C, - 0x300C, - 0x300C, - 0x3C3C, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 10 */ - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xF00F, - 0xC3C3, - 0xCFF3, - 0xCFF3, - 0xC3C3, - 0xF00F, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - }, - { /* 11 */ - 0x0, - 0x0, - 0x1FE, - 0x7E, - 0x1F6, - 0x786, - 0x1FE0, - 0x3870, - 0x3870, - 0x3870, - 0x3870, - 0x1FE0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 12 */ - 0x0, - 0x0, - 0xFF0, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0xFF0, - 0x3C0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 13 */ - 0x0, - 0x0, - 0xFFE, - 0xF0E, - 0xFFE, - 0xE00, - 0xE00, - 0xE00, - 0xE00, - 0x3E00, - 0x7E00, - 0x3C00, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 14 */ - 0x0, - 0x0, - 0x1FFE, - 0x1C0E, - 0x1FFE, - 0x1C0E, - 0x1C0E, - 0x1C0E, - 0x1C0E, - 0x1C1E, - 0x3C3E, - 0x7C1C, - 0x3800, - 0x0, - 0x0, - 0x0, - }, - { /* 15 */ - 0x0, - 0x0, - 0x0, - 0x4002, - 0x23C4, - 0x13C8, - 0xE70, - 0x781E, - 0xE70, - 0x13C8, - 0x23C4, - 0x4002, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 16 */ - 0x0, - 0x3000, - 0x3C00, - 0x3F00, - 0x3FC0, - 0x3FF0, - 0x3FF8, - 0x3FF0, - 0x3FC0, - 0x3F00, - 0x3C00, - 0x3000, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 17 */ - 0x0, - 0xC, - 0x3C, - 0xFC, - 0x3FC, - 0xFFC, - 0x1FFC, - 0xFFC, - 0x3FC, - 0xFC, - 0x3C, - 0xC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 18 */ - 0x0, - 0x180, - 0x3C0, - 0xFF0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0xFF0, - 0x3C0, - 0x180, - 0x0, - 0x0, - 0x0, - }, - { /* 19 */ - 0x0, - 0x0, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x0, - 0x3C3C, - 0x3C3C, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 20 */ - 0x0, - 0x0, - 0x3FFE, - 0x71CE, - 0x71CE, - 0x71CE, - 0x3FCE, - 0x1CE, - 0x1CE, - 0x1CE, - 0x1CE, - 0x1CE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 21 */ - 0x0, - 0x3FF0, - 0x7038, - 0x3C18, - 0xFC0, - 0x3CF0, - 0x7038, - 0x7038, - 0x7038, - 0x3CF0, - 0xFC0, - 0x60F0, - 0x7038, - 0x3FF0, - 0x0, - 0x0, - }, - { /* 22 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3FFC, - 0x3FFC, - 0x3FFC, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 23 */ - 0x0, - 0x180, - 0x3C0, - 0xFF0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0xFF0, - 0x3C0, - 0x180, - 0x3FFC, - 0x0, - 0x0, - }, - { /* 24 */ - 0x0, - 0x0, - 0x180, - 0x3C0, - 0xFF0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - }, - { /* 25 */ - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0xFF0, - 0x3C0, - 0x180, - 0x0, - 0x0, - 0x0, - }, - { /* 26 */ - 0x0, - 0x0, - 0x0, - 0x40, - 0x60, - 0x70, - 0x78, - 0x3FFC, - 0x78, - 0x70, - 0x60, - 0x40, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 27 */ - 0x0, - 0x0, - 0x0, - 0x200, - 0x600, - 0xE00, - 0x1E00, - 0x3FFC, - 0x1E00, - 0xE00, - 0x600, - 0x200, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 28 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3800, - 0x3800, - 0x3800, - 0x3800, - 0x3FFE, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 29 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x420, - 0xC30, - 0x1C38, - 0x3FFC, - 0x1C38, - 0xC30, - 0x420, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 30 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x180, - 0x7E0, - 0x7E0, - 0x1FF8, - 0x1FF8, - 0x7FFE, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 31 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFC, - 0xFFFC, - 0x3FF0, - 0x3FF0, - 0xFC0, - 0xFC0, - 0x300, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 32 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 33 */ - 0x0, - 0x0, - 0x3C0, - 0x7E0, - 0x7E0, - 0x7E0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 34 */ - 0x0, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0xC30, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 35 */ - 0x0, - 0x0, - 0x0, - 0x1C38, - 0x1C38, - 0x7FFE, - 0x1C38, - 0x1C38, - 0x1C38, - 0x7FFE, - 0x1C38, - 0x1C38, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 36 */ - 0x0, - 0x1E0, - 0x1E0, - 0x1FF8, - 0x781E, - 0x7806, - 0x7800, - 0x1FF8, - 0x1E, - 0x601E, - 0x781E, - 0x1FF8, - 0x1E0, - 0x1E0, - 0x0, - 0x0, - }, - { /* 37 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x7806, - 0x781E, - 0x78, - 0x1E0, - 0x780, - 0x1E00, - 0x781E, - 0x601E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 38 */ - 0x0, - 0x0, - 0x7E0, - 0x1E78, - 0x1E78, - 0x7E0, - 0x1F9E, - 0x79F8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 39 */ - 0x0, - 0xF00, - 0xF00, - 0xF00, - 0x3C00, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 40 */ - 0x0, - 0x0, - 0xF0, - 0x3C0, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0x3C0, - 0xF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 41 */ - 0x0, - 0x0, - 0xF00, - 0x3C0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0x3C0, - 0xF00, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 42 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C3C, - 0xFF0, - 0x7FFE, - 0xFF0, - 0x3C3C, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 43 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 44 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xF00, - 0x0, - 0x0, - 0x0, - }, - { /* 45 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 46 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 47 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x6, - 0x1E, - 0x78, - 0x1E0, - 0x780, - 0x1E00, - 0x7800, - 0x6000, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 48 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x787E, - 0x799E, - 0x799E, - 0x7E1E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 49 */ - 0x0, - 0x0, - 0x3C0, - 0xFC0, - 0x3FC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 50 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x1E, - 0x78, - 0x1E0, - 0x780, - 0x1E00, - 0x7800, - 0x781E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 51 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x1E, - 0x1E, - 0x7F8, - 0x1E, - 0x1E, - 0x1E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 52 */ - 0x0, - 0x0, - 0x78, - 0x1F8, - 0x7F8, - 0x1E78, - 0x7878, - 0x7FFE, - 0x78, - 0x78, - 0x78, - 0x1FE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 53 */ - 0x0, - 0x0, - 0x7FFE, - 0x7800, - 0x7800, - 0x7800, - 0x7FF8, - 0x7E, - 0x1E, - 0x1E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 54 */ - 0x0, - 0x0, - 0x7E0, - 0x1E00, - 0x7800, - 0x7800, - 0x7FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 55 */ - 0x0, - 0x0, - 0x7FFE, - 0x781E, - 0x1E, - 0x1E, - 0x78, - 0x1E0, - 0x780, - 0x780, - 0x780, - 0x780, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 56 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 57 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x1FFE, - 0x1E, - 0x1E, - 0x1E, - 0x78, - 0x1FE0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 58 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 59 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0xF00, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 60 */ - 0x0, - 0x0, - 0x0, - 0x3C, - 0xF0, - 0x3C0, - 0xF00, - 0x3C00, - 0xF00, - 0x3C0, - 0xF0, - 0x3C, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 61 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3FFC, - 0x0, - 0x0, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 62 */ - 0x0, - 0x0, - 0x0, - 0x3C00, - 0xF00, - 0x3C0, - 0xF0, - 0x3C, - 0xF0, - 0x3C0, - 0xF00, - 0x3C00, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 63 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x78, - 0x1E0, - 0x1E0, - 0x1E0, - 0x0, - 0x1E0, - 0x1E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 64 */ - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x79FE, - 0x79FE, - 0x79FE, - 0x79F8, - 0x7800, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 65 */ - 0x0, - 0x0, - 0x180, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x7FFE, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 66 */ - 0x0, - 0x0, - 0x7FF8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1FF8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x7FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 67 */ - 0x0, - 0x0, - 0x7F8, - 0x1E1E, - 0x7806, - 0x7800, - 0x7800, - 0x7800, - 0x7800, - 0x7806, - 0x1E1E, - 0x7F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 68 */ - 0x0, - 0x0, - 0x7FE0, - 0x1E78, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E78, - 0x7FE0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 69 */ - 0x0, - 0x0, - 0x7FFE, - 0x1E1E, - 0x1E06, - 0x1E60, - 0x1FE0, - 0x1E60, - 0x1E00, - 0x1E06, - 0x1E1E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 70 */ - 0x0, - 0x0, - 0x7FFE, - 0x1E1E, - 0x1E06, - 0x1E60, - 0x1FE0, - 0x1E60, - 0x1E00, - 0x1E00, - 0x1E00, - 0x7F80, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 71 */ - 0x0, - 0x0, - 0x7F8, - 0x1E1E, - 0x7806, - 0x7800, - 0x7800, - 0x79FE, - 0x781E, - 0x781E, - 0x1E1E, - 0x7E6, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 72 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x7FFE, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 73 */ - 0x0, - 0x0, - 0x7F8, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x7F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 74 */ - 0x0, - 0x0, - 0x1FE, - 0x78, - 0x78, - 0x78, - 0x78, - 0x78, - 0x7878, - 0x7878, - 0x7878, - 0x1FE0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 75 */ - 0x0, - 0x0, - 0x7E1E, - 0x1E1E, - 0x1E78, - 0x1E78, - 0x1FE0, - 0x1FE0, - 0x1E78, - 0x1E1E, - 0x1E1E, - 0x7E1E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 76 */ - 0x0, - 0x0, - 0x7F80, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E06, - 0x1E1E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 77 */ - 0x0, - 0x0, - 0x781E, - 0x7E7E, - 0x7FFE, - 0x7FFE, - 0x799E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 78 */ - 0x0, - 0x0, - 0x781E, - 0x7E1E, - 0x7F9E, - 0x7FFE, - 0x79FE, - 0x787E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 79 */ - 0x0, - 0x0, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1E78, - 0x7E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 80 */ - 0x0, - 0x0, - 0x7FF8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1FF8, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E00, - 0x7F80, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 81 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x799E, - 0x79FE, - 0x1FF8, - 0x78, - 0x7E, - 0x0, - 0x0, - }, - { /* 82 */ - 0x0, - 0x0, - 0x7FF8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1FF8, - 0x1E78, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x7E1E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 83 */ - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x1E00, - 0x7E0, - 0x78, - 0x1E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 84 */ - 0x0, - 0x0, - 0x1FFE, - 0x1FFE, - 0x19E6, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x7F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 85 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 86 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1E78, - 0x7E0, - 0x180, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 87 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x799E, - 0x799E, - 0x7FFE, - 0x1E78, - 0x1E78, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 88 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x1E78, - 0x1E78, - 0x7E0, - 0x7E0, - 0x1E78, - 0x1E78, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 89 */ - 0x0, - 0x0, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0xFF0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 90 */ - 0x0, - 0x0, - 0x7FFE, - 0x781E, - 0x601E, - 0x78, - 0x1E0, - 0x780, - 0x1E00, - 0x7806, - 0x781E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 91 */ - 0x0, - 0x0, - 0xFF0, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xF00, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 92 */ - 0x0, - 0x0, - 0x0, - 0x6000, - 0x7800, - 0x7E00, - 0x1F80, - 0x7E0, - 0x1F8, - 0x7E, - 0x1E, - 0x6, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 93 */ - 0x0, - 0x0, - 0xFF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 94 */ - 0x180, - 0x7E0, - 0x1E78, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 95 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0x0, - 0x0, - }, - { /* 96 */ - 0xF00, - 0xF00, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 97 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FE0, - 0x78, - 0x1FF8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 98 */ - 0x0, - 0x0, - 0x7E00, - 0x1E00, - 0x1E00, - 0x1FE0, - 0x1E78, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x79F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 99 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x7800, - 0x7800, - 0x7800, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 100 */ - 0x0, - 0x0, - 0x1F8, - 0x78, - 0x78, - 0x7F8, - 0x1E78, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 101 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x7FFE, - 0x7800, - 0x7800, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 102 */ - 0x0, - 0x0, - 0x7E0, - 0x1E78, - 0x1E18, - 0x1E00, - 0x7F80, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E00, - 0x7F80, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 103 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1F9E, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1FF8, - 0x78, - 0x7878, - 0x1FE0, - 0x0, - }, - { /* 104 */ - 0x0, - 0x0, - 0x7E00, - 0x1E00, - 0x1E00, - 0x1E78, - 0x1F9E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x7E1E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 105 */ - 0x0, - 0x0, - 0x1E0, - 0x1E0, - 0x0, - 0x7E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x7F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 106 */ - 0x0, - 0x0, - 0x1E, - 0x1E, - 0x0, - 0x7E, - 0x1E, - 0x1E, - 0x1E, - 0x1E, - 0x1E, - 0x1E, - 0x1E1E, - 0x1E1E, - 0x7F8, - 0x0, - }, - { /* 107 */ - 0x0, - 0x0, - 0x7E00, - 0x1E00, - 0x1E00, - 0x1E1E, - 0x1E78, - 0x1FE0, - 0x1FE0, - 0x1E78, - 0x1E1E, - 0x7E1E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 108 */ - 0x0, - 0x0, - 0x7E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x7F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 109 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x7E78, - 0x7FFE, - 0x799E, - 0x799E, - 0x799E, - 0x799E, - 0x799E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 110 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x79F8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 111 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 112 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x79F8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1FF8, - 0x1E00, - 0x1E00, - 0x7F80, - 0x0, - }, - { /* 113 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1F9E, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1FF8, - 0x78, - 0x78, - 0x1FE, - 0x0, - }, - { /* 114 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x79F8, - 0x1F9E, - 0x1E06, - 0x1E00, - 0x1E00, - 0x1E00, - 0x7F80, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 115 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x1E00, - 0x7E0, - 0x78, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 116 */ - 0x0, - 0x0, - 0x180, - 0x780, - 0x780, - 0x7FF8, - 0x780, - 0x780, - 0x780, - 0x780, - 0x79E, - 0x1F8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 117 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 118 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x7F8, - 0x1E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 119 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x799E, - 0x799E, - 0x7FFE, - 0x1E78, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 120 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x781E, - 0x1E78, - 0x7E0, - 0x7E0, - 0x7E0, - 0x1E78, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 121 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FFE, - 0x1E, - 0x78, - 0x7FE0, - 0x0, - }, - { /* 122 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x7FFE, - 0x7878, - 0x1E0, - 0x780, - 0x1E00, - 0x781E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 123 */ - 0x0, - 0x0, - 0xFC, - 0x3C0, - 0x3C0, - 0x3C0, - 0xF00, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 124 */ - 0x0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x0, - }, - { /* 125 */ - 0x0, - 0x0, - 0x3F00, - 0x3C0, - 0x3C0, - 0x3C0, - 0xF0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3F00, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 126 */ - 0x0, - 0x0, - 0x1F9E, - 0x79F8, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 127 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x180, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x781E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 128 */ - 0x0, - 0x0, - 0x7F8, - 0x1E1E, - 0x7806, - 0x7800, - 0x7800, - 0x7800, - 0x7806, - 0x1E1E, - 0x7F8, - 0x78, - 0x1E, - 0x1FF8, - 0x0, - 0x0, - }, - { /* 129 */ - 0x0, - 0x0, - 0x7878, - 0x7878, - 0x0, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 130 */ - 0x0, - 0x78, - 0x1E0, - 0x780, - 0x0, - 0x1FF8, - 0x781E, - 0x7FFE, - 0x7800, - 0x7800, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 131 */ - 0x0, - 0x180, - 0x7E0, - 0x1E78, - 0x0, - 0x1FE0, - 0x78, - 0x1FF8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 132 */ - 0x0, - 0x0, - 0x7878, - 0x7878, - 0x0, - 0x1FE0, - 0x78, - 0x1FF8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 133 */ - 0x0, - 0x1E00, - 0x780, - 0x1E0, - 0x0, - 0x1FE0, - 0x78, - 0x1FF8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 134 */ - 0x0, - 0x7E0, - 0x1E78, - 0x7E0, - 0x0, - 0x1FE0, - 0x78, - 0x1FF8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 135 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0xFF0, - 0x3C3C, - 0x3C00, - 0x3C00, - 0x3C3C, - 0xFF0, - 0xF0, - 0x3C, - 0xFF0, - 0x0, - 0x0, - 0x0, - }, - { /* 136 */ - 0x0, - 0x180, - 0x7E0, - 0x1E78, - 0x0, - 0x1FF8, - 0x781E, - 0x7FFE, - 0x7800, - 0x7800, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 137 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x0, - 0x1FF8, - 0x781E, - 0x7FFE, - 0x7800, - 0x7800, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 138 */ - 0x0, - 0x1E00, - 0x780, - 0x1E0, - 0x0, - 0x1FF8, - 0x781E, - 0x7FFE, - 0x7800, - 0x7800, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 139 */ - 0x0, - 0x0, - 0x3C3C, - 0x3C3C, - 0x0, - 0xFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 140 */ - 0x0, - 0x3C0, - 0xFF0, - 0x3C3C, - 0x0, - 0xFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 141 */ - 0x0, - 0x3C00, - 0xF00, - 0x3C0, - 0x0, - 0xFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 142 */ - 0x0, - 0x781E, - 0x781E, - 0x180, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x7FFE, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 143 */ - 0x7E0, - 0x1E78, - 0x7E0, - 0x0, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x7FFE, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 144 */ - 0x1E0, - 0x780, - 0x1E00, - 0x0, - 0x7FFE, - 0x1E1E, - 0x1E00, - 0x1FF8, - 0x1E00, - 0x1E00, - 0x1E1E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 145 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x7878, - 0x1F9E, - 0x79E, - 0x1FFE, - 0x79E0, - 0x79E0, - 0x1E7E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 146 */ - 0x0, - 0x0, - 0x7FE, - 0x1E78, - 0x7878, - 0x7878, - 0x7FFE, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x787E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 147 */ - 0x0, - 0x180, - 0x7E0, - 0x1E78, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 148 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 149 */ - 0x0, - 0x1E00, - 0x780, - 0x1E0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 150 */ - 0x0, - 0x780, - 0x1FE0, - 0x7878, - 0x0, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 151 */ - 0x0, - 0x1E00, - 0x780, - 0x1E0, - 0x0, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 152 */ - 0x0, - 0x0, - 0x781E, - 0x781E, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FFE, - 0x1E, - 0x78, - 0x1FE0, - 0x0, - }, - { /* 153 */ - 0x0, - 0x781E, - 0x781E, - 0x0, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1E78, - 0x7E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 154 */ - 0x0, - 0x781E, - 0x781E, - 0x0, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 155 */ - 0x0, - 0x3C0, - 0x3C0, - 0xFF0, - 0x3C3C, - 0x3C00, - 0x3C00, - 0x3C00, - 0x3C3C, - 0xFF0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 156 */ - 0x0, - 0x7E0, - 0x1E78, - 0x1E18, - 0x1E00, - 0x7F80, - 0x1E00, - 0x1E00, - 0x1E00, - 0x1E00, - 0x7E1E, - 0x7FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 157 */ - 0x0, - 0x0, - 0x3C3C, - 0x3C3C, - 0xFF0, - 0x3C0, - 0x3FFC, - 0x3C0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 158 */ - 0x0, - 0x7FE0, - 0x7878, - 0x7878, - 0x7FE0, - 0x7818, - 0x7878, - 0x79FE, - 0x7878, - 0x7878, - 0x7878, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 159 */ - 0x0, - 0xFC, - 0x3CF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xF3C0, - 0x3F00, - 0x0, - 0x0, - }, - { /* 160 */ - 0x0, - 0x1E0, - 0x780, - 0x1E00, - 0x0, - 0x1FE0, - 0x78, - 0x1FF8, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 161 */ - 0x0, - 0xF0, - 0x3C0, - 0xF00, - 0x0, - 0xFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 162 */ - 0x0, - 0x1E0, - 0x780, - 0x1E00, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 163 */ - 0x0, - 0x1E0, - 0x780, - 0x1E00, - 0x0, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x7878, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 164 */ - 0x0, - 0x0, - 0x1F9E, - 0x79F8, - 0x0, - 0x79F8, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 165 */ - 0x1F9E, - 0x79F8, - 0x0, - 0x781E, - 0x7E1E, - 0x7F9E, - 0x7FFE, - 0x79FE, - 0x787E, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 166 */ - 0x0, - 0xFF0, - 0x3CF0, - 0x3CF0, - 0xFFC, - 0x0, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 167 */ - 0x0, - 0x7E0, - 0x1E78, - 0x1E78, - 0x7E0, - 0x0, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 168 */ - 0x0, - 0x0, - 0x780, - 0x780, - 0x0, - 0x780, - 0x780, - 0x1E00, - 0x7800, - 0x781E, - 0x781E, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 169 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFC, - 0xF000, - 0xF000, - 0xF000, - 0xF000, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 170 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFC, - 0x3C, - 0x3C, - 0x3C, - 0x3C, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 171 */ - 0x0, - 0x7000, - 0x7000, - 0x700C, - 0x703C, - 0x70F0, - 0x3C0, - 0xF00, - 0x3C00, - 0xF0FC, - 0xC30E, - 0x3C, - 0xF0, - 0x3FE, - 0x0, - 0x0, - }, - { /* 172 */ - 0x0, - 0x7000, - 0x7000, - 0x700C, - 0x703C, - 0x70F0, - 0x3C0, - 0xF00, - 0x3C3C, - 0xF0FC, - 0xC38C, - 0x7FE, - 0x3C, - 0xFE, - 0x0, - 0x0, - }, - { /* 173 */ - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x7E0, - 0x7E0, - 0x7E0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 174 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xE0E, - 0x3C3C, - 0x7070, - 0x3C3C, - 0xE0E, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 175 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x7070, - 0x3C3C, - 0xE0E, - 0x3C3C, - 0x7070, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 176 */ - 0x303, - 0x3030, - 0x303, - 0x3030, - 0x303, - 0x3030, - 0x303, - 0x3030, - 0x303, - 0x3030, - 0x303, - 0x3030, - 0x303, - 0x3030, - 0x303, - 0x3030, - }, - { /* 177 */ - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - 0xAAAA, - 0x5555, - }, - { /* 178 */ - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - 0xF3F3, - 0x3F3F, - }, - { /* 179 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 180 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 181 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFC0, - 0x3C0, - 0xFFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 182 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 183 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFC, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 184 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFC0, - 0x3C0, - 0xFFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 185 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFF3C, - 0x3C, - 0xFF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 186 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 187 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFC, - 0x3C, - 0xFF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 188 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFF3C, - 0x3C, - 0xFFFC, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 189 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFFFC, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 190 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFC0, - 0x3C0, - 0xFFC0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 191 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFC0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 192 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 193 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 194 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 195 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 196 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 197 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFFF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 198 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FF, - 0x3C0, - 0x3FF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 199 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3F, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 200 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3F, - 0xF00, - 0xFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 201 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFF, - 0xF00, - 0xF3F, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 202 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFF3F, - 0x0, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 203 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0x0, - 0xFF3F, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 204 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3F, - 0xF00, - 0xF3F, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 205 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0x0, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 206 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFF3F, - 0x0, - 0xFF3F, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 207 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFFF, - 0x0, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 208 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 209 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0x0, - 0xFFFF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 210 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 211 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 212 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3FF, - 0x3C0, - 0x3FF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 213 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3FF, - 0x3C0, - 0x3FF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 214 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFF, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 215 */ - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xFFFF, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - 0xF3C, - }, - { /* 216 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFFF, - 0x3C0, - 0xFFFF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 217 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xFFC0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 218 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3FF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 219 */ - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - }, - { /* 220 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - }, - { /* 221 */ - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - 0xFF00, - }, - { /* 222 */ - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - }, - { /* 223 */ - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0xFFFF, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 224 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1F9E, - 0x79F8, - 0x79E0, - 0x79E0, - 0x79E0, - 0x79F8, - 0x1F9E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 225 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x7FF8, - 0x781E, - 0x7FF8, - 0x781E, - 0x781E, - 0x7FF8, - 0x7800, - 0x7800, - 0x7800, - 0x0, - 0x0, - }, - { /* 226 */ - 0x0, - 0x0, - 0x7FFE, - 0x781E, - 0x781E, - 0x7800, - 0x7800, - 0x7800, - 0x7800, - 0x7800, - 0x7800, - 0x7800, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 227 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x7FFE, - 0x7FFE, - 0x1E78, - 0x1E78, - 0x1E78, - 0x1E78, - 0x1E78, - 0x1E78, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 228 */ - 0x0, - 0x0, - 0x0, - 0x7FFE, - 0x781E, - 0x1E00, - 0x780, - 0x1E0, - 0x780, - 0x1E00, - 0x781E, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 229 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FFE, - 0x79E0, - 0x79E0, - 0x79E0, - 0x79E0, - 0x79E0, - 0x1F80, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 230 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1E1E, - 0x1FF8, - 0x1E00, - 0x1E00, - 0x7800, - 0x0, - 0x0, - 0x0, - }, - { /* 231 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x1F9E, - 0x79F8, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x1E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 232 */ - 0x0, - 0x0, - 0x0, - 0x3FFC, - 0x3C0, - 0xFF0, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0xFF0, - 0x3C0, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 233 */ - 0x0, - 0x0, - 0x0, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x7FFE, - 0x781E, - 0x781E, - 0x1E78, - 0x7E0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 234 */ - 0x0, - 0x0, - 0x7E0, - 0x1E78, - 0x781E, - 0x781E, - 0x781E, - 0x1E78, - 0x1E78, - 0x1E78, - 0x1E78, - 0x7E7E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 235 */ - 0x0, - 0x0, - 0x3FC, - 0xF00, - 0x3C0, - 0xF0, - 0xFFC, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0x3C3C, - 0xFF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 236 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3E7C, - 0x73CE, - 0x73CE, - 0x73CE, - 0x3E7C, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 237 */ - 0x0, - 0x0, - 0x0, - 0xF, - 0x3C, - 0x3FFC, - 0xF0FF, - 0xF3CF, - 0xFF0F, - 0x3FFC, - 0x3C00, - 0xF000, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 238 */ - 0x0, - 0x0, - 0x3F0, - 0xF00, - 0x1C00, - 0x1C00, - 0x1FF0, - 0x1C00, - 0x1C00, - 0x1C00, - 0xF00, - 0x3F0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 239 */ - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x781E, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 240 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x7FFE, - 0x0, - 0x0, - 0x7FFE, - 0x0, - 0x0, - 0x7FFE, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 241 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x3FFC, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x3FFC, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 242 */ - 0x0, - 0x0, - 0x0, - 0xF00, - 0x3C0, - 0xF0, - 0x38, - 0xF0, - 0x3C0, - 0xF00, - 0x0, - 0xFF8, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 243 */ - 0x0, - 0x0, - 0x0, - 0xF0, - 0x3C0, - 0xF00, - 0x1C00, - 0xF00, - 0x3C0, - 0xF0, - 0x0, - 0x1FF0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 244 */ - 0x0, - 0x0, - 0xFC, - 0x3CF, - 0x3CF, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - }, - { /* 245 */ - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0x3C0, - 0xF3C0, - 0xF3C0, - 0xF3C0, - 0x3F00, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 246 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x3FFC, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 247 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x1F9E, - 0x79F8, - 0x0, - 0x1F9E, - 0x79F8, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 248 */ - 0x0, - 0x7E0, - 0x1E78, - 0x1E78, - 0x7E0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 249 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 250 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x3C0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 251 */ - 0x0, - 0xFF, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0xF0, - 0x70F0, - 0x38F0, - 0x1CF0, - 0xFF0, - 0x3F0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 252 */ - 0x0, - 0x79E0, - 0x1E78, - 0x1E78, - 0x1E78, - 0x1E78, - 0x1E78, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 253 */ - 0x0, - 0x1F80, - 0x61E0, - 0x780, - 0x1E00, - 0x7860, - 0x7FE0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 254 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x1FF8, - 0x1FF8, - 0x1FF8, - 0x1FF8, - 0x1FF8, - 0x1FF8, - 0x1FF8, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, - { /* 255 */ - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - }, -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/filter_tools.c b/libs/spandsp/src/filter_tools.c deleted file mode 100644 index 4411226074..0000000000 --- a/libs/spandsp/src/filter_tools.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * filter_tools.c - A collection of routines used for filter design. - * - * Written by Steve Underwood - * - * Copyright (C) 2008 Steve Underwood - * - * This includes some elements based on the mkfilter package by - * A.J. Fisher, University of York , November 1996 - * - * 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(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 -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif -#include "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/complex.h" -#include "filter_tools.h" - -#define MAXPZ 8192 -#define SEQ_LEN 8192 -#define MAX_FFT_LEN SEQ_LEN - -static complex_t circle[MAX_FFT_LEN/2]; - -static __inline__ complex_t expj(double theta) -{ - return complex_set(cos(theta), sin(theta)); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ double fix(double x) -{ - /* Nearest integer */ - return (x >= 0.0) ? floor(0.5 + x) : -floor(0.5 - x); -} -/*- End of function --------------------------------------------------------*/ - -static void fftx(complex_t data[], complex_t temp[], int n) -{ - int i; - int h; - int p; - int t; - int i2; - complex_t wkt; - - if (n > 1) - { - h = n/2; - for (i = 0; i < h; i++) - { - i2 = i*2; - temp[i] = data[i2]; /* Even */ - temp[h + i] = data[i2 + 1]; /* Odd */ - } - fftx(&temp[0], &data[0], h); - fftx(&temp[h], &data[h], h); - p = 0; - t = MAX_FFT_LEN/n; - for (i = 0; i < h; i++) - { - wkt = complex_mul(&circle[p], &temp[h + i]); - data[i] = complex_add(&temp[i], &wkt); - data[h + i] = complex_sub(&temp[i], &wkt); - p += t; - } - } -} -/*- End of function --------------------------------------------------------*/ - -void ifft(complex_t data[], int len) -{ - int i; - double x; - complex_t temp[MAX_FFT_LEN]; - - /* A very slow and clunky FFT, that's just fine for filter design. */ - for (i = 0; i < MAX_FFT_LEN/2; i++) - { - x = (2.0*3.1415926535*i)/(double) MAX_FFT_LEN; - circle[i] = expj(x); - } - fftx(data, temp, len); -} -/*- End of function --------------------------------------------------------*/ - -void compute_raised_cosine_filter(double coeffs[], - int len, - int root, - int sinc_compensate, - double alpha, - double beta) -{ - double f; - double x; - double f1; - double f2; - double tau; - complex_t vec[SEQ_LEN]; - int i; - int j; - int h; - - f1 = (1.0 - beta)*alpha; - f2 = (1.0 + beta)*alpha; - tau = 0.5/alpha; - /* (Root) raised cosine */ - for (i = 0; i <= SEQ_LEN/2; i++) - { - f = (double) i/(double) SEQ_LEN; - if (f <= f1) - vec[i] = complex_set(1.0, 0.0); - else if (f <= f2) - vec[i] = complex_set(0.5*(1.0 + cos((3.1415926535*tau/beta)*(f - f1))), 0.0); - else - vec[i] = complex_set(0.0, 0.0); - } - if (root) - { - for (i = 0; i <= SEQ_LEN/2; i++) - vec[i].re = sqrt(vec[i].re); - } - if (sinc_compensate) - { - for (i = 1; i <= SEQ_LEN/2; i++) - { - x = 3.1415926535*(double) i/(double) SEQ_LEN; - vec[i].re *= (x/sin(x)); - } - } - for (i = 0; i <= SEQ_LEN/2; i++) - vec[i].re *= tau; - for (i = 1; i < SEQ_LEN/2; i++) - vec[SEQ_LEN - i] = vec[i]; - ifft(vec, SEQ_LEN); - h = (len - 1)/2; - for (i = 0; i < len; i++) - { - j = (SEQ_LEN - h + i)%SEQ_LEN; - coeffs[i] = vec[j].re/(double) SEQ_LEN; - } -} -/*- End of function --------------------------------------------------------*/ - -void compute_hilbert_transform(double coeffs[], int len) -{ - double x; - int i; - int h; - - h = (len - 1)/2; - coeffs[h] = 0.0; - for (i = 1; i <= h; i++) - { - if ((i & 1)) - { - x = 1.0/(double) i; - coeffs[h + i] = -x; - coeffs[h - i] = x; - } - else - { - coeffs[h + i] = - coeffs[h - i] = 0.0; - } - } -} -/*- End of function --------------------------------------------------------*/ - -void apply_hamming_window(double coeffs[], int len) -{ - double w; - int i; - int h; - - h = (len - 1)/2; - for (i = 1; i <= h; i++) - { - w = 0.53836 - 0.46164*cos(2.0*3.1415926535*(double) (h + i)/(double) (len - 1.0)); - coeffs[h + i] *= w; - coeffs[h - i] *= w; - } -} -/*- End of function --------------------------------------------------------*/ - -void truncate_coeffs(double coeffs[], int len, int bits, int hilbert) -{ - double x; - double fac; - double max; - double scale; - int h; - int i; - - fac = pow(2.0, (double) (bits - 1.0)); - h = (len - 1)/2; - max = (hilbert) ? coeffs[h - 1] : coeffs[h]; /* Max coeff */ - scale = (fac - 1.0)/(fac*max); - for (i = 0; i < len; i++) - { - x = coeffs[i]*scale; /* Scale coeffs so max is (fac - 1.0)/fac */ - coeffs[i] = fix(x*fac)/fac; /* Truncate */ - } -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/filter_tools.h b/libs/spandsp/src/filter_tools.h deleted file mode 100644 index cca1871cfd..0000000000 --- a/libs/spandsp/src/filter_tools.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * filter_tools.h - A collection of routines used for filter design. - * - * Written by Steve Underwood - * - * Copyright (C) 2008 Steve Underwood - * - * Based on: - * mkshape -- design raised cosine FIR filter - * A.J. Fisher, University of York , November 1996 - * - * 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(_FILTER_TOOLS_H_) -#define _FILTER_TOOLS_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -void ifft(complex_t data[], int len); -void apply_hamming_window(double coeffs[], int len); -void truncate_coeffs(double coeffs[], int len, int bits, int hilbert); - -void compute_raised_cosine_filter(double coeffs[], - int len, - int root, - int sinc_compensate, - double alpha, - double beta); - -void compute_hilbert_transform(double coeffs[], int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/floating_fudge.h b/libs/spandsp/src/floating_fudge.h deleted file mode 100644 index a2e46db46d..0000000000 --- a/libs/spandsp/src/floating_fudge.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * floating_fudge.h - A bunch of shims, to use double maths - * functions on platforms which lack the - * float versions with an 'f' at the end, - * and to deal with the vaguaries of lrint(). - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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(_FLOATING_FUDGE_H_) -#define _FLOATING_FUDGE_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if !defined(HAVE_SINF) -static __inline__ float sinf(float x) -{ - return (float) sin((double) x); -} -#endif - -#if !defined(HAVE_COSF) -static __inline__ float cosf(float x) -{ - return (float) cos((double) x); -} -#endif - -#if !defined(HAVE_TANF) -static __inline__ float tanf(float x) -{ - return (float) tan((double) x); -} -#endif - -#if !defined(HAVE_ASINF) -static __inline__ float asinf(float x) -{ - return (float) asin((double) x); -} -#endif - -#if !defined(HAVE_ACOSF) -static __inline__ float acosf(float x) -{ - return (float) acos((double) x); -} -#endif - -#if !defined(HAVE_ATANF) -static __inline__ float atanf(float x) -{ - return (float) atan((double) x); -} - -#endif - -#if !defined(HAVE_ATAN2F) -static __inline__ float atan2f(float y, float x) -{ - return (float) atan2((double) y, (double) x); -} - -#endif - -#if !defined(HAVE_CEILF) -static __inline__ float ceilf(float x) -{ - return (float) ceil((double) x); -} -#endif - -#if !defined(HAVE_FLOORF) -static __inline__ float floorf(float x) -{ - return (float) floor((double) x); -} - -#endif - -#if !defined(HAVE_POWF) -static __inline__ float powf(float x, float y) -{ - return (float) pow((double) x, (double) y); -} -#endif - -#if !defined(HAVE_EXPF) -static __inline__ float expf(float x) -{ - return (float) expf((double) x); -} -#endif - -#if !defined(HAVE_LOGF) -static __inline__ float logf(float x) -{ - return (float) logf((double) x); -} -#endif - -#if !defined(HAVE_LOG10F) -static __inline__ float log10f(float x) -{ - return (float) log10((double) x); -} -#endif - -#if defined(__cplusplus) -} -#endif - -#endif - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/fsk.c b/libs/spandsp/src/fsk.c deleted file mode 100644 index 8b714d1c1d..0000000000 --- a/libs/spandsp/src/fsk.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fsk.c - FSK modem transmit and receive parts - * - * 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 */ - -#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 -#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[] = -{ - { - "V21 ch 1", - 1080 + 100, - 1080 - 100, - -14, - -30, - 300*100 - }, - { - "V21 ch 2", - 1750 + 100, - 1750 - 100, - -14, - -30, - 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, - -14, - -30, - 1200*100 - }, - { - "V23 ch 2", - 420 + 30, - 420 - 30, - -14, - -30, - 75*100 - }, - { - "Bell103 ch 1", - 2125 - 100, - 2125 + 100, - -14, - -30, - 300*100 - }, - { - "Bell103 ch 2", - 1170 - 100, - 1170 + 100, - -14, - -30, - 300*100 - }, - { - "Bell202", - 1700 + 500, - 1700 - 500, - -14, - -30, - 1200*100 - }, - { - "Weitbrecht 45.45", /* Used for US TDD (Telecoms Device for the Deaf) */ - 1600 + 200, - 1600 - 200, - -14, - -30, - 4545 - }, - { - "Weitbrecht 50", /* Used for international TDD (Telecoms Device for the Deaf) */ - 1600 + 200, - 1600 - 200, - -14, - -30, - 50*100 - }, - { - "Weitbrecht 47.6", /* Used for V.18 probing */ - 1600 + 200, - 1600 - 200, - -14, - -30, - 4760 - }, - { - "V21 (110bps) ch 1", - 1080 + 100, - 1080 - 100, - -14, - -30, - 110*100 - } -}; - -SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec) -{ - s->baud_rate = spec->baud_rate; - s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero); - s->phase_rates[1] = dds_phase_rate((float) spec->freq_one); - s->scaling = dds_scaling_dbm0((float) spec->tx_level); - /* Initialise fractional sample baud generation. */ - s->phase_acc = 0; - s->baud_frac = 0; - s->current_phase_rate = s->phase_rates[1]; - - s->shutdown = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s, - const fsk_spec_t *spec, - get_bit_func_t get_bit, - void *user_data) -{ - if (s == NULL) - { - if ((s = (fsk_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - - s->get_bit = get_bit; - s->get_bit_user_data = user_data; - fsk_tx_restart(s, spec); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len) -{ - int sample; - int bit; - - if (s->shutdown) - return 0; - /*endif*/ - /* Make the transitions between 0 and 1 phase coherent, but instantaneous - jumps. There is currently no interpolation for bauds that end mid-sample. - Mainstream users will not care. Some specialist users might have a problem - with them, if they care about accurate transition timing. */ - for (sample = 0; sample < len; sample++) - { - if ((s->baud_frac += s->baud_rate) >= SAMPLE_RATE*100) - { - s->baud_frac -= SAMPLE_RATE*100; - if ((bit = s->get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA) - { - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); - /*endif*/ - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE); - /*endif*/ - s->shutdown = true; - break; - } - /*endif*/ - s->current_phase_rate = s->phase_rates[bit & 1]; - } - /*endif*/ - amp[sample] = dds_mod(&s->phase_acc, s->current_phase_rate, s->scaling, 0); - } - /*endfor*/ - return sample; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fsk_tx_power(fsk_tx_state_t *s, float power) -{ - s->scaling = dds_scaling_dbm0(power); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, void *user_data) -{ - s->get_bit = get_bit; - s->get_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fsk_rx_signal_cutoff(fsk_rx_state_t *s, float cutoff) -{ - /* The 6.04 allows for the gain of the DC blocker */ - s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f - 6.04f)); - s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f - 6.04f)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) fsk_rx_signal_power(fsk_rx_state_t *s) -{ - return power_meter_current_dbm0(&s->power); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data) -{ - s->put_bit = put_bit; - s->put_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode) -{ - int chop; - - s->baud_rate = spec->baud_rate; - s->framing_mode = framing_mode; - fsk_rx_signal_cutoff(s, (float) spec->min_level); - - /* Detect by correlating against the tones we want, over a period - of one baud. The correlation must be quadrature. */ - - /* First we need the quadrature tone generators to correlate - against. */ - s->phase_rate[0] = dds_phase_rate((float) spec->freq_zero); - s->phase_rate[1] = dds_phase_rate((float) spec->freq_one); - s->phase_acc[0] = 0; - s->phase_acc[1] = 0; - s->last_sample = 0; - - /* The correlation should be over one baud. */ - s->correlation_span = SAMPLE_RATE*100/spec->baud_rate; - /* But limit it for very slow baud rates, so we do not overflow our - buffer. */ - if (s->correlation_span > FSK_MAX_WINDOW_LEN) - s->correlation_span = FSK_MAX_WINDOW_LEN; - /*endif*/ - - /* We need to scale, to avoid overflow in the correlation. */ - s->scaling_shift = 0; - chop = s->correlation_span; - while (chop != 0) - { - s->scaling_shift++; - chop >>= 1; - } - /*endwhile*/ - - /* Initialise the baud/bit rate tracking. */ - s->baud_phase = 0; - s->frame_state = 0; - s->frame_bits = 0; - s->last_bit = 0; - - /* Initialise a power detector, so sense when a signal is present. */ - power_meter_init(&s->power, 4); - s->signal_present = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, - const fsk_spec_t *spec, - int framing_mode, - put_bit_func_t put_bit, - void *user_data) -{ - if (s == NULL) - { - if ((s = (fsk_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - - s->put_bit = put_bit; - s->put_bit_user_data = user_data; - fsk_rx_restart(s, spec, framing_mode); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void report_status_change(fsk_rx_state_t *s, int status) -{ - if (s->status_handler) - s->status_handler(s->status_user_data, status); - else if (s->put_bit) - s->put_bit(s->put_bit_user_data, status); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len) -{ - int buf_ptr; - int baudstate; - int i; - int j; - int16_t x; - int32_t dot; - int32_t sum[2]; - int32_t power; - complexi_t ph; - - buf_ptr = s->buf_ptr; - for (i = 0; i < len; i++) - { - /* The *totally* asynchronous character to character behaviour of these - modems, when carrying async. data, seems to force a sample by sample - approach. */ - for (j = 0; j < 2; j++) - { - s->dot[j].re -= s->window[j][buf_ptr].re; - s->dot[j].im -= s->window[j][buf_ptr].im; - - ph = dds_complexi(&s->phase_acc[j], s->phase_rate[j]); - s->window[j][buf_ptr].re = (ph.re*amp[i]) >> s->scaling_shift; - s->window[j][buf_ptr].im = (ph.im*amp[i]) >> s->scaling_shift; - - s->dot[j].re += s->window[j][buf_ptr].re; - s->dot[j].im += s->window[j][buf_ptr].im; - - dot = s->dot[j].re >> 15; - sum[j] = dot*dot; - dot = s->dot[j].im >> 15; - sum[j] += dot*dot; - } - /*endfor*/ - /* If there isn't much signal, don't demodulate - it will only produce - useless junk results. */ - /* There should be no DC in the signal, but sometimes there is. - We need to measure the power with the DC blocked, but not using - a slow to respond DC blocker. Use the most elementary HPF. */ - x = amp[i] >> 1; - power = power_meter_update(&s->power, x - s->last_sample); - s->last_sample = x; - if (s->signal_present) - { - /* Look for power below turn-off threshold to turn the carrier off */ - if (power < s->carrier_off_power) - { - if (--s->signal_present <= 0) - { - /* Count down a short delay, to ensure we push the last - few bits through the filters before stopping. */ - report_status_change(s, SIG_STATUS_CARRIER_DOWN); - s->baud_phase = 0; - continue; - } - /*endif*/ - } - /*endif*/ - } - else - { - /* Look for power exceeding turn-on threshold to turn the carrier on */ - if (power < s->carrier_on_power) - { - s->baud_phase = 0; - continue; - } - /*endif*/ - if (s->baud_phase < (s->correlation_span >> 1) - 30) - { - s->baud_phase++; - continue; - } - /*endif*/ - s->signal_present = 1; - /* Initialise the baud/bit rate tracking. */ - s->baud_phase = 0; - s->frame_state = 0; - s->frame_bits = 0; - s->last_bit = 0; - report_status_change(s, SIG_STATUS_CARRIER_UP); - } - /*endif*/ - /* Non-coherent FSK demodulation by correlation with the target tones - over a one baud interval. The slow V.xx specs. are too open ended - to allow anything fancier to be used. The dot products are calculated - using a sliding window approach, so the compute load is not that great. */ - - baudstate = (sum[0] < sum[1]); - switch (s->framing_mode) - { - case FSK_FRAME_MODE_SYNC: - /* Synchronous serial operation - e.g. for HDLC */ - if (s->last_bit != baudstate) - { - /* On a transition we check our timing */ - s->last_bit = baudstate; - /* For synchronous use (e.g. HDLC channels in FAX modems), nudge - the baud phase gently, trying to keep it centred on the bauds. */ - if (s->baud_phase < (SAMPLE_RATE*50)) - s->baud_phase += (s->baud_rate >> 3); - else - s->baud_phase -= (s->baud_rate >> 3); - /*endif*/ - } - /*endif*/ - if ((s->baud_phase += s->baud_rate) >= (SAMPLE_RATE*100)) - { - /* We should be in the middle of a baud now, so report the current - state as the next bit */ - s->baud_phase -= (SAMPLE_RATE*100); - s->put_bit(s->put_bit_user_data, baudstate); - } - /*endif*/ - break; - case FSK_FRAME_MODE_ASYNC: - /* Fully asynchronous mode */ - if (s->last_bit != baudstate) - { - /* On a transition we check our timing */ - s->last_bit = baudstate; - /* For async. operation, believe transitions completely, and - sample appropriately. This allows instant start on the first - transition. */ - /* We must now be about half way to a sampling point. We do not do - any fractional sample estimation of the transitions, so this is - the most accurate baud alignment we can do. */ - s->baud_phase = SAMPLE_RATE*50; - } - /*endif*/ - if ((s->baud_phase += s->baud_rate) >= (SAMPLE_RATE*100)) - { - /* We should be in the middle of a baud now, so report the current - state as the next bit */ - s->baud_phase -= (SAMPLE_RATE*100); - s->put_bit(s->put_bit_user_data, baudstate); - } - /*endif*/ - break; - case FSK_FRAME_MODE_5N1_FRAMES: - case FSK_FRAME_MODE_7N1_FRAMES: - case FSK_FRAME_MODE_7E1_FRAMES: - case FSK_FRAME_MODE_7E2_FRAMES: - default: - /* Gather the specified number of bits, with robust checking to ensure reasonable voice immunity. - The first bit should be a start bit (0), and the last bit should be a stop bit (1) */ - if (s->frame_state == 0) - { - /* Looking for the start of a zero bit, which hopefully the start of a start bit */ - if (baudstate == 0) - { - s->baud_phase = SAMPLE_RATE*(100 - 40)/2; - s->frame_state = -1; - s->frame_bits = 0; - s->last_bit = -1; - } - /*endif*/ - } - else if (s->frame_state == -1) - { - /* Look for a continuous zero from the start of the start bit until - beyond the middle */ - if (baudstate != 0) - { - /* If we aren't looking at a stable start bit, restart */ - s->frame_state = 0; - } - else - { - s->baud_phase += s->baud_rate; - if (s->baud_phase >= SAMPLE_RATE*100) - { - s->frame_state = 1; - s->last_bit = baudstate; - } - /*endif*/ - } - /*endif*/ - } - else - { - s->baud_phase += s->baud_rate; - if (s->baud_phase >= SAMPLE_RATE*(100 - 40)) - { - if (s->last_bit < 0) - s->last_bit = baudstate; - /*endif*/ - /* Look for the bit being consistent over the central 20% of the bit time. */ - if (s->last_bit != baudstate) - { - s->frame_state = 0; - } - else if (s->baud_phase >= SAMPLE_RATE*100) - { - /* We should be in the middle of a baud now, so report the current - state as the next bit */ - if (s->last_bit == baudstate) - { - if (++s->frame_state > s->framing_mode) - { - /* Check we have a stop bit and a start bit */ - if (baudstate == 1 && (s->frame_bits & 0x02) == 0) - { - /* Drop the start bit, and pass the rest back */ - s->put_bit(s->put_bit_user_data, s->frame_bits >> 2); - } - /*endif*/ - s->frame_state = 0; - } - else - { - s->frame_bits |= (baudstate << s->framing_mode); - s->frame_bits >>= 1; - } - /*endif*/ - s->baud_phase -= (SAMPLE_RATE*100); - } - else - { - s->frame_state = 0; - } - /*endif*/ - s->last_bit = -1; - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ - break; - } - /*endswitch*/ - if (++buf_ptr >= s->correlation_span) - buf_ptr = 0; - /*endif*/ - } - /*endfor*/ - s->buf_ptr = buf_ptr; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len) -{ - int buf_ptr; - int i; - int j; - - /* The valid choice here is probably to do nothing. We don't change state - (i.e carrier on<->carrier off), and we'll just output less bits than we - should. */ - buf_ptr = s->buf_ptr; - for (i = 0; i < len; i++) - { - for (j = 0; j < 2; j++) - { - s->dot[j].re -= s->window[j][buf_ptr].re; - s->dot[j].im -= s->window[j][buf_ptr].im; - - dds_advance(&s->phase_acc[j], s->phase_rate[j]); - - s->window[j][buf_ptr].re = 0; - s->window[j][buf_ptr].im = 0; - - s->dot[j].re += s->window[j][buf_ptr].re; - s->dot[j].im += s->window[j][buf_ptr].im; - } - /*endfor*/ - } - /*endfor*/ - s->buf_ptr = buf_ptr; - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/g711.c b/libs/spandsp/src/g711.c deleted file mode 100644 index edccd27bb1..0000000000 --- a/libs/spandsp/src/g711.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g711.c - A-law and u-law transcoding routines - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/bit_operations.h" -#include "spandsp/g711.h" -#include "spandsp/private/g711.h" - -/* Copied from the CCITT G.711 specification */ -static const uint8_t ulaw_to_alaw_table[256] = -{ - 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37, - 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53, - 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 26, - 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106, - 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120, - 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77, - 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93, - 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85, - 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165, - 186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181, - 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154, - 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234, - 232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248, - 254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205, - 194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221, - 210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213 -}; - -/* These transcoding tables are copied from the CCITT G.711 specification. To achieve - optimal results, do not change them. */ - -static const uint8_t alaw_to_ulaw_table[256] = -{ - 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37, - 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 47, 48, 53, 54, 51, 52, - 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5, - 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, - 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94, - 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109, - 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67, - 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81, - 170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165, - 185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180, - 138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133, - 154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, - 226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222, - 244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237, - 200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195, - 214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209 -}; - -SPAN_DECLARE(uint8_t) alaw_to_ulaw(uint8_t alaw) -{ - return alaw_to_ulaw_table[alaw]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint8_t) ulaw_to_alaw(uint8_t ulaw) -{ - return ulaw_to_alaw_table[ulaw]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g711_decode(g711_state_t *s, - int16_t amp[], - const uint8_t g711_data[], - int g711_bytes) -{ - int i; - - if (s->mode == G711_ALAW) - { - for (i = 0; i < g711_bytes; i++) - amp[i] = alaw_to_linear(g711_data[i]); - /*endfor*/ - } - else - { - for (i = 0; i < g711_bytes; i++) - amp[i] = ulaw_to_linear(g711_data[i]); - /*endfor*/ - } - /*endif*/ - return g711_bytes; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g711_encode(g711_state_t *s, - uint8_t g711_data[], - const int16_t amp[], - int len) -{ - int i; - - if (s->mode == G711_ALAW) - { - for (i = 0; i < len; i++) - g711_data[i] = linear_to_alaw(amp[i]); - /*endfor*/ - } - else - { - for (i = 0; i < len; i++) - g711_data[i] = linear_to_ulaw(amp[i]); - /*endfor*/ - } - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g711_transcode(g711_state_t *s, - uint8_t g711_out[], - const uint8_t g711_in[], - int g711_bytes) -{ - int i; - - if (s->mode == G711_ALAW) - { - for (i = 0; i < g711_bytes; i++) - g711_out[i] = alaw_to_ulaw_table[g711_in[i]]; - /*endfor*/ - } - else - { - for (i = 0; i < g711_bytes; i++) - g711_out[i] = ulaw_to_alaw_table[g711_in[i]]; - /*endfor*/ - } - /*endif*/ - return g711_bytes; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(g711_state_t *) g711_init(g711_state_t *s, int mode) -{ - if (s == NULL) - { - if ((s = (g711_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - s->mode = mode; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g711_release(g711_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g711_free(g711_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/g722.c b/libs/spandsp/src/g722.c deleted file mode 100644 index f9bd7f37b2..0000000000 --- a/libs/spandsp/src/g722.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g722.c - The ITU G.722 codec. - * - * 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. - */ - -/*! \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 "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" -#include "spandsp/g722.h" - -#include "spandsp/private/g722.h" - -static const int16_t qmf_coeffs_fwd[12] = -{ - 3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11, -}; - -static const int16_t qmf_coeffs_rev[12] = -{ - -11, 53, -156, 362, -805, 3876, 951, -210, 32, 12, -11, 3 -}; - -static const int16_t qm2[4] = -{ - -7408, -1616, 7408, 1616 -}; - -static const int16_t qm4[16] = -{ - 0, -20456, -12896, -8968, - -6288, -4240, -2584, -1200, - 20456, 12896, 8968, 6288, - 4240, 2584, 1200, 0 -}; - -static const int16_t qm5[32] = -{ - -280, -280, -23352, -17560, - -14120, -11664, -9752, -8184, - -6864, -5712, -4696, -3784, - -2960, -2208, -1520, -880, - 23352, 17560, 14120, 11664, - 9752, 8184, 6864, 5712, - 4696, 3784, 2960, 2208, - 1520, 880, 280, -280 -}; - -static const int16_t qm6[64] = -{ - -136, -136, -136, -136, - -24808, -21904, -19008, -16704, - -14984, -13512, -12280, -11192, - -10232, -9360, -8576, -7856, - -7192, -6576, -6000, -5456, - -4944, -4464, -4008, -3576, - -3168, -2776, -2400, -2032, - -1688, -1360, -1040, -728, - 24808, 21904, 19008, 16704, - 14984, 13512, 12280, 11192, - 10232, 9360, 8576, 7856, - 7192, 6576, 6000, 5456, - 4944, 4464, 4008, 3576, - 3168, 2776, 2400, 2032, - 1688, 1360, 1040, 728, - 432, 136, -432, -136 -}; - -static const int16_t q6[32] = -{ - 0, 35, 72, 110, - 150, 190, 233, 276, - 323, 370, 422, 473, - 530, 587, 650, 714, - 786, 858, 940, 1023, - 1121, 1219, 1339, 1458, - 1612, 1765, 1980, 2195, - 2557, 2919, 0, 0 -}; - -static const int16_t ilb[32] = -{ - 2048, 2093, 2139, 2186, - 2233, 2282, 2332, 2383, - 2435, 2489, 2543, 2599, - 2656, 2714, 2774, 2834, - 2896, 2960, 3025, 3091, - 3158, 3228, 3298, 3371, - 3444, 3520, 3597, 3676, - 3756, 3838, 3922, 4008 -}; - -static const int16_t iln[32] = -{ - 0, 63, 62, 31, 30, 29, 28, 27, - 26, 25, 24, 23, 22, 21, 20, 19, - 18, 17, 16, 15, 14, 13, 12, 11, - 10, 9, 8, 7, 6, 5, 4, 0 -}; - -static const int16_t ilp[32] = -{ - 0, 61, 60, 59, 58, 57, 56, 55, - 54, 53, 52, 51, 50, 49, 48, 47, - 46, 45, 44, 43, 42, 41, 40, 39, - 38, 37, 36, 35, 34, 33, 32, 0 -}; - -static const int16_t ihn[3] = -{ - 0, 1, 0 -}; - -static const int16_t ihp[3] = -{ - 0, 3, 2 -}; - -static const int16_t wl[8] = -{ - -60, -30, 58, 172, 334, 538, 1198, 3042 -}; - -static const int16_t rl42[16] = -{ - 0, 7, 6, 5, 4, 3, 2, 1, - 7, 6, 5, 4, 3, 2, 1, 0 -}; - -static const int16_t wh[3] = -{ - 0, -214, 798 -}; - -static const int16_t rh2[4] = -{ - 2, 1, 2, 1 -}; - -static void block4(g722_band_t *s, int16_t dx) -{ - int16_t wd1; - int16_t wd2; - int16_t wd3; - int16_t sp; - int16_t r; - int16_t p; - int16_t ap[2]; - int32_t wd32; - int32_t sz; - int i; - - /* RECONS */ - r = sat_add16(s->s, dx); - /* PARREC */ - p = sat_add16(s->sz, dx); - - /* UPPOL2 */ - wd1 = saturate16((int32_t) s->a[0] << 2); - wd32 = ((p ^ s->p[0]) & 0x8000) ? wd1 : -wd1; - if (wd32 > 32767) - wd32 = 32767; - wd3 = (int16_t) ((((p ^ s->p[1]) & 0x8000) ? -128 : 128) - + (wd32 >> 7) - + (((int32_t) s->a[1]*32512) >> 15)); - if (abs(wd3) > 12288) - wd3 = (wd3 < 0) ? -12288 : 12288; - ap[1] = wd3; - - /* UPPOL1 */ - wd1 = ((p ^ s->p[0]) & 0x8000) ? -192 : 192; - wd2 = (int16_t) (((int32_t) s->a[0]*32640) >> 15); - ap[0] = sat_add16(wd1, wd2); - - wd3 = sat_sub16(15360, ap[1]); - if (abs(ap[0]) > wd3) - ap[0] = (ap[0] < 0) ? -wd3 : wd3; - - /* FILTEP */ - wd1 = sat_add16(r, r); - wd1 = (int16_t) (((int32_t) ap[0]*wd1) >> 15); - wd2 = sat_add16(s->r, s->r); - wd2 = (int16_t) (((int32_t) ap[1]*wd2) >> 15); - sp = sat_add16(wd1, wd2); - s->r = r; - s->a[1] = ap[1]; - s->a[0] = ap[0]; - s->p[1] = s->p[0]; - s->p[0] = p; - - /* UPZERO */ - /* DELAYA */ - /* FILTEZ */ - wd1 = (dx == 0) ? 0 : 128; - s->d[0] = dx; - sz = 0; - for (i = 5; i >= 0; i--) - { - wd2 = ((s->d[i + 1] ^ dx) & 0x8000) ? -wd1 : wd1; - wd3 = (int16_t) (((int32_t) s->b[i]*32640) >> 15); - s->b[i] = sat_add16(wd2, wd3); - wd3 = sat_add16(s->d[i], s->d[i]); - sz += ((int32_t) s->b[i]*wd3) >> 15; - s->d[i + 1] = s->d[i]; - } - s->sz = saturate16(sz); - - /* PREDIC */ - s->s = sat_add16(sp, s->sz); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(g722_decode_state_t *) g722_decode_init(g722_decode_state_t *s, int rate, int options) -{ - if (s == NULL) - { - if ((s = (g722_decode_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - if (rate == 48000) - s->bits_per_sample = 6; - else if (rate == 56000) - s->bits_per_sample = 7; - else - s->bits_per_sample = 8; - if ((options & G722_SAMPLE_RATE_8000)) - s->eight_k = true; - if ((options & G722_PACKED) && s->bits_per_sample != 8) - s->packed = true; - else - s->packed = false; - s->band[0].det = 32; - s->band[1].det = 8; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g722_decode_release(g722_decode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g722_decode_free(g722_decode_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len) -{ - int rlow; - int ihigh; - int16_t dlow; - int16_t dhigh; - int rhigh; - int wd1; - int wd2; - int wd3; - int code; - int outlen; - int j; - - outlen = 0; - rhigh = 0; - for (j = 0; j < len; ) - { - if (s->packed) - { - /* Unpack the code bits */ - if (s->in_bits < s->bits_per_sample) - { - s->in_buffer |= (g722_data[j++] << s->in_bits); - s->in_bits += 8; - } - code = s->in_buffer & ((1 << s->bits_per_sample) - 1); - s->in_buffer >>= s->bits_per_sample; - s->in_bits -= s->bits_per_sample; - } - else - { - code = g722_data[j++]; - } - - switch (s->bits_per_sample) - { - default: - case 8: - wd1 = code & 0x3F; - ihigh = (code >> 6) & 0x03; - wd2 = qm6[wd1]; - wd1 >>= 2; - break; - case 7: - wd1 = code & 0x1F; - ihigh = (code >> 5) & 0x03; - wd2 = qm5[wd1]; - wd1 >>= 1; - break; - case 6: - wd1 = code & 0x0F; - ihigh = (code >> 4) & 0x03; - wd2 = qm4[wd1]; - break; - } - /* Block 5L, LOW BAND INVQBL */ - wd2 = ((int32_t) s->band[0].det*wd2) >> 15; - /* Block 5L, RECONS */ - /* Block 6L, LIMIT */ - rlow = saturate15(s->band[0].s + wd2); - - /* Block 2L, INVQAL */ - wd2 = qm4[wd1]; - dlow = (int16_t) (((int32_t) s->band[0].det*wd2) >> 15); - - /* Block 3L, LOGSCL */ - wd2 = rl42[wd1]; - wd1 = ((int32_t) s->band[0].nb*127) >> 7; - wd1 += wl[wd2]; - if (wd1 < 0) - wd1 = 0; - else if (wd1 > 18432) - wd1 = 18432; - s->band[0].nb = (int16_t) wd1; - - /* Block 3L, SCALEL */ - wd1 = (s->band[0].nb >> 6) & 31; - wd2 = 8 - (s->band[0].nb >> 11); - wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); - s->band[0].det = (int16_t) (wd3 << 2); - - block4(&s->band[0], dlow); - - if (!s->eight_k) - { - /* Block 2H, INVQAH */ - wd2 = qm2[ihigh]; - dhigh = (int16_t) (((int32_t) s->band[1].det*wd2) >> 15); - /* Block 5H, RECONS */ - /* Block 6H, LIMIT */ - rhigh = saturate15(dhigh + s->band[1].s); - - /* Block 2H, INVQAH */ - wd2 = rh2[ihigh]; - wd1 = ((int32_t) s->band[1].nb*127) >> 7; - wd1 += wh[wd2]; - if (wd1 < 0) - wd1 = 0; - else if (wd1 > 22528) - wd1 = 22528; - s->band[1].nb = (int16_t) wd1; - - /* Block 3H, SCALEH */ - wd1 = (s->band[1].nb >> 6) & 31; - wd2 = 10 - (s->band[1].nb >> 11); - wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); - s->band[1].det = (int16_t) (wd3 << 2); - - block4(&s->band[1], dhigh); - } - - if (s->itu_test_mode) - { - amp[outlen++] = (int16_t) (rlow << 1); - amp[outlen++] = (int16_t) (rhigh << 1); - } - else - { - if (s->eight_k) - { - /* We shift by 1 to allow for the 15 bit input to the G.722 algorithm. */ - amp[outlen++] = (int16_t) (rlow << 1); - } - else - { - /* Apply the QMF to build the final signal */ - s->x[s->ptr] = (int16_t) (rlow + rhigh); - s->y[s->ptr] = (int16_t) (rlow - rhigh); - if (++s->ptr >= 12) - s->ptr = 0; - /* We shift by 12 to allow for the QMF filters (DC gain = 4096), less 1 - to allow for the 15 bit input to the G.722 algorithm. */ - amp[outlen++] = saturate16(vec_circular_dot_prodi16(s->y, qmf_coeffs_rev, 12, s->ptr) >> 11); - amp[outlen++] = saturate16(vec_circular_dot_prodi16(s->x, qmf_coeffs_fwd, 12, s->ptr) >> 11); - } - } - } - return outlen; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(g722_encode_state_t *) g722_encode_init(g722_encode_state_t *s, int rate, int options) -{ - if (s == NULL) - { - if ((s = (g722_encode_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - if (rate == 48000) - s->bits_per_sample = 6; - else if (rate == 56000) - s->bits_per_sample = 7; - else - s->bits_per_sample = 8; - if ((options & G722_SAMPLE_RATE_8000)) - s->eight_k = true; - if ((options & G722_PACKED) && s->bits_per_sample != 8) - s->packed = true; - else - s->packed = false; - s->band[0].det = 32; - s->band[1].det = 8; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g722_encode_release(g722_encode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g722_encode_free(g722_encode_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len) -{ - int16_t dlow; - int16_t dhigh; - int el; - int wd; - int wd1; - int ril; - int wd2; - int il4; - int ih2; - int wd3; - int eh; - int g722_bytes; - int ihigh; - int ilow; - int code; - /* Low and high band PCM from the QMF */ - int16_t xlow; - int16_t xhigh; - int32_t sumeven; - int32_t sumodd; - int mih; - int i; - int j; - - g722_bytes = 0; - xhigh = 0; - for (j = 0; j < len; ) - { - if (s->itu_test_mode) - { - xlow = - xhigh = amp[j++] >> 1; - } - else - { - if (s->eight_k) - { - /* We shift by 1 to allow for the 15 bit input to the G.722 algorithm. */ - xlow = amp[j++] >> 1; - } - else - { - /* Apply the transmit QMF */ - s->x[s->ptr] = amp[j++]; - s->y[s->ptr] = amp[j++]; - if (++s->ptr >= 12) - s->ptr = 0; - sumodd = vec_circular_dot_prodi16(s->x, qmf_coeffs_fwd, 12, s->ptr); - sumeven = vec_circular_dot_prodi16(s->y, qmf_coeffs_rev, 12, s->ptr); - /* We shift by 12 to allow for the QMF filters (DC gain = 4096), plus 1 - to allow for us summing two filters, plus 1 to allow for the 15 bit - input to the G.722 algorithm. */ - xlow = (int16_t) ((sumeven + sumodd) >> 14); - xhigh = (int16_t) ((sumeven - sumodd) >> 14); - } - } - /* Block 1L, SUBTRA */ - el = sat_sub16(xlow, s->band[0].s); - - /* Block 1L, QUANTL */ - wd = (el >= 0) ? el : ~el; - - for (i = 1; i < 30; i++) - { - wd1 = ((int32_t) q6[i]*s->band[0].det) >> 12; - if (wd < wd1) - break; - } - ilow = (el < 0) ? iln[i] : ilp[i]; - - /* Block 2L, INVQAL */ - ril = ilow >> 2; - wd2 = qm4[ril]; - dlow = (int16_t) (((int32_t) s->band[0].det*wd2) >> 15); - - /* Block 3L, LOGSCL */ - il4 = rl42[ril]; - wd = ((int32_t) s->band[0].nb*127) >> 7; - s->band[0].nb = (int16_t) (wd + wl[il4]); - if (s->band[0].nb < 0) - s->band[0].nb = 0; - else if (s->band[0].nb > 18432) - s->band[0].nb = 18432; - - /* Block 3L, SCALEL */ - wd1 = (s->band[0].nb >> 6) & 31; - wd2 = 8 - (s->band[0].nb >> 11); - wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); - s->band[0].det = (int16_t) (wd3 << 2); - - block4(&s->band[0], dlow); - - if (s->eight_k) - { - /* Just leave the high bits as zero */ - code = (0xC0 | ilow) >> (8 - s->bits_per_sample); - } - else - { - /* Block 1H, SUBTRA */ - eh = sat_sub16(xhigh, s->band[1].s); - - /* Block 1H, QUANTH */ - wd = (eh >= 0) ? eh : ~eh; - wd1 = (564*s->band[1].det) >> 12; - mih = (wd >= wd1) ? 2 : 1; - ihigh = (eh < 0) ? ihn[mih] : ihp[mih]; - - /* Block 2H, INVQAH */ - wd2 = qm2[ihigh]; - dhigh = (int16_t) (((int32_t) s->band[1].det*wd2) >> 15); - - /* Block 3H, LOGSCH */ - ih2 = rh2[ihigh]; - wd = ((int32_t) s->band[1].nb*127) >> 7; - s->band[1].nb = (int16_t) (wd + wh[ih2]); - if (s->band[1].nb < 0) - s->band[1].nb = 0; - else if (s->band[1].nb > 22528) - s->band[1].nb = 22528; - - /* Block 3H, SCALEH */ - wd1 = (s->band[1].nb >> 6) & 31; - wd2 = 10 - (s->band[1].nb >> 11); - wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); - s->band[1].det = (int16_t) (wd3 << 2); - - block4(&s->band[1], dhigh); - code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample); - } - - if (s->packed) - { - /* Pack the code bits */ - s->out_buffer |= (code << s->out_bits); - s->out_bits += s->bits_per_sample; - if (s->out_bits >= 8) - { - g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF); - s->out_bits -= 8; - s->out_buffer >>= 8; - } - } - else - { - g722_data[g722_bytes++] = (uint8_t) code; - } - } - return g722_bytes; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/g726.c b/libs/spandsp/src/g726.c deleted file mode 100644 index 3219465d11..0000000000 --- a/libs/spandsp/src/g726.c +++ /dev/null @@ -1,1191 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g726.c - The ITU G.726 codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * Based on G.721/G.723 code which is: - * - * This source code is a product of Sun Microsystems, Inc. and is provided - * for unrestricted use. Users may copy or modify this source code without - * charge. - * - * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING - * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun source code is provided with no support and without any obligation on - * the part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -/*! \file */ - -#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 -#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" -#include "spandsp/g726.h" - -#include "spandsp/private/bitstream.h" -#include "spandsp/private/g726.h" - -/* - * Maps G.726_16 code word to reconstructed scale factor normalized log - * magnitude values. - */ -static const int g726_16_dqlntab[4] = -{ - 116, 365, 365, 116 -}; - -/* Maps G.726_16 code word to log of scale factor multiplier. */ -static const int g726_16_witab[4] = -{ - -704, 14048, 14048, -704 -}; - -/* - * Maps G.726_16 code words to a set of values whose long and short - * term averages are computed and then compared to give an indication - * how stationary (steady state) the signal is. - */ -static const int g726_16_fitab[4] = -{ - 0x000, 0xE00, 0xE00, 0x000 -}; - -static const int qtab_726_16[1] = -{ - 261 -}; - -/* - * Maps G.726_24 code word to reconstructed scale factor normalized log - * magnitude values. - */ -static const int g726_24_dqlntab[8] = -{ - -2048, 135, 273, 373, 373, 273, 135, -2048 -}; - -/* Maps G.726_24 code word to log of scale factor multiplier. */ -static const int g726_24_witab[8] = -{ - -128, 960, 4384, 18624, 18624, 4384, 960, -128 -}; - -/* - * Maps G.726_24 code words to a set of values whose long and short - * term averages are computed and then compared to give an indication - * how stationary (steady state) the signal is. - */ -static const int g726_24_fitab[8] = -{ - 0x000, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0x000 -}; - -static const int qtab_726_24[3] = -{ - 8, 218, 331 -}; - -/* - * Maps G.726_32 code word to reconstructed scale factor normalized log - * magnitude values. - */ -static const int g726_32_dqlntab[16] = -{ - -2048, 4, 135, 213, 273, 323, 373, 425, - 425, 373, 323, 273, 213, 135, 4, -2048 -}; - -/* Maps G.726_32 code word to log of scale factor multiplier. */ -static const int g726_32_witab[16] = -{ - -384, 576, 1312, 2048, 3584, 6336, 11360, 35904, - 35904, 11360, 6336, 3584, 2048, 1312, 576, -384 -}; - -/* - * Maps G.726_32 code words to a set of values whose long and short - * term averages are computed and then compared to give an indication - * how stationary (steady state) the signal is. - */ -static const int g726_32_fitab[16] = -{ - 0x000, 0x000, 0x000, 0x200, 0x200, 0x200, 0x600, 0xE00, - 0xE00, 0x600, 0x200, 0x200, 0x200, 0x000, 0x000, 0x000 -}; - -static const int qtab_726_32[7] = -{ - -124, 80, 178, 246, 300, 349, 400 -}; - -/* - * Maps G.726_40 code word to ructeconstructed scale factor normalized log - * magnitude values. - */ -static const int g726_40_dqlntab[32] = -{ - -2048, -66, 28, 104, 169, 224, 274, 318, - 358, 395, 429, 459, 488, 514, 539, 566, - 566, 539, 514, 488, 459, 429, 395, 358, - 318, 274, 224, 169, 104, 28, -66, -2048 -}; - -/* Maps G.726_40 code word to log of scale factor multiplier. */ -static const int g726_40_witab[32] = -{ - 448, 448, 768, 1248, 1280, 1312, 1856, 3200, - 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, - 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, - 3200, 1856, 1312, 1280, 1248, 768, 448, 448 -}; - -/* - * Maps G.726_40 code words to a set of values whose long and short - * term averages are computed and then compared to give an indication - * how stationary (steady state) the signal is. - */ -static const int g726_40_fitab[32] = -{ - 0x000, 0x000, 0x000, 0x000, 0x000, 0x200, 0x200, 0x200, - 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, - 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, - 0x200, 0x200, 0x200, 0x000, 0x000, 0x000, 0x000, 0x000 -}; - -static const int qtab_726_40[15] = -{ - -122, -16, 68, 139, 198, 250, 298, 339, - 378, 413, 445, 475, 502, 528, 553 -}; - -/* - * returns the integer product of the 14-bit integer "an" and - * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". - */ -static int16_t fmult(int16_t an, int16_t srn) -{ - int16_t anmag; - int16_t anexp; - int16_t anmant; - int16_t wanexp; - int16_t wanmant; - int16_t retval; - - anmag = (an > 0) ? an : ((-an) & 0x1FFF); - anexp = (int16_t) (top_bit(anmag) - 5); - anmant = (anmag == 0) ? 32 : (anexp >= 0) ? (anmag >> anexp) : (anmag << -anexp); - wanexp = anexp + ((srn >> 6) & 0xF) - 13; - - wanmant = (anmant*(srn & 0x3F) + 0x30) >> 4; - retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : (wanmant >> -wanexp); - - return (((an ^ srn) < 0) ? -retval : retval); -} -/*- End of function --------------------------------------------------------*/ - -/* - * Compute the estimated signal from the 6-zero predictor. - */ -static __inline__ int16_t predictor_zero(g726_state_t *s) -{ - int i; - int sezi; - - sezi = fmult(s->b[0] >> 2, s->dq[0]); - /* ACCUM */ - for (i = 1; i < 6; i++) - sezi += fmult(s->b[i] >> 2, s->dq[i]); - return (int16_t) sezi; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Computes the estimated signal from the 2-pole predictor. - */ -static __inline__ int16_t predictor_pole(g726_state_t *s) -{ - return (fmult(s->a[1] >> 2, s->sr[1]) + fmult(s->a[0] >> 2, s->sr[0])); -} -/*- End of function --------------------------------------------------------*/ - -/* - * Computes the quantization step size of the adaptive quantizer. - */ -static int step_size(g726_state_t *s) -{ - int y; - int dif; - int al; - - if (s->ap >= 256) - return s->yu; - y = s->yl >> 6; - dif = s->yu - y; - al = s->ap >> 2; - if (dif > 0) - y += (dif*al) >> 6; - else if (dif < 0) - y += (dif*al + 0x3F) >> 6; - return y; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Given a raw sample, 'd', of the difference signal and a - * quantization step size scale factor, 'y', this routine returns the - * ADPCM codeword to which that sample gets quantized. The step - * size scale factor division operation is done in the log base 2 domain - * as a subtraction. - */ -static int16_t quantize(int d, /* Raw difference signal sample */ - int y, /* Step size multiplier */ - const int table[], /* quantization table */ - int quantizer_states) /* table size of int16_t integers */ -{ - int16_t dqm; /* Magnitude of 'd' */ - int16_t exp; /* Integer part of base 2 log of 'd' */ - int16_t mant; /* Fractional part of base 2 log */ - int16_t dl; /* Log of magnitude of 'd' */ - int16_t dln; /* Step size scale factor normalized log */ - int i; - int size; - - /* - * LOG - * - * Compute base 2 log of 'd', and store in 'dl'. - */ - dqm = (int16_t) abs(d); - exp = (int16_t) (top_bit(dqm >> 1) + 1); - /* Fractional portion. */ - mant = ((dqm << 7) >> exp) & 0x7F; - dl = (exp << 7) + mant; - - /* - * SUBTB - * - * "Divide" by step size multiplier. - */ - dln = dl - (int16_t) (y >> 2); - - /* - * QUAN - * - * Search for codword i for 'dln'. - */ - size = (quantizer_states - 1) >> 1; - for (i = 0; i < size; i++) - { - if (dln < table[i]) - break; - } - if (d < 0) - { - /* Take 1's complement of i */ - return (int16_t) ((size << 1) + 1 - i); - } - if (i == 0 && (quantizer_states & 1)) - { - /* Zero is only valid if there are an even number of states, so - take the 1's complement if the code is zero. */ - return (int16_t) quantizer_states; - } - return (int16_t) i; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Returns reconstructed difference signal 'dq' obtained from - * codeword 'i' and quantization step size scale factor 'y'. - * Multiplication is performed in log base 2 domain as addition. - */ -static int16_t reconstruct(int sign, /* 0 for non-negative value */ - int dqln, /* G.72x codeword */ - int y) /* Step size multiplier */ -{ - int16_t dql; /* Log of 'dq' magnitude */ - int16_t dex; /* Integer part of log */ - int16_t dqt; - int16_t dq; /* Reconstructed difference signal sample */ - - dql = (int16_t) (dqln + (y >> 2)); /* ADDA */ - - if (dql < 0) - return ((sign) ? -0x8000 : 0); - /* ANTILOG */ - dex = (dql >> 7) & 15; - dqt = 128 + (dql & 127); - dq = (dqt << 7) >> (14 - dex); - return ((sign) ? (dq - 0x8000) : dq); -} -/*- End of function --------------------------------------------------------*/ - -/* - * updates the state variables for each output code - */ -static void update(g726_state_t *s, - int y, /* quantizer step size */ - int wi, /* scale factor multiplier */ - int fi, /* for long/short term energies */ - int dq, /* quantized prediction difference */ - int sr, /* reconstructed signal */ - int dqsez) /* difference from 2-pole predictor */ -{ - int16_t mag; - int16_t exp; - int16_t a2p; /* LIMC */ - int16_t a1ul; /* UPA1 */ - int16_t pks1; /* UPA2 */ - int16_t fa1; - int16_t ylint; - int16_t dqthr; - int16_t ylfrac; - int16_t thr; - int16_t pk0; - int i; - bool tr; - - a2p = 0; - /* Needed in updating predictor poles */ - pk0 = (dqsez < 0) ? 1 : 0; - - /* prediction difference magnitude */ - mag = (int16_t) (dq & 0x7FFF); - /* TRANS */ - ylint = (int16_t) (s->yl >> 15); /* exponent part of yl */ - ylfrac = (int16_t) ((s->yl >> 10) & 0x1F); /* fractional part of yl */ - /* Limit threshold to 31 << 10 */ - 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; - else if (mag <= dqthr) /* supposed data, but small mag */ - tr = false; /* treated as voice */ - else /* signal is data (modem) */ - tr = true; - - /* - * Quantizer scale factor adaptation. - */ - - /* FUNCTW & FILTD & DELAY */ - /* update non-steady state step size multiplier */ - s->yu = (int16_t) (y + ((wi - y) >> 5)); - - /* LIMB */ - if (s->yu < 544) - s->yu = 544; - else if (s->yu > 5120) - s->yu = 5120; - - /* FILTE & DELAY */ - /* update steady state step size multiplier */ - s->yl += s->yu + ((-s->yl) >> 6); - - /* - * Adaptive predictor coefficients. - */ - if (tr) - { - /* Reset the a's and b's for a modem signal */ - s->a[0] = 0; - s->a[1] = 0; - s->b[0] = 0; - s->b[1] = 0; - s->b[2] = 0; - s->b[3] = 0; - s->b[4] = 0; - s->b[5] = 0; - } - else - { - /* Update the a's and b's */ - /* UPA2 */ - pks1 = pk0 ^ s->pk[0]; - - /* Update predictor pole a[1] */ - a2p = s->a[1] - (s->a[1] >> 7); - if (dqsez != 0) - { - fa1 = (pks1) ? s->a[0] : -s->a[0]; - /* a2p = function of fa1 */ - if (fa1 < -8191) - a2p -= 0x100; - else if (fa1 > 8191) - a2p += 0xFF; - else - a2p += fa1 >> 5; - - if (pk0 ^ s->pk[1]) - { - /* LIMC */ - if (a2p <= -12160) - a2p = -12288; - else if (a2p >= 12416) - a2p = 12288; - else - a2p -= 0x80; - } - else if (a2p <= -12416) - a2p = -12288; - else if (a2p >= 12160) - a2p = 12288; - else - a2p += 0x80; - } - - /* TRIGB & DELAY */ - s->a[1] = a2p; - - /* UPA1 */ - /* Update predictor pole a[0] */ - s->a[0] -= s->a[0] >> 8; - if (dqsez != 0) - { - if (pks1 == 0) - s->a[0] += 192; - else - s->a[0] -= 192; - } - /* LIMD */ - a1ul = 15360 - a2p; - if (s->a[0] < -a1ul) - s->a[0] = -a1ul; - else if (s->a[0] > a1ul) - s->a[0] = a1ul; - - /* UPB : update predictor zeros b[6] */ - for (i = 0; i < 6; i++) - { - /* Distinguish 40Kbps mode from the others */ - s->b[i] -= s->b[i] >> ((s->bits_per_sample == 5) ? 9 : 8); - if (dq & 0x7FFF) - { - /* XOR */ - if ((dq ^ s->dq[i]) >= 0) - s->b[i] += 128; - else - s->b[i] -= 128; - } - } - } - - for (i = 5; i > 0; i--) - s->dq[i] = s->dq[i - 1]; - /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ - if (mag == 0) - { - s->dq[0] = (dq >= 0) ? 0x20 : 0xFC20; - } - else - { - exp = (int16_t) (top_bit(mag) + 1); - s->dq[0] = (dq >= 0) - ? ((exp << 6) + ((mag << 6) >> exp)) - : ((exp << 6) + ((mag << 6) >> exp) - 0x400); - } - - s->sr[1] = s->sr[0]; - /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ - if (sr == 0) - { - s->sr[0] = 0x20; - } - else if (sr > 0) - { - exp = (int16_t) (top_bit(sr) + 1); - s->sr[0] = (int16_t) ((exp << 6) + ((sr << 6) >> exp)); - } - else if (sr > -32768) - { - mag = (int16_t) -sr; - exp = (int16_t) (top_bit(mag) + 1); - s->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400; - } - else - { - s->sr[0] = (uint16_t) 0xFC20; - } - - /* DELAY A */ - s->pk[1] = s->pk[0]; - s->pk[0] = pk0; - - /* TONE */ - if (tr) /* this sample has been treated as data */ - 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 */ - else /* signal is voice */ - s->td = false; - - /* Adaptation speed control. */ - /* FILTA */ - s->dms += ((int16_t) fi - s->dms) >> 5; - /* FILTB */ - s->dml += (((int16_t) (fi << 2) - s->dml) >> 7); - - if (tr) - s->ap = 256; - else if (y < 1536) /* SUBTC */ - s->ap += (0x200 - s->ap) >> 4; - else if (s->td) - s->ap += (0x200 - s->ap) >> 4; - else if (abs((s->dms << 2) - s->dml) >= (s->dml >> 3)) - s->ap += (0x200 - s->ap) >> 4; - else - s->ap += (-s->ap) >> 4; -} -/*- End of function --------------------------------------------------------*/ - -static int16_t tandem_adjust_alaw(int16_t sr, /* decoder output linear PCM sample */ - int se, /* predictor estimate sample */ - int y, /* quantizer step size */ - int i, /* decoder input code */ - int sign, - const int qtab[], - int quantizer_states) -{ - uint8_t sp; /* A-law compressed 8-bit code */ - int16_t dx; /* prediction error */ - int id; /* quantized prediction error */ - int sd; /* adjusted A-law decoded sample value */ - - if (sr <= -32768) - sr = -1; - sp = linear_to_alaw((sr >> 1) << 3); - /* 16-bit prediction error */ - dx = (int16_t) ((alaw_to_linear(sp) >> 2) - se); - id = quantize(dx, y, qtab, quantizer_states); - if (id == i) - { - /* No adjustment of sp required */ - return (int16_t) sp; - } - /* sp adjustment needed */ - /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ - /* 2's complement to biased unsigned */ - if ((id ^ sign) > (i ^ sign)) - { - /* sp adjusted to next lower value */ - if (sp & 0x80) - sd = (sp == 0xD5) ? 0x55 : (((sp ^ 0x55) - 1) ^ 0x55); - else - sd = (sp == 0x2A) ? 0x2A : (((sp ^ 0x55) + 1) ^ 0x55); - } - else - { - /* sp adjusted to next higher value */ - if (sp & 0x80) - sd = (sp == 0xAA) ? 0xAA : (((sp ^ 0x55) + 1) ^ 0x55); - else - sd = (sp == 0x55) ? 0xD5 : (((sp ^ 0x55) - 1) ^ 0x55); - } - return (int16_t) sd; -} -/*- End of function --------------------------------------------------------*/ - -static int16_t tandem_adjust_ulaw(int16_t sr, /* decoder output linear PCM sample */ - int se, /* predictor estimate sample */ - int y, /* quantizer step size */ - int i, /* decoder input code */ - int sign, - const int qtab[], - int quantizer_states) -{ - uint8_t sp; /* u-law compressed 8-bit code */ - int16_t dx; /* prediction error */ - int id; /* quantized prediction error */ - int sd; /* adjusted u-law decoded sample value */ - - if (sr <= -32768) - sr = 0; - sp = linear_to_ulaw(sr << 2); - /* 16-bit prediction error */ - dx = (int16_t) ((ulaw_to_linear(sp) >> 2) - se); - id = quantize(dx, y, qtab, quantizer_states); - if (id == i) - { - /* No adjustment of sp required. */ - return (int16_t) sp; - } - /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ - /* 2's complement to biased unsigned */ - if ((id ^ sign) > (i ^ sign)) - { - /* sp adjusted to next lower value */ - if (sp & 0x80) - sd = (sp == 0xFF) ? 0x7E : (sp + 1); - else - sd = (sp == 0x00) ? 0x00 : (sp - 1); - } - else - { - /* sp adjusted to next higher value */ - if (sp & 0x80) - sd = (sp == 0x80) ? 0x80 : (sp - 1); - else - sd = (sp == 0x7F) ? 0xFE : (sp + 1); - } - return (int16_t) sd; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. - */ -static uint8_t g726_16_encoder(g726_state_t *s, int16_t amp) -{ - int y; - int16_t sei; - int16_t sezi; - int16_t se; - int16_t d; - int16_t sr; - int16_t dqsez; - int16_t dq; - int16_t i; - - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - se = sei >> 1; - d = amp - se; - - /* Quantize prediction difference */ - y = step_size(s); - i = quantize(d, y, qtab_726_16, 4); - dq = reconstruct(i & 2, g726_16_dqlntab[i], y); - - /* Reconstruct the signal */ - sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_16_witab[i], g726_16_fitab[i], dq, sr, dqsez); - return (uint8_t) i; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Decodes a 2-bit CCITT G.726_16 ADPCM code and returns - * the resulting 16-bit linear PCM, A-law or u-law sample value. - */ -static int16_t g726_16_decoder(g726_state_t *s, uint8_t code) -{ - int16_t sezi; - int16_t sei; - int16_t se; - int16_t sr; - int16_t dq; - int16_t dqsez; - int y; - - /* Mask to get proper bits */ - code &= 0x03; - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - - y = step_size(s); - dq = reconstruct(code & 2, g726_16_dqlntab[code], y); - - /* Reconstruct the signal */ - se = sei >> 1; - sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_16_witab[code], g726_16_fitab[code], dq, sr, dqsez); - - switch (s->ext_coding) - { - case G726_ENCODING_ALAW: - return tandem_adjust_alaw(sr, se, y, code, 2, qtab_726_16, 4); - case G726_ENCODING_ULAW: - return tandem_adjust_ulaw(sr, se, y, code, 2, qtab_726_16, 4); - } - return (sr << 2); -} -/*- End of function --------------------------------------------------------*/ - -/* - * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. - */ -static uint8_t g726_24_encoder(g726_state_t *s, int16_t amp) -{ - int16_t sei; - int16_t sezi; - int16_t se; - int16_t d; - int16_t sr; - int16_t dqsez; - int16_t dq; - int16_t i; - int y; - - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - se = sei >> 1; - d = amp - se; - - /* Quantize prediction difference */ - y = step_size(s); - i = quantize(d, y, qtab_726_24, 7); - dq = reconstruct(i & 4, g726_24_dqlntab[i], y); - - /* Reconstruct the signal */ - sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_24_witab[i], g726_24_fitab[i], dq, sr, dqsez); - return (uint8_t) i; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Decodes a 3-bit CCITT G.726_24 ADPCM code and returns - * the resulting 16-bit linear PCM, A-law or u-law sample value. - */ -static int16_t g726_24_decoder(g726_state_t *s, uint8_t code) -{ - int16_t sezi; - int16_t sei; - int16_t se; - int16_t sr; - int16_t dq; - int16_t dqsez; - int y; - - /* Mask to get proper bits */ - code &= 0x07; - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - - y = step_size(s); - dq = reconstruct(code & 4, g726_24_dqlntab[code], y); - - /* Reconstruct the signal */ - se = sei >> 1; - sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_24_witab[code], g726_24_fitab[code], dq, sr, dqsez); - - switch (s->ext_coding) - { - case G726_ENCODING_ALAW: - return tandem_adjust_alaw(sr, se, y, code, 4, qtab_726_24, 7); - case G726_ENCODING_ULAW: - return tandem_adjust_ulaw(sr, se, y, code, 4, qtab_726_24, 7); - } - return (sr << 2); -} -/*- End of function --------------------------------------------------------*/ - -/* - * Encodes a linear input sample and returns its 4-bit code. - */ -static uint8_t g726_32_encoder(g726_state_t *s, int16_t amp) -{ - int16_t sei; - int16_t sezi; - int16_t se; - int16_t d; - int16_t sr; - int16_t dqsez; - int16_t dq; - int16_t i; - int y; - - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - se = sei >> 1; - d = amp - se; - - /* Quantize the prediction difference */ - y = step_size(s); - i = quantize(d, y, qtab_726_32, 15); - dq = reconstruct(i & 8, g726_32_dqlntab[i], y); - - /* Reconstruct the signal */ - sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_32_witab[i], g726_32_fitab[i], dq, sr, dqsez); - return (uint8_t) i; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Decodes a 4-bit CCITT G.726_32 ADPCM code and returns - * the resulting 16-bit linear PCM, A-law or u-law sample value. - */ -static int16_t g726_32_decoder(g726_state_t *s, uint8_t code) -{ - int16_t sezi; - int16_t sei; - int16_t se; - int16_t sr; - int16_t dq; - int16_t dqsez; - int y; - - /* Mask to get proper bits */ - code &= 0x0F; - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - - y = step_size(s); - dq = reconstruct(code & 8, g726_32_dqlntab[code], y); - - /* Reconstruct the signal */ - se = sei >> 1; - sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_32_witab[code], g726_32_fitab[code], dq, sr, dqsez); - - switch (s->ext_coding) - { - case G726_ENCODING_ALAW: - return tandem_adjust_alaw(sr, se, y, code, 8, qtab_726_32, 15); - case G726_ENCODING_ULAW: - return tandem_adjust_ulaw(sr, se, y, code, 8, qtab_726_32, 15); - } - return (sr << 2); -} -/*- End of function --------------------------------------------------------*/ - -/* - * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens - * the resulting 5-bit CCITT G.726 40Kbps code. - */ -static uint8_t g726_40_encoder(g726_state_t *s, int16_t amp) -{ - int16_t sei; - int16_t sezi; - int16_t se; - int16_t d; - int16_t sr; - int16_t dqsez; - int16_t dq; - int16_t i; - int y; - - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - se = sei >> 1; - d = amp - se; - - /* Quantize prediction difference */ - y = step_size(s); - i = quantize(d, y, qtab_726_40, 31); - dq = reconstruct(i & 0x10, g726_40_dqlntab[i], y); - - /* Reconstruct the signal */ - sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_40_witab[i], g726_40_fitab[i], dq, sr, dqsez); - return (uint8_t) i; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Decodes a 5-bit CCITT G.726 40Kbps code and returns - * the resulting 16-bit linear PCM, A-law or u-law sample value. - */ -static int16_t g726_40_decoder(g726_state_t *s, uint8_t code) -{ - int16_t sezi; - int16_t sei; - int16_t se; - int16_t sr; - int16_t dq; - int16_t dqsez; - int y; - - /* Mask to get proper bits */ - code &= 0x1F; - sezi = predictor_zero(s); - sei = sezi + predictor_pole(s); - - y = step_size(s); - dq = reconstruct(code & 0x10, g726_40_dqlntab[code], y); - - /* Reconstruct the signal */ - se = sei >> 1; - sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); - - /* Pole prediction difference */ - dqsez = sr + (sezi >> 1) - se; - - update(s, y, g726_40_witab[code], g726_40_fitab[code], dq, sr, dqsez); - - switch (s->ext_coding) - { - case G726_ENCODING_ALAW: - return tandem_adjust_alaw(sr, se, y, code, 0x10, qtab_726_40, 31); - case G726_ENCODING_ULAW: - return tandem_adjust_ulaw(sr, se, y, code, 0x10, qtab_726_40, 31); - } - return (sr << 2); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(g726_state_t *) g726_init(g726_state_t *s, int bit_rate, int ext_coding, int packing) -{ - int i; - - if (bit_rate != 16000 && bit_rate != 24000 && bit_rate != 32000 && bit_rate != 40000) - return NULL; - if (s == NULL) - { - if ((s = (g726_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - s->yl = 34816; - s->yu = 544; - s->dms = 0; - s->dml = 0; - s->ap = 0; - s->rate = bit_rate; - s->ext_coding = ext_coding; - s->packing = packing; - for (i = 0; i < 2; i++) - { - s->a[i] = 0; - s->pk[i] = 0; - s->sr[i] = 32; - } - for (i = 0; i < 6; i++) - { - s->b[i] = 0; - s->dq[i] = 32; - } - s->td = false; - switch (bit_rate) - { - case 16000: - s->enc_func = g726_16_encoder; - s->dec_func = g726_16_decoder; - s->bits_per_sample = 2; - break; - case 24000: - s->enc_func = g726_24_encoder; - s->dec_func = g726_24_decoder; - s->bits_per_sample = 3; - break; - case 32000: - default: - s->enc_func = g726_32_encoder; - s->dec_func = g726_32_decoder; - s->bits_per_sample = 4; - break; - case 40000: - s->enc_func = g726_40_encoder; - s->dec_func = g726_40_decoder; - s->bits_per_sample = 5; - break; - } - bitstream_init(&s->bs, (s->packing != G726_PACKING_LEFT)); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g726_release(g726_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g726_free(g726_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g726_decode(g726_state_t *s, - int16_t amp[], - const uint8_t g726_data[], - int g726_bytes) -{ - int i; - int samples; - uint8_t code; - int sl; - - for (samples = i = 0; ; ) - { - if (s->packing != G726_PACKING_NONE) - { - /* Unpack the code bits */ - if (s->packing != G726_PACKING_LEFT) - { - if (s->bs.residue < s->bits_per_sample) - { - if (i >= g726_bytes) - break; - s->bs.bitstream |= (g726_data[i++] << s->bs.residue); - s->bs.residue += 8; - } - code = (uint8_t) (s->bs.bitstream & ((1 << s->bits_per_sample) - 1)); - s->bs.bitstream >>= s->bits_per_sample; - } - else - { - if (s->bs.residue < s->bits_per_sample) - { - if (i >= g726_bytes) - break; - s->bs.bitstream = (s->bs.bitstream << 8) | g726_data[i++]; - s->bs.residue += 8; - } - code = (uint8_t) ((s->bs.bitstream >> (s->bs.residue - s->bits_per_sample)) & ((1 << s->bits_per_sample) - 1)); - } - s->bs.residue -= s->bits_per_sample; - } - else - { - if (i >= g726_bytes) - break; - code = g726_data[i++]; - } - sl = s->dec_func(s, code); - if (s->ext_coding != G726_ENCODING_LINEAR) - ((uint8_t *) amp)[samples++] = (uint8_t) sl; - else - amp[samples++] = (int16_t) sl; - } - return samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) g726_encode(g726_state_t *s, - uint8_t g726_data[], - const int16_t amp[], - int len) -{ - int i; - int g726_bytes; - int16_t sl; - uint8_t code; - - for (g726_bytes = i = 0; i < len; i++) - { - /* Linearize the input sample to 14-bit PCM */ - switch (s->ext_coding) - { - case G726_ENCODING_ALAW: - sl = alaw_to_linear(((const uint8_t *) amp)[i]) >> 2; - break; - case G726_ENCODING_ULAW: - sl = ulaw_to_linear(((const uint8_t *) amp)[i]) >> 2; - break; - default: - sl = amp[i] >> 2; - break; - } - code = s->enc_func(s, sl); - if (s->packing != G726_PACKING_NONE) - { - /* Pack the code bits */ - if (s->packing != G726_PACKING_LEFT) - { - s->bs.bitstream |= (code << s->bs.residue); - s->bs.residue += s->bits_per_sample; - if (s->bs.residue >= 8) - { - g726_data[g726_bytes++] = (uint8_t) (s->bs.bitstream & 0xFF); - s->bs.bitstream >>= 8; - s->bs.residue -= 8; - } - } - else - { - s->bs.bitstream = (s->bs.bitstream << s->bits_per_sample) | code; - s->bs.residue += s->bits_per_sample; - if (s->bs.residue >= 8) - { - g726_data[g726_bytes++] = (uint8_t) ((s->bs.bitstream >> (s->bs.residue - 8)) & 0xFF); - s->bs.residue -= 8; - } - } - } - else - { - g726_data[g726_bytes++] = (uint8_t) code; - } - } - return g726_bytes; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_decode.c b/libs/spandsp/src/gsm0610_decode.c deleted file mode 100644 index 81097d1a21..0000000000 --- a/libs/spandsp/src/gsm0610_decode.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_decode.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include -#include - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/saturated.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER */ - -static void postprocessing(gsm0610_state_t *s, int16_t amp[]) -{ - int k; - int16_t msr; - int16_t tmp; - - msr = s->msr; - for (k = 0; k < GSM0610_FRAME_LEN; k++) - { - tmp = gsm_mult_r(msr, 28180); - /* De-emphasis */ - msr = sat_add16(amp[k], tmp); - /* Truncation and upscaling */ - amp[k] = (int16_t) (sat_add16(msr, msr) & 0xFFF8); - } - /*endfor*/ - s->msr = msr; -} -/*- End of function --------------------------------------------------------*/ - -static void decode_a_frame(gsm0610_state_t *s, - int16_t amp[GSM0610_FRAME_LEN], - gsm0610_frame_t *f) -{ - int j; - int k; - int16_t erp[40]; - int16_t wt[GSM0610_FRAME_LEN]; - int16_t *drp; - - drp = s->dp0 + 120; - for (j = 0; j < 4; j++) - { - gsm0610_rpe_decoding(s, f->xmaxc[j], f->Mc[j], f->xMc[j], erp); - gsm0610_long_term_synthesis_filtering(s, f->Nc[j], f->bc[j], erp, drp); - for (k = 0; k < 40; k++) - wt[j*40 + k] = drp[k]; - /*endfor*/ - } - /*endfor*/ - - gsm0610_short_term_synthesis_filter(s, f->LARc, wt, amp); - postprocessing(s, amp); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_unpack_none(gsm0610_frame_t *s, const uint8_t c[]) -{ - int i; - int j; - int k; - - i = 0; - for (j = 0; j < 8; j++) - s->LARc[j] = c[i++]; - for (j = 0; j < 4; j++) - { - s->Nc[j] = c[i++]; - s->bc[j] = c[i++]; - s->Mc[j] = c[i++]; - s->xmaxc[j] = c[i++]; - for (k = 0; k < 13; k++) - s->xMc[j][k] = c[i++]; - } - return 76; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_unpack_wav49(gsm0610_frame_t *s, const uint8_t c[]) -{ - uint16_t sr; - int i; - - sr = *c++; - s->LARc[0] = sr & 0x3F; - sr >>= 6; - sr |= (uint16_t) *c++ << 2; - s->LARc[1] = sr & 0x3F; - sr >>= 6; - sr |= (uint16_t) *c++ << 4; - s->LARc[2] = sr & 0x1F; - sr >>= 5; - s->LARc[3] = sr & 0x1F; - sr >>= 5; - sr |= (uint16_t) *c++ << 2; - s->LARc[4] = sr & 0xF; - sr >>= 4; - s->LARc[5] = sr & 0xF; - sr >>= 4; - sr |= (uint16_t) *c++ << 2; - s->LARc[6] = sr & 0x7; - sr >>= 3; - s->LARc[7] = sr & 0x7; - sr >>= 3; - - for (i = 0; i < 4; i++) - { - sr |= (uint16_t) *c++ << 4; - s->Nc[i] = sr & 0x7F; - sr >>= 7; - s->bc[i] = sr & 0x3; - sr >>= 2; - s->Mc[i] = sr & 0x3; - sr >>= 2; - sr |= (uint16_t) *c++ << 1; - s->xmaxc[i] = sr & 0x3F; - sr >>= 6; - s->xMc[i][0] = sr & 0x7; - sr = *c++; - s->xMc[i][1] = sr & 0x7; - sr >>= 3; - s->xMc[i][2] = sr & 0x7; - sr >>= 3; - sr |= (uint16_t) *c++ << 2; - s->xMc[i][3] = sr & 0x7; - sr >>= 3; - s->xMc[i][4] = sr & 0x7; - sr >>= 3; - s->xMc[i][5] = sr & 0x7; - sr >>= 3; - sr |= (uint16_t) *c++ << 1; - s->xMc[i][6] = sr & 0x7; - sr >>= 3; - s->xMc[i][7] = sr & 0x7; - sr >>= 3; - s->xMc[i][8] = sr & 0x7; - sr = *c++; - s->xMc[i][9] = sr & 0x7; - sr >>= 3; - s->xMc[i][10] = sr & 0x7; - sr >>= 3; - sr |= (uint16_t) *c++ << 2; - s->xMc[i][11] = sr & 0x7; - sr >>= 3; - s->xMc[i][12] = sr & 0x7; - sr >>= 3; - } - - s++; - sr |= (uint16_t) *c++ << 4; - s->LARc[0] = sr & 0x3F; - sr >>= 6; - s->LARc[1] = sr & 0x3F; - sr = *c++; - s->LARc[2] = sr & 0x1F; - sr >>= 5; - sr |= (uint16_t) *c++ << 3; - s->LARc[3] = sr & 0x1F; - sr >>= 5; - s->LARc[4] = sr & 0xF; - sr >>= 4; - sr |= (uint16_t) *c++ << 2; - s->LARc[5] = sr & 0xF; - sr >>= 4; - s->LARc[6] = sr & 0x7; - sr >>= 3; - s->LARc[7] = sr & 0x7; - - for (i = 0; i < 4; i++) - { - sr = *c++; - s->Nc[i] = sr & 0x7F; - sr >>= 7; - sr |= (uint16_t) *c++ << 1; - s->bc[i] = sr & 0x3; - sr >>= 2; - s->Mc[i] = sr & 0x3; - sr >>= 2; - sr |= (uint16_t) *c++ << 5; - s->xmaxc[i] = sr & 0x3F; - sr >>= 6; - s->xMc[i][0] = sr & 0x7; - sr >>= 3; - s->xMc[i][1] = sr & 0x7; - sr >>= 3; - sr |= (uint16_t) *c++ << 1; - s->xMc[i][2] = sr & 0x7; - sr >>= 3; - s->xMc[i][3] = sr & 0x7; - sr >>= 3; - s->xMc[i][4] = sr & 0x7; - sr = *c++; - s->xMc[i][5] = sr & 0x7; - sr >>= 3; - s->xMc[i][6] = sr & 0x7; - sr >>= 3; - sr |= (uint16_t) *c++ << 2; - s->xMc[i][7] = sr & 0x7; - sr >>= 3; - s->xMc[i][8] = sr & 0x7; - sr >>= 3; - s->xMc[i][9] = sr & 0x7; - sr >>= 3; - sr |= (uint16_t) *c++ << 1; - s->xMc[i][10] = sr & 0x7; - sr >>= 3; - s->xMc[i][11] = sr & 0x7; - sr >>= 3; - s->xMc[i][12] = sr & 0x7; - } - return 65; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_unpack_voip(gsm0610_frame_t *s, const uint8_t c[33]) -{ - int i; - - s->LARc[0] = (*c++ & 0xF) << 2; - s->LARc[0] |= (*c >> 6) & 0x3; - s->LARc[1] = *c++ & 0x3F; - s->LARc[2] = (*c >> 3) & 0x1F; - s->LARc[3] = (*c++ & 0x7) << 2; - s->LARc[3] |= (*c >> 6) & 0x3; - s->LARc[4] = (*c >> 2) & 0xF; - s->LARc[5] = (*c++ & 0x3) << 2; - s->LARc[5] |= (*c >> 6) & 0x3; - s->LARc[6] = (*c >> 3) & 0x7; - s->LARc[7] = *c++ & 0x7; - - for (i = 0; i < 4; i++) - { - s->Nc[i] = (*c >> 1) & 0x7F; - s->bc[i] = (*c++ & 0x1) << 1; - s->bc[i] |= (*c >> 7) & 0x1; - s->Mc[i] = (*c >> 5) & 0x3; - s->xmaxc[i] = (*c++ & 0x1F) << 1; - s->xmaxc[i] |= (*c >> 7) & 0x1; - s->xMc[i][0] = (*c >> 4) & 0x7; - s->xMc[i][1] = (*c >> 1) & 0x7; - s->xMc[i][2] = (*c++ & 0x1) << 2; - s->xMc[i][2] |= (*c >> 6) & 0x3; - s->xMc[i][3] = (*c >> 3) & 0x7; - s->xMc[i][4] = *c++ & 0x7; - s->xMc[i][5] = (*c >> 5) & 0x7; - s->xMc[i][6] = (*c >> 2) & 0x7; - s->xMc[i][7] = (*c++ & 0x3) << 1; - s->xMc[i][7] |= (*c >> 7) & 0x1; - s->xMc[i][8] = (*c >> 4) & 0x7; - s->xMc[i][9] = (*c >> 1) & 0x7; - s->xMc[i][10] = (*c++ & 0x1) << 2; - s->xMc[i][10] |= (*c >> 6) & 0x3; - s->xMc[i][11] = (*c >> 3) & 0x7; - s->xMc[i][12] = *c++ & 0x7; - } - return 33; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_decode(gsm0610_state_t *s, int16_t amp[], const uint8_t code[], int len) -{ - gsm0610_frame_t frame[2]; - int bytes; - int samples; - int i; - - samples = 0; - for (i = 0; i < len; i += bytes) - { - switch (s->packing) - { - default: - case GSM0610_PACKING_NONE: - if ((bytes = gsm0610_unpack_none(frame, &code[i])) < 0) - return 0; - decode_a_frame(s, &[samples], frame); - samples += GSM0610_FRAME_LEN; - break; - case GSM0610_PACKING_WAV49: - if ((bytes = gsm0610_unpack_wav49(frame, &code[i])) < 0) - return 0; - decode_a_frame(s, &[samples], frame); - samples += GSM0610_FRAME_LEN; - decode_a_frame(s, &[samples], frame + 1); - samples += GSM0610_FRAME_LEN; - break; - case GSM0610_PACKING_VOIP: - if ((bytes = gsm0610_unpack_voip(frame, &code[i])) < 0) - return 0; - decode_a_frame(s, &[samples], frame); - samples += GSM0610_FRAME_LEN; - break; - } - /*endswitch*/ - } - /*endfor*/ - return samples; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_encode.c b/libs/spandsp/src/gsm0610_encode.c deleted file mode 100644 index 7621f22adc..0000000000 --- a/libs/spandsp/src/gsm0610_encode.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_encode.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include -#include - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/saturated.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER */ - -/* The RPE-LTD coder works on a frame by frame basis. The length of - the frame is equal to 160 samples. Some computations are done - once per frame to produce at the output of the coder the - LARc[1..8] parameters which are the coded LAR coefficients and - also to realize the inverse filtering operation for the entire - frame (160 samples of signal d[0..159]). These parts produce at - the output of the coder: - - Procedure 4.2.11 to 4.2.18 are to be executed four times per - frame. That means once for each sub-segment RPE-LTP analysis of - 40 samples. These parts produce at the output of the coder. -*/ -static void encode_a_frame(gsm0610_state_t *s, gsm0610_frame_t *f, const int16_t amp[]) -{ - int k; - int16_t *dp; - int16_t *dpp; - int16_t so[GSM0610_FRAME_LEN]; - int i; - - dp = s->dp0 + 120; - dpp = dp; - gsm0610_preprocess(s, amp, so); - gsm0610_lpc_analysis(s, so, f->LARc); - gsm0610_short_term_analysis_filter(s, f->LARc, so); - - for (k = 0; k < 4; k++) - { - gsm0610_long_term_predictor(s, - so + k*40, - dp, - s->e + 5, - dpp, - &f->Nc[k], - &f->bc[k]); - gsm0610_rpe_encoding(s, s->e + 5, &f->xmaxc[k], &f->Mc[k], f->xMc[k]); - - for (i = 0; i < 40; i++) - dp[i] = sat_add16(s->e[5 + i], dpp[i]); - /*endfor*/ - dp += 40; - dpp += 40; - } - /*endfor*/ - memcpy((char *) s->dp0, - (char *) (s->dp0 + GSM0610_FRAME_LEN), - 120*sizeof(*s->dp0)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_set_packing(gsm0610_state_t *s, int packing) -{ - s->packing = packing; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(gsm0610_state_t *) gsm0610_init(gsm0610_state_t *s, int packing) -{ - if (s == NULL) - { - if ((s = (gsm0610_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset((char *) s, '\0', sizeof(gsm0610_state_t)); - s->nrp = 40; - s->packing = packing; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_release(gsm0610_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_free(gsm0610_state_t *s) -{ - if (s) - span_free(s); - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_pack_none(uint8_t c[], const gsm0610_frame_t *s) -{ - int i; - int j; - int k; - - i = 0; - for (j = 0; j < 8; j++) - c[i++] = (uint8_t) s->LARc[j]; - for (j = 0; j < 4; j++) - { - c[i++] = (uint8_t) s->Nc[j]; - c[i++] = (uint8_t) s->bc[j]; - c[i++] = (uint8_t) s->Mc[j]; - c[i++] = (uint8_t) s->xmaxc[j]; - for (k = 0; k < 13; k++) - c[i++] = (uint8_t) s->xMc[j][k]; - } - /*endfor*/ - return 76; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_pack_wav49(uint8_t c[], const gsm0610_frame_t *s) -{ - uint16_t sr; - int i; - - sr = 0; - sr = (sr >> 6) | (s->LARc[0] << 10); - sr = (sr >> 6) | (s->LARc[1] << 10); - *c++ = (uint8_t) (sr >> 4); - sr = (sr >> 5) | (s->LARc[2] << 11); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 5) | (s->LARc[3] << 11); - sr = (sr >> 4) | (s->LARc[4] << 12); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 4) | (s->LARc[5] << 12); - sr = (sr >> 3) | (s->LARc[6] << 13); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 3) | (s->LARc[7] << 13); - - for (i = 0; i < 4; i++) - { - sr = (sr >> 7) | (s->Nc[i] << 9); - *c++ = (uint8_t) (sr >> 5); - sr = (sr >> 2) | (s->bc[i] << 14); - sr = (sr >> 2) | (s->Mc[i] << 14); - sr = (sr >> 6) | (s->xmaxc[i] << 10); - *c++ = (uint8_t) (sr >> 3); - sr = (sr >> 3) | (s->xMc[i][0] << 13); - *c++ = (uint8_t) (sr >> 8); - sr = (sr >> 3) | (s->xMc[i][1] << 13); - sr = (sr >> 3) | (s->xMc[i][2] << 13); - sr = (sr >> 3) | (s->xMc[i][3] << 13); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 3) | (s->xMc[i][4] << 13); - sr = (sr >> 3) | (s->xMc[i][5] << 13); - sr = (sr >> 3) | (s->xMc[i][6] << 13); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 3) | (s->xMc[i][7] << 13); - sr = (sr >> 3) | (s->xMc[i][8] << 13); - *c++ = (uint8_t) (sr >> 8); - sr = (sr >> 3) | (s->xMc[i][9] << 13); - sr = (sr >> 3) | (s->xMc[i][10] << 13); - sr = (sr >> 3) | (s->xMc[i][11] << 13); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 3) | (s->xMc[i][12] << 13); - } - /*endfor*/ - - s++; - sr = (sr >> 6) | (s->LARc[0] << 10); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 6) | (s->LARc[1] << 10); - *c++ = (uint8_t) (sr >> 8); - sr = (sr >> 5) | (s->LARc[2] << 11); - sr = (sr >> 5) | (s->LARc[3] << 11); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 4) | (s->LARc[4] << 12); - sr = (sr >> 4) | (s->LARc[5] << 12); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 3) | (s->LARc[6] << 13); - sr = (sr >> 3) | (s->LARc[7] << 13); - *c++ = (uint8_t) (sr >> 8); - - for (i = 0; i < 4; i++) - { - sr = (sr >> 7) | (s->Nc[i] << 9); - sr = (sr >> 2) | (s->bc[i] << 14); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 2) | (s->Mc[i] << 14); - sr = (sr >> 6) | (s->xmaxc[i] << 10); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 3) | (s->xMc[i][0] << 13); - sr = (sr >> 3) | (s->xMc[i][1] << 13); - sr = (sr >> 3) | (s->xMc[i][2] << 13); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 3) | (s->xMc[i][3] << 13); - sr = (sr >> 3) | (s->xMc[i][4] << 13); - *c++ = (uint8_t) (sr >> 8); - sr = (sr >> 3) | (s->xMc[i][5] << 13); - sr = (sr >> 3) | (s->xMc[i][6] << 13); - sr = (sr >> 3) | (s->xMc[i][7] << 13); - *c++ = (uint8_t) (sr >> 7); - sr = (sr >> 3) | (s->xMc[i][8] << 13); - sr = (sr >> 3) | (s->xMc[i][9] << 13); - sr = (sr >> 3) | (s->xMc[i][10] << 13); - *c++ = (uint8_t) (sr >> 6); - sr = (sr >> 3) | (s->xMc[i][11] << 13); - sr = (sr >> 3) | (s->xMc[i][12] << 13); - *c++ = (uint8_t) (sr >> 8); - } - /*endfor*/ - return 65; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_pack_voip(uint8_t c[33], const gsm0610_frame_t *s) -{ - int i; - - *c++ = (uint8_t) (((GSM0610_MAGIC & 0xF) << 4) - | ((s->LARc[0] >> 2) & 0xF)); - *c++ = (uint8_t) (((s->LARc[0] & 0x3) << 6) - | (s->LARc[1] & 0x3F)); - *c++ = (uint8_t) (((s->LARc[2] & 0x1F) << 3) - | ((s->LARc[3] >> 2) & 0x7)); - *c++ = (uint8_t) (((s->LARc[3] & 0x3) << 6) - | ((s->LARc[4] & 0xF) << 2) - | ((s->LARc[5] >> 2) & 0x3)); - *c++ = (uint8_t) (((s->LARc[5] & 0x3) << 6) - | ((s->LARc[6] & 0x7) << 3) - | (s->LARc[7] & 0x7)); - - for (i = 0; i < 4; i++) - { - *c++ = (uint8_t) (((s->Nc[i] & 0x7F) << 1) - | ((s->bc[i] >> 1) & 0x1)); - *c++ = (uint8_t) (((s->bc[i] & 0x1) << 7) - | ((s->Mc[i] & 0x3) << 5) - | ((s->xmaxc[i] >> 1) & 0x1F)); - *c++ = (uint8_t) (((s->xmaxc[i] & 0x1) << 7) - | ((s->xMc[i][0] & 0x7) << 4) - | ((s->xMc[i][1] & 0x7) << 1) - | ((s->xMc[i][2] >> 2) & 0x1)); - *c++ = (uint8_t) (((s->xMc[i][2] & 0x3) << 6) - | ((s->xMc[i][3] & 0x7) << 3) - | (s->xMc[i][4] & 0x7)); - *c++ = (uint8_t) (((s->xMc[i][5] & 0x7) << 5) - | ((s->xMc[i][6] & 0x7) << 2) - | ((s->xMc[i][7] >> 1) & 0x3)); - *c++ = (uint8_t) (((s->xMc[i][7] & 0x1) << 7) - | ((s->xMc[i][8] & 0x7) << 4) - | ((s->xMc[i][9] & 0x7) << 1) - | ((s->xMc[i][10] >> 2) & 0x1)); - *c++ = (uint8_t) (((s->xMc[i][10] & 0x3) << 6) - | ((s->xMc[i][11] & 0x7) << 3) - | (s->xMc[i][12] & 0x7)); - } - /*endfor*/ - return 33; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) gsm0610_encode(gsm0610_state_t *s, uint8_t code[], const int16_t amp[], int len) -{ - gsm0610_frame_t frame[2]; - int bytes; - int i; - - bytes = 0; - for (i = 0; i < len; i += GSM0610_FRAME_LEN) - { - encode_a_frame(s, frame, &[i]); - switch (s->packing) - { - case GSM0610_PACKING_WAV49: - i += GSM0610_FRAME_LEN; - encode_a_frame(s, frame + 1, &[i]); - bytes += gsm0610_pack_wav49(&code[bytes], frame); - break; - case GSM0610_PACKING_VOIP: - bytes += gsm0610_pack_voip(&code[bytes], frame); - break; - default: - bytes += gsm0610_pack_none(&code[bytes], frame); - break; - } - /*endswitch*/ - } - /*endfor*/ - return bytes; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_local.h b/libs/spandsp/src/gsm0610_local.h deleted file mode 100644 index e1b3b10ed8..0000000000 --- a/libs/spandsp/src/gsm0610_local.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_local.h - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -#if !defined(_GSM0610_LOCAL_H_) -#define _GSM0610_LOCAL_H_ - -#define GSM0610_FRAME_LEN 160 - -#define GSM0610_MAGIC 0xD - -#include "spandsp/private/gsm0610.h" - -static __inline__ int16_t gsm_add(int16_t a, int16_t b) -{ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__( - " addw %2,%0;\n" - " jno 0f;\n" - " movw $0x7fff,%0;\n" - " adcw $0,%0;\n" - "0:" - : "=&r" (a) - : "0" (a), "ir" (b) - : "cc" - ); - return a; -#else - int32_t sum; - - sum = (int32_t) a + (int32_t) b; - return saturate16(sum); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t gsm_l_add(int32_t a, int32_t b) -{ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__( - " addl %2,%0;\n" - " jno 0f;\n" - " movl $0x7fffffff,%0;\n" - " adcl $0,%0;\n" - "0:" - : "=&r" (a) - : "0" (a), "ir" (b) - : "cc" - ); - return a; -#else - uint32_t A; - - if (a < 0) - { - if (b >= 0) - return a + b; - /*endif*/ - A = (uint32_t) -(a + 1) + (uint32_t) -(b + 1); - return (A >= INT32_MAX) ? INT32_MIN : -(int32_t) A - 2; - } - /*endif*/ - if (b <= 0) - return a + b; - /*endif*/ - A = (uint32_t) a + (uint32_t) b; - return (A > INT32_MAX) ? INT32_MAX : A; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t gsm_sub(int16_t a, int16_t b) -{ - int32_t diff; - - diff = (int32_t) a - (int32_t) b; - return saturate16(diff); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t gsm_mult(int16_t a, int16_t b) -{ - if (a == INT16_MIN && b == INT16_MIN) - return INT16_MAX; - /*endif*/ - return (int16_t) (((int32_t) a * (int32_t) b) >> 15); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t gsm_l_mult(int16_t a, int16_t b) -{ - assert (a != INT16_MIN || b != INT16_MIN); - return ((int32_t) a * (int32_t) b) << 1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t gsm_mult_r(int16_t a, int16_t b) -{ - int32_t prod; - - if (b == INT16_MIN && a == INT16_MIN) - return INT16_MAX; - /*endif*/ - prod = (int32_t) a * (int32_t) b + 16384; - prod >>= 15; - return (int16_t) (prod & 0xFFFF); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t gsm_abs(int16_t a) -{ - return (a == INT16_MIN) ? INT16_MAX : (int16_t) abs(a); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t gsm_asr(int16_t a, int n) -{ - if (n >= 16) - return (int16_t) (-(a < 0)); - /*endif*/ - if (n <= -16) - return 0; - /*endif*/ - if (n < 0) - return (int16_t) (a << -n); - /*endif*/ - return (int16_t) (a >> n); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t gsm_asl(int16_t a, int n) -{ - if (n >= 16) - return 0; - /*endif*/ - if (n <= -16) - return (int16_t) (-(a < 0)); - /*endif*/ - if (n < 0) - return gsm_asr(a, -n); - /*endif*/ - return (int16_t) (a << n); -} -/*- End of function --------------------------------------------------------*/ - -extern void gsm0610_long_term_predictor(gsm0610_state_t *s, - int16_t d[40], - int16_t *dp, /* [-120..-1] d' IN */ - int16_t e[40], - int16_t dpp[40], - int16_t *Nc, - int16_t *bc); - -extern void gsm0610_lpc_analysis(gsm0610_state_t *s, - int16_t amp[160], - int16_t LARc[8]); - -extern void gsm0610_preprocess(gsm0610_state_t *s, - const int16_t amp[], - int16_t so[]); - -extern void gsm0610_short_term_analysis_filter(gsm0610_state_t *s, - int16_t LARc[8], - int16_t amp[160]); - -extern void gsm0610_long_term_synthesis_filtering(gsm0610_state_t *s, - int16_t Ncr, - int16_t bcr, - int16_t erp[40], - int16_t *drp); /* [-120..-1] IN, [0..40] OUT */ - -extern void gsm0610_rpe_decoding(gsm0610_state_t *s, - int16_t xmaxcr, - int16_t Mcr, - int16_t *xMcr, /* [0..12], 3 bits IN */ - int16_t erp[40]); - -extern void gsm0610_rpe_encoding(gsm0610_state_t *s, - int16_t *e, /* [-5..-1][0..39][40..44] IN/OUT */ - int16_t *xmaxc, - int16_t *Mc, - int16_t xMc[13]); - -extern void gsm0610_short_term_synthesis_filter(gsm0610_state_t *s, - int16_t LARcr[8], - int16_t drp[40], - int16_t amp[160]); - -extern int16_t gsm0610_norm(int32_t a); - -#endif - -/*- End of include ---------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_long_term.c b/libs/spandsp/src/gsm0610_long_term.c deleted file mode 100644 index 2ec7aa7818..0000000000 --- a/libs/spandsp/src/gsm0610_long_term.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_long_term.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/saturated.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* Table 4.3a Decision level of the LTP gain quantizer */ -static const int16_t gsm_DLB[4] = -{ - 6554, 16384, 26214, 32767 -}; - -/* Table 4.3b Quantization levels of the LTP gain quantizer */ -static const int16_t gsm_QLB[4] = -{ - 3277, 11469, 21299, 32767 -}; - -/* 4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION */ - -static int32_t gsm0610_max_cross_corr(const int16_t *wt, const int16_t *dp, int16_t *index_out) -{ - int32_t max; - int32_t index; - int32_t res; - int i; - - max = 0; - index = 40; /* index for the maximum cross-correlation */ - - for (i = 40; i <= 120; i++) - { -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__x86_64__) - __asm__ __volatile__( - " emms;\n" - " .p2align 2;\n" - " movq (%%rdi),%%mm0;\n" - " movq (%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm0;\n" - " movq 8(%%rdi),%%mm1;\n" - " movq 8(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 16(%%rdi),%%mm1;\n" - " movq 16(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 24(%%rdi),%%mm1;\n" - " movq 24(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 32(%%rdi),%%mm1;\n" - " movq 32(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 40(%%rdi),%%mm1;\n" - " movq 40(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 48(%%rdi),%%mm1;\n" - " movq 48(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 56(%%rdi),%%mm1;\n" - " movq 56(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 64(%%rdi),%%mm1;\n" - " movq 64(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 72(%%rdi),%%mm1;\n" - " movq 72(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq %%mm0,%%mm1;\n" - " punpckhdq %%mm0,%%mm1;\n" /* mm1 has high int32 of mm0 dup'd */ - " paddd %%mm1,%%mm0;\n" - " movd %%mm0,%[res];\n" - " emms;\n" - : [res] "=r" (res) - : "D" (wt), "S" (&dp[-i]) - ); -#elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) - __asm__ __volatile__( - " emms;\n" - " .p2align 2;\n" - " movq (%%edi),%%mm0;\n" - " movq (%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm0;\n" - " movq 8(%%edi),%%mm1;\n" - " movq 8(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 16(%%edi),%%mm1;\n" - " movq 16(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 24(%%edi),%%mm1;\n" - " movq 24(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 32(%%edi),%%mm1;\n" - " movq 32(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 40(%%edi),%%mm1;\n" - " movq 40(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 48(%%edi),%%mm1;\n" - " movq 48(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 56(%%edi),%%mm1;\n" - " movq 56(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 64(%%edi),%%mm1;\n" - " movq 64(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 72(%%edi),%%mm1;\n" - " movq 72(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq %%mm0,%%mm1;\n" - " punpckhdq %%mm0,%%mm1;\n" /* mm1 has high int32 of mm0 dup'd */ - " paddd %%mm1,%%mm0;\n" - " movd %%mm0,%[res];\n" - " emms;\n" - : [res] "=r" (res) - : "D" (wt), "S" (&dp[-i]) - ); -#else - res = (wt[0]*dp[0 - i]) - + (wt[1]*dp[1 - i]) - + (wt[2]*dp[2 - i]) - + (wt[3]*dp[3 - i]) - + (wt[4]*dp[4 - i]) - + (wt[5]*dp[5 - i]) - + (wt[6]*dp[6 - i]) - + (wt[7]*dp[7 - i]) - + (wt[8]*dp[8 - i]) - + (wt[9]*dp[9 - i]) - + (wt[10]*dp[10 - i]) - + (wt[11]*dp[11 - i]) - + (wt[12]*dp[12 - i]) - + (wt[13]*dp[13 - i]) - + (wt[14]*dp[14 - i]) - + (wt[15]*dp[15 - i]) - + (wt[16]*dp[16 - i]) - + (wt[17]*dp[17 - i]) - + (wt[18]*dp[18 - i]) - + (wt[19]*dp[19 - i]) - + (wt[20]*dp[20 - i]) - + (wt[21]*dp[21 - i]) - + (wt[22]*dp[22 - i]) - + (wt[23]*dp[23 - i]) - + (wt[24]*dp[24 - i]) - + (wt[25]*dp[25 - i]) - + (wt[26]*dp[26 - i]) - + (wt[27]*dp[27 - i]) - + (wt[28]*dp[28 - i]) - + (wt[29]*dp[29 - i]) - + (wt[30]*dp[30 - i]) - + (wt[31]*dp[31 - i]) - + (wt[32]*dp[32 - i]) - + (wt[33]*dp[33 - i]) - + (wt[34]*dp[34 - i]) - + (wt[35]*dp[35 - i]) - + (wt[36]*dp[36 - i]) - + (wt[37]*dp[37 - i]) - + (wt[38]*dp[38 - i]) - + (wt[39]*dp[39 - i]); -#endif - if (res > max) - { - max = res; - index = i; - } - /*endif*/ - } - /*endfor*/ - *index_out = index; - return max; -} -/*- End of function --------------------------------------------------------*/ - -/* This procedure computes the LTP gain (bc) and the LTP lag (Nc) - for the long term analysis filter. This is done by calculating a - maximum of the cross-correlation function between the current - sub-segment short term residual signal d[0..39] (output of - the short term analysis filter; for simplification the index - of this array begins at 0 and ends at 39 for each sub-segment of the - RPE-LTP analysis) and the previous reconstructed short term - residual signal dp[ -120 .. -1 ]. A dynamic scaling must be - performed to avoid overflow. */ - -/* This procedure exists in three versions. First, the integer - version; then, the two floating point versions (as another - function), with or without scaling. */ - -static int16_t evaluate_ltp_parameters(int16_t d[40], - int16_t *dp, // [-120..-1] IN - int16_t *Nc_out) -{ - int k; - int16_t bc; - int16_t wt[40]; - int32_t L_max; - int32_t L_power; - int16_t R; - int16_t S; - int16_t dmax; - int16_t scale; - int16_t temp; - int32_t L_temp; - - /* Search of the optimum scaling of d[0..39]. */ - dmax = 0; - for (k = 0; k < 40; k++) - { - temp = d[k]; - temp = sat_abs16(temp); - if (temp > dmax) - dmax = temp; - /*endif*/ - } - /*endfor*/ - - if (dmax == 0) - { - temp = 0; - } - else - { - assert(dmax > 0); - temp = gsm0610_norm((int32_t) dmax << 16); - } - /*endif*/ - - if (temp > 6) - scale = 0; - else - scale = (int16_t) (6 - temp); - /*endif*/ - assert(scale >= 0); - - /* Initialization of a working array wt */ - for (k = 0; k < 40; k++) - wt[k] = d[k] >> scale; - /*endfor*/ - - /* Search for the maximum cross-correlation and coding of the LTP lag */ - L_max = gsm0610_max_cross_corr(wt, dp, Nc_out); - L_max <<= 1; - - /* Rescaling of L_max */ - assert(scale <= 100 && scale >= -100); - L_max = L_max >> (6 - scale); - - assert(*Nc_out <= 120 && *Nc_out >= 40); - - /* Compute the power of the reconstructed short term residual signal dp[..] */ - L_power = 0; - for (k = 0; k < 40; k++) - { - L_temp = dp[k - *Nc_out] >> 3; - L_power += L_temp*L_temp; - } - /*endfor*/ - L_power <<= 1; /* from L_MULT */ - - /* Normalization of L_max and L_power */ - if (L_max <= 0) - return 0; - /*endif*/ - if (L_max >= L_power) - return 3; - /*endif*/ - temp = gsm0610_norm(L_power); - - R = (int16_t) ((L_max << temp) >> 16); - S = (int16_t) ((L_power << temp) >> 16); - - /* Coding of the LTP gain */ - - /* Table 4.3a must be used to obtain the level DLB[i] for the - quantization of the LTP gain b to get the coded version bc. */ - for (bc = 0; bc <= 2; bc++) - { - if (R <= sat_mul16(S, gsm_DLB[bc])) - break; - /*endif*/ - } - /*endfor*/ - return bc; -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.12 */ -static void long_term_analysis_filtering(int16_t bc, - int16_t Nc, - int16_t *dp, // previous d [-120..-1] IN - int16_t d[40], - int16_t dpp[40], - int16_t e[40]) -{ - int k; - - /* In this part, we have to decode the bc parameter to compute - the samples of the estimate dpp[0..39]. The decoding of bc needs the - use of table 4.3b. The long term residual signal e[0..39] - is then calculated to be fed to the RPE encoding section. */ - for (k = 0; k < 40; k++) - { - dpp[k] = gsm_mult_r(gsm_QLB[bc], dp[k - Nc]); - e[k] = sat_sub16(d[k], dpp[k]); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4x for 160 samples */ -void gsm0610_long_term_predictor(gsm0610_state_t *s, - int16_t d[40], - int16_t *dp, // [-120..-1] d' IN - int16_t e[40], - int16_t dpp[40], - int16_t *Nc, - int16_t *bc) -{ -#if 0 - assert(d); - assert(dp); - assert(e); - assert(dpp); - assert(Nc); - assert(bc); -#endif - - *bc = evaluate_ltp_parameters(d, dp, Nc); - long_term_analysis_filtering(*bc, *Nc, dp, d, dpp, e); -} -/*- End of function --------------------------------------------------------*/ - -/* 4.3.2 */ -void gsm0610_long_term_synthesis_filtering(gsm0610_state_t *s, - int16_t Ncr, - int16_t bcr, - int16_t erp[40], - int16_t *drp) // [-120..-1] IN, [0..40] OUT -{ - int k; - int16_t brp; - int16_t drpp; - int16_t Nr; - - /* This procedure uses the bcr and Ncr parameters to realize the - long term synthesis filter. The decoding of bcr needs - table 4.3b. */ - - /* Check the limits of Nr. */ - Nr = (Ncr < 40 || Ncr > 120) ? s->nrp : Ncr; - s->nrp = Nr; - assert (Nr >= 40 && Nr <= 120); - - /* Decode the LTP gain, bcr */ - brp = gsm_QLB[bcr]; - - /* Compute the reconstructed short term residual signal, drp[0..39] */ - assert(brp != INT16_MIN); - for (k = 0; k < 40; k++) - { - drpp = gsm_mult_r(brp, drp[k - Nr]); - drp[k] = sat_add16(erp[k], drpp); - } - /*endfor*/ - - /* Update the reconstructed short term residual signal, drp[-1..-120] */ - for (k = 0; k < 120; k++) - drp[k - 120] = drp[k - 80]; - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_lpc.c b/libs/spandsp/src/gsm0610_lpc.c deleted file mode 100644 index c1341882d8..0000000000 --- a/libs/spandsp/src/gsm0610_lpc.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_lpc.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include -#include -#include - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/bit_operations.h" -#include "spandsp/saturated.h" -#include "spandsp/vector_int.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION */ - -/* The number of left shifts needed to normalize the 32 bit - variable x for positive values on the interval - with minimum of - minimum of 1073741824 (01000000000000000000000000000000) and - maximum of 2147483647 (01111111111111111111111111111111) - and for negative values on the interval with - minimum of -2147483648 (-10000000000000000000000000000000) and - maximum of -1073741824 ( -1000000000000000000000000000000). - - In order to normalize the result, the following - operation must be done: norm_var1 = x << gsm0610_norm(x); - - (That's 'ffs', only from the left, not the right..) -*/ - -int16_t gsm0610_norm(int32_t x) -{ - assert(x != 0); - - if (x < 0) - { - if (x <= -1073741824) - return 0; - /*endif*/ - x = ~x; - } - /*endif*/ - return (int16_t) (30 - top_bit(x)); -} -/*- End of function --------------------------------------------------------*/ - -/* - (From p. 46, end of section 4.2.5) - - NOTE: The following lines gives [sic] one correct implementation - of the div(num, denum) arithmetic operation. Compute div - which is the integer division of num by denom: with - denom >= num > 0 -*/ -static int16_t gsm_div(int16_t num, int16_t denom) -{ - int32_t num32; - int32_t denom32; - int16_t div; - int k; - - /* The parameter num sometimes becomes zero. - Although this is explicitly guarded against in 4.2.5, - we assume that the result should then be zero as well. */ - - assert(num >= 0 && denom >= num); - if (num == 0) - return 0; - /*endif*/ - num32 = num; - denom32 = denom; - div = 0; - k = 15; - while (k--) - { - div <<= 1; - num32 <<= 1; - - if (num32 >= denom32) - { - num32 -= denom32; - div++; - } - /*endif*/ - } - /*endwhile*/ - - return div; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) -static void gsm0610_vec_vsraw(const int16_t *p, int n, int bits) -{ - static const int64_t ones = 0x0001000100010001LL; - - if (n == 0) - return; - /*endif*/ -#if defined(__x86_64__) - __asm__ __volatile__( - " leaq -16(%%rsi,%%rax,2),%%rdx;\n" /* edx = top - 16 */ - " emms;\n" - " movd %%ecx,%%mm3;\n" - " movq %[ones],%%mm2;\n" - " psllw %%mm3,%%mm2;\n" - " psrlw $1,%%mm2;\n" - " cmpq %%rdx,%%rsi;" - " ja 4f;\n" - - " .p2align 2;\n" - /* 8 words per iteration */ - "6:\n" - " movq (%%rsi),%%mm0;\n" - " movq 8(%%rsi),%%mm1;\n" - " paddsw %%mm2,%%mm0;\n" - " psraw %%mm3,%%mm0;\n" - " paddsw %%mm2,%%mm1;\n" - " psraw %%mm3,%%mm1;\n" - " movq %%mm0,(%%rsi);\n" - " movq %%mm1,8(%%rsi);\n" - " addq $16,%%rsi;\n" - " cmpq %%rdx,%%rsi;\n" - " jbe 6b;\n" - - " .p2align 2;\n" - "4:\n" - " addq $12,%%rdx;\n" /* now edx = top-4 */ - " cmpq %%rdx,%%rsi;\n" - " ja 3f;\n" - - " .p2align 2;\n" - /* do up to 6 words, two per iteration */ - "5:\n" - " movd (%%rsi),%%mm0;\n" - " paddsw %%mm2,%%mm0;\n" - " psraw %%mm3,%%mm0;\n" - " movd %%mm0,(%%rsi);\n" - " addq $4,%%rsi;\n" - " cmpq %%rdx,%%rsi;\n" - " jbe 5b;\n" - - " .p2align 2;\n" - "3:\n" - " addq $2,%%rdx;\n" /* now edx = top-2 */ - " cmpq %%rdx,%%rsi;\n" - " ja 2f;\n" - - " movzwl (%%rsi),%%eax;\n" - " movd %%eax,%%mm0;\n" - " paddsw %%mm2,%%mm0;\n" - " psraw %%mm3,%%mm0;\n" - " movd %%mm0,%%eax;\n" - " movw %%ax,(%%rsi);\n" - - " .p2align 2;\n" - "2:\n" - " emms;\n" - : - : "S" (p), "a" (n), "c" (bits), [ones] "m" (ones) - : "edx" - ); -#else - __asm__ __volatile__( - " leal -16(%%esi,%%eax,2),%%edx;\n" /* edx = top - 16 */ - " emms;\n" - " movd %%ecx,%%mm3;\n" - " movq %[ones],%%mm2;\n" - " psllw %%mm3,%%mm2;\n" - " psrlw $1,%%mm2;\n" - " cmpl %%edx,%%esi;" - " ja 4f;\n" - - " .p2align 2;\n" - /* 8 words per iteration */ - "6:\n" - " movq (%%esi),%%mm0;\n" - " movq 8(%%esi),%%mm1;\n" - " paddsw %%mm2,%%mm0;\n" - " psraw %%mm3,%%mm0;\n" - " paddsw %%mm2,%%mm1;\n" - " psraw %%mm3,%%mm1;\n" - " movq %%mm0,(%%esi);\n" - " movq %%mm1,8(%%esi);\n" - " addl $16,%%esi;\n" - " cmpl %%edx,%%esi;\n" - " jbe 6b;\n" - - " .p2align 2;\n" - "4:\n" - " addl $12,%%edx;\n" /* now edx = top-4 */ - " cmpl %%edx,%%esi;\n" - " ja 3f;\n" - - " .p2align 2;\n" - /* do up to 6 words, two per iteration */ - "5:\n" - " movd (%%esi),%%mm0;\n" - " paddsw %%mm2,%%mm0;\n" - " psraw %%mm3,%%mm0;\n" - " movd %%mm0,(%%esi);\n" - " addl $4,%%esi;\n" - " cmpl %%edx,%%esi;\n" - " jbe 5b;\n" - - " .p2align 2;\n" - "3:\n" - " addl $2,%%edx;\n" /* now edx = top-2 */ - " cmpl %%edx,%%esi;\n" - " ja 2f;\n" - - " movzwl (%%esi),%%eax;\n" - " movd %%eax,%%mm0;\n" - " paddsw %%mm2,%%mm0;\n" - " psraw %%mm3,%%mm0;\n" - " movd %%mm0,%%eax;\n" - " movw %%ax,(%%esi);\n" - - " .p2align 2;\n" - "2:\n" - " emms;\n" - : - : "S" (p), "a" (n), "c" (bits), [ones] "m" (ones) - : "edx" - ); -#endif -} -/*- End of function --------------------------------------------------------*/ -#endif - -/* 4.2.4 */ -static void autocorrelation(int16_t amp[GSM0610_FRAME_LEN], int32_t L_ACF[9]) -{ - int k; - int16_t smax; - int16_t scalauto; -#if !(defined(__GNUC__) && defined(SPANDSP_USE_MMX)) - int i; - int temp; - int16_t *sp; - int16_t sl; -#endif - - /* The goal is to compute the array L_ACF[k]. The signal s[i] must - be scaled in order to avoid an overflow situation. */ - - /* Dynamic scaling of the array s[0..159] */ - /* Search for the maximum. */ -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) - smax = saturate16(vec_min_maxi16(amp, GSM0610_FRAME_LEN, NULL)); -#else - for (smax = 0, k = 0; k < GSM0610_FRAME_LEN; k++) - { - temp = sat_abs16(amp[k]); - if (temp > smax) - smax = (int16_t) temp; - /*endif*/ - } - /*endfor*/ -#endif - - /* Computation of the scaling factor. */ - if (smax == 0) - { - scalauto = 0; - } - else - { - assert(smax > 0); - scalauto = (int16_t) (4 - gsm0610_norm((int32_t) smax << 16)); - } - /*endif*/ - - /* Scaling of the array s[0...159] */ -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) - if (scalauto > 0) - gsm0610_vec_vsraw(amp, GSM0610_FRAME_LEN, scalauto); - /*endif*/ -#else - if (scalauto > 0) - { - for (k = 0; k < GSM0610_FRAME_LEN; k++) - amp[k] = gsm_mult_r(amp[k], 16384 >> (scalauto - 1)); - /*endfor*/ - } - /*endif*/ -#endif - - /* Compute the L_ACF[..]. */ -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) - for (k = 0; k < 9; k++) - L_ACF[k] = vec_dot_prodi16(amp, amp + k, GSM0610_FRAME_LEN - k) << 1; - /*endfor*/ -#else - sp = amp; - sl = *sp; - L_ACF[0] = ((int32_t) sl*(int32_t) sp[0]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] = ((int32_t) sl*(int32_t) sp[-1]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] = ((int32_t) sl*(int32_t) sp[-2]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] = ((int32_t) sl*(int32_t) sp[-3]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] += ((int32_t) sl*(int32_t) sp[-3]); - L_ACF[4] = ((int32_t) sl*(int32_t) sp[-4]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] += ((int32_t) sl*(int32_t) sp[-3]); - L_ACF[4] += ((int32_t) sl*(int32_t) sp[-4]); - L_ACF[5] = ((int32_t) sl*(int32_t) sp[-5]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] += ((int32_t) sl*(int32_t) sp[-3]); - L_ACF[4] += ((int32_t) sl*(int32_t) sp[-4]); - L_ACF[5] += ((int32_t) sl*(int32_t) sp[-5]); - L_ACF[6] = ((int32_t) sl*(int32_t) sp[-6]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] += ((int32_t) sl*(int32_t) sp[-3]); - L_ACF[4] += ((int32_t) sl*(int32_t) sp[-4]); - L_ACF[5] += ((int32_t) sl*(int32_t) sp[-5]); - L_ACF[6] += ((int32_t) sl*(int32_t) sp[-6]); - L_ACF[7] = ((int32_t) sl*(int32_t) sp[-7]); - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] += ((int32_t) sl*(int32_t) sp[-3]); - L_ACF[4] += ((int32_t) sl*(int32_t) sp[-4]); - L_ACF[5] += ((int32_t) sl*(int32_t) sp[-5]); - L_ACF[6] += ((int32_t) sl*(int32_t) sp[-6]); - L_ACF[7] += ((int32_t) sl*(int32_t) sp[-7]); - L_ACF[8] = ((int32_t) sl*(int32_t) sp[-8]); - for (i = 9; i < GSM0610_FRAME_LEN; i++) - { - sl = *++sp; - L_ACF[0] += ((int32_t) sl*(int32_t) sp[0]); - L_ACF[1] += ((int32_t) sl*(int32_t) sp[-1]); - L_ACF[2] += ((int32_t) sl*(int32_t) sp[-2]); - L_ACF[3] += ((int32_t) sl*(int32_t) sp[-3]); - L_ACF[4] += ((int32_t) sl*(int32_t) sp[-4]); - L_ACF[5] += ((int32_t) sl*(int32_t) sp[-5]); - L_ACF[6] += ((int32_t) sl*(int32_t) sp[-6]); - L_ACF[7] += ((int32_t) sl*(int32_t) sp[-7]); - L_ACF[8] += ((int32_t) sl*(int32_t) sp[-8]); - } - /*endfor*/ - for (k = 0; k < 9; k++) - L_ACF[k] <<= 1; - /*endfor*/ -#endif - /* Rescaling of the array s[0..159] */ - if (scalauto > 0) - { - assert(scalauto <= 4); - for (k = 0; k < GSM0610_FRAME_LEN; k++) - amp[k] <<= scalauto; - /*endfor*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.5 */ -static void reflection_coefficients(int32_t L_ACF[9], int16_t r[8]) -{ - int i; - int m; - int n; - int16_t temp; - int16_t ACF[9]; - int16_t P[9]; - int16_t K[9]; - - /* Schur recursion with 16 bits arithmetic. */ - if (L_ACF[0] == 0) - { - for (i = 8; i--; *r++ = 0) - ; - /*endfor*/ - return; - } - /*endif*/ - - assert(L_ACF[0] != 0); - temp = gsm0610_norm(L_ACF[0]); - - assert(temp >= 0 && temp < 32); - - /* ? overflow ? */ - for (i = 0; i <= 8; i++) - ACF[i] = (int16_t) ((L_ACF[i] << temp) >> 16); - /*endfor*/ - - /* Initialize array P[..] and K[..] for the recursion. */ - for (i = 1; i <= 7; i++) - K[i] = ACF[i]; - /*endfor*/ - for (i = 0; i <= 8; i++) - P[i] = ACF[i]; - /*endfor*/ - /* Compute reflection coefficients */ - for (n = 1; n <= 8; n++, r++) - { - temp = P[1]; - temp = sat_abs16(temp); - if (P[0] < temp) - { - for (i = n; i <= 8; i++) - *r++ = 0; - /*endfor*/ - return; - } - /*endif*/ - - *r = gsm_div(temp, P[0]); - - assert(*r >= 0); - if (P[1] > 0) - *r = -*r; /* r[n] = sub(0, r[n]) */ - /*endif*/ - assert(*r != INT16_MIN); - if (n == 8) - return; - /*endif*/ - - /* Schur recursion */ - temp = gsm_mult_r(P[1], *r); - P[0] = sat_add16(P[0], temp); - - for (m = 1; m <= 8 - n; m++) - { - temp = gsm_mult_r(K[m], *r); - P[m] = sat_add16(P[m + 1], temp); - - temp = gsm_mult_r(P[m + 1], *r); - K[m] = sat_add16(K[m], temp); - } - /*endfor*/ - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.6 */ -static void transform_to_log_area_ratios(int16_t r[8]) -{ - int16_t temp; - int i; - - /* The following scaling for r[..] and LAR[..] has been used: - - r[..] = integer (real_r[..]*32768.); -1 <= real_r < 1. - LAR[..] = integer (real_LAR[..] * 16384); - with -1.625 <= real_LAR <= 1.625 - */ - - /* Computation of the LAR[0..7] from the r[0..7] */ - for (i = 1; i <= 8; i++, r++) - { - temp = sat_abs16(*r); - assert(temp >= 0); - - if (temp < 22118) - { - temp >>= 1; - } - else if (temp < 31130) - { - assert(temp >= 11059); - temp -= 11059; - } - else - { - assert(temp >= 26112); - temp -= 26112; - temp <<= 2; - } - /*endif*/ - - *r = (*r < 0) ? -temp : temp; - assert(*r != INT16_MIN); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.7 */ -static void quantization_and_coding(int16_t LAR[8]) -{ - int16_t temp; - - /* This procedure needs four tables; the following equations - give the optimum scaling for the constants: - - A[0..7] = integer(real_A[0..7] * 1024) - B[0..7] = integer(real_B[0..7] * 512) - MAC[0..7] = maximum of the LARc[0..7] - MIC[0..7] = minimum of the LARc[0..7] */ - -#undef STEP -#define STEP(A,B,MAC,MIC) \ - temp = sat_mul16(A, *LAR); \ - temp = sat_add16(temp, (B + 256)); \ - temp >>= 9; \ - *LAR = (int16_t) ((temp > MAC) \ - ? \ - MAC - MIC \ - : \ - ((temp < MIC) ? 0 : temp - MIC)); \ - LAR++; - - STEP(20480, 0, 31, -32); - STEP(20480, 0, 31, -32); - STEP(20480, 2048, 15, -16); - STEP(20480, -2560, 15, -16); - - STEP(13964, 94, 7, -8); - STEP(15360, -1792, 7, -8); - STEP( 8534, -341, 3, -4); - STEP( 9036, -1144, 3, -4); -#undef STEP -} -/*- End of function --------------------------------------------------------*/ - -void gsm0610_lpc_analysis(gsm0610_state_t *s, - int16_t amp[GSM0610_FRAME_LEN], - int16_t LARc[8]) -{ - int32_t L_ACF[9]; - - autocorrelation(amp, L_ACF); - reflection_coefficients(L_ACF, LARc); - transform_to_log_area_ratios(LARc); - quantization_and_coding(LARc); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_preprocess.c b/libs/spandsp/src/gsm0610_preprocess.c deleted file mode 100644 index b4191b78c8..0000000000 --- a/libs/spandsp/src/gsm0610_preprocess.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_preprocess.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/saturated.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* - 4.2.0 .. 4.2.3 PREPROCESSING SECTION - - After A-law to linear conversion (or directly from the - A to D converter) the following scaling is assumed for - input to the RPE-LTP algorithm: - - in: 0.1.....................12 - S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.* - - Where S is the sign bit, v a valid bit, and * a "don't care" bit. - The original signal is called sop[..] - - out: 0.1................... 12 - S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0 -*/ - -void gsm0610_preprocess(gsm0610_state_t *s, const int16_t amp[GSM0610_FRAME_LEN], int16_t so[GSM0610_FRAME_LEN]) -{ - int16_t z1; - int16_t mp; - int16_t s1; - int16_t msp; - int16_t SO; - int32_t L_z2; - int32_t L_s2; - int32_t L_temp; -#if !defined(__GNUC__) - int16_t lsp; -#endif - int k; - - z1 = s->z1; - L_z2 = s->L_z2; - mp = s->mp; - for (k = 0; k < GSM0610_FRAME_LEN; k++) - { - /* 4.2.1 Downscaling of the input signal */ - SO = (amp[k] >> 1) & ~3; - - /* This is supposed to have been downscaled by previous routine. */ - assert(SO >= -0x4000); - assert(SO <= 0x3FFC); - - /* 4.2.2 Offset compensation */ - - /* This part implements a high-pass filter and requires extended - arithmetic precision for the recursive part of this filter. - The input of this procedure is the array so[0...159] and the - output the array sof[0...159]. - */ - /* Compute the non-recursive part */ - s1 = SO - z1; - z1 = SO; - - assert(s1 != INT16_MIN); - - /* Compute the recursive part */ - L_s2 = s1; - L_s2 <<= 15; - - /* Perform a 31 by 16 bits multiplication */ -#if defined(__GNUC__) - L_z2 = ((int64_t) L_z2*32735 + 0x4000) >> 15; - /* Alternate (ANSI) version of below line does slightly different rounding: - * L_temp = L_z2 >> 9; - * L_temp += L_temp >> 5; - * L_temp = (++L_temp) >> 1; - * L_z2 = L_z2 - L_temp; - */ - L_z2 = sat_add32(L_z2, L_s2); -#else - /* This does L_z2 = L_z2 * 0x7FD5/0x8000 + L_s2 */ - msp = (int16_t) (L_z2 >> 15); - lsp = (int16_t) (L_z2 - ((int32_t) msp << 15)); - - L_s2 += gsm_mult_r(lsp, 32735); - L_temp = (int32_t) msp*32735; - L_z2 = sat_add32(L_temp, L_s2); -#endif - - /* Compute sof[k] with rounding */ - L_temp = sat_add32(L_z2, 16384); - - /* 4.2.3 Preemphasis */ - msp = gsm_mult_r(mp, -28180); - mp = (int16_t) (L_temp >> 15); - so[k] = sat_add16(mp, msp); - } - /*endfor*/ - - s->z1 = z1; - s->L_z2 = L_z2; - s->mp = mp; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_rpe.c b/libs/spandsp/src/gsm0610_rpe.c deleted file mode 100644 index 3bd683b5d3..0000000000 --- a/libs/spandsp/src/gsm0610_rpe.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_rpe.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include - -#include "mmx_sse_decs.h" - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/saturated.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* 4.2.13 .. 4.2.17 RPE ENCODING SECTION */ - -/* 4.2.13 */ -static void weighting_filter(int16_t x[40], - const int16_t *e) // signal [-5..0.39.44] IN) -{ -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__x86_64__) && !defined(__OpenBSD__) - /* Table 4.4 Coefficients of the weighting filter */ - /* This must be padded to a multiple of 4 for MMX to work */ - static const union - { - int16_t gsm_H[12]; - __m64 x[3]; - } gsm_H = - { - { - -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134, 0 - } - - }; - - __asm__ __volatile__( - " emms;\n" - " addq $-10,%%rcx;\n" - " leaq %[gsm_H],%%rax;\n" - " movq (%%rax),%%mm1;\n" - " movq 8(%%rax),%%mm2;\n" - " movq 16(%%rax),%%mm3;\n" - " movq $0x1000,%%rax;\n" - " movq %%rax,%%mm5;\n" /* For rounding */ - " xorq %%rsi,%%rsi;\n" - " .p2align 2;\n" - "1:\n" - " movq (%%rcx,%%rsi,2),%%mm0;\n" - " pmaddwd %%mm1,%%mm0;\n" - - " movq 8(%%rcx,%%rsi,2),%%mm4;\n" - " pmaddwd %%mm2,%%mm4;\n" - " paddd %%mm4,%%mm0;\n" - - " movq 16(%%rcx,%%rsi,2),%%mm4;\n" - " pmaddwd %%mm3,%%mm4;\n" - " paddd %%mm4,%%mm0;\n" - - " movq %%mm0,%%mm4;\n" - " punpckhdq %%mm0,%%mm4;\n" /* mm4 has high int32 of mm0 dup'd */ - " paddd %%mm4,%%mm0;\n" - - " paddd %%mm5,%%mm0;\n" /* Add for roundoff */ - " psrad $13,%%mm0;\n" - " packssdw %%mm0,%%mm0;\n" - " movd %%mm0,%%eax;\n" /* eax has result */ - " movw %%ax,(%%rdi,%%rsi,2);\n" - " incq %%rsi;\n" - " cmpq $39,%%rsi;\n" - " jle 1b;\n" - " emms;\n" - : - : "c" (e), "D" (x), [gsm_H] "X" (gsm_H) - : "rax", "rdx", "rsi", "memory" - ); -#elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) - /* Table 4.4 Coefficients of the weighting filter */ - /* This must be padded to a multiple of 4 for MMX to work */ - static const union - { - int16_t gsm_H[12]; - __m64 x[3]; - } gsm_H = - { - { - -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134, 0 - } - - }; - - __asm__ __volatile__( - " emms;\n" - " addl $-10,%%ecx;\n" - " leal %[gsm_H],%%eax;\n" - " movq (%%eax),%%mm1;\n" - " movq 8(%%eax),%%mm2;\n" - " movq 16(%%eax),%%mm3;\n" - " movl $0x1000,%%eax;\n" - " movd %%eax,%%mm5;\n" /* For rounding */ - " xorl %%esi,%%esi;\n" - " .p2align 2;\n" - "1:\n" - " movq (%%ecx,%%esi,2),%%mm0;\n" - " pmaddwd %%mm1,%%mm0;\n" - - " movq 8(%%ecx,%%esi,2),%%mm4;\n" - " pmaddwd %%mm2,%%mm4;\n" - " paddd %%mm4,%%mm0;\n" - - " movq 16(%%ecx,%%esi,2),%%mm4;\n" - " pmaddwd %%mm3,%%mm4;\n" - " paddd %%mm4,%%mm0;\n" - - " movq %%mm0,%%mm4;\n" - " punpckhdq %%mm0,%%mm4;\n" /* mm4 has high int32 of mm0 dup'd */ - " paddd %%mm4,%%mm0;\n" - - " paddd %%mm5,%%mm0;\n" /* Add for roundoff */ - " psrad $13,%%mm0;\n" - " packssdw %%mm0,%%mm0;\n" - " movd %%mm0,%%eax;\n" /* eax has result */ - " movw %%ax,(%%edi,%%esi,2);\n" - " incl %%esi;\n" - " cmpl $39,%%esi;\n" - " jle 1b;\n" - " emms;\n" - : - : "c" (e), "D" (x), [gsm_H] "X" (gsm_H) - : "eax", "edx", "esi", "memory" - ); -#else - int32_t result; - int k; - - /* The coefficients of the weighting filter are stored in a table - (see table 4.4). The following scaling is used: - - H[0..10] = integer(real_H[0..10] * 8192); - */ - /* Initialization of a temporary working array wt[0...49] */ - - /* for (k = 0; k <= 4; k++) wt[k] = 0; - * for (k = 5; k <= 44; k++) wt[k] = *e++; - * for (k = 45; k <= 49; k++) wt[k] = 0; - * - * (e[-5..-1] and e[40..44] are allocated by the caller, - * are initially zero and are not written anywhere.) - */ - e -= 5; - - /* Compute the signal x[0..39] */ - for (k = 0; k < 40; k++) - { - result = 8192 >> 1; - - /* for (i = 0; i <= 10; i++) - * { - * temp = sat_mul16_32(wt[k + i], gsm_H[i]); - * result = sat_add32(result, temp); - * } - */ - -#undef STEP -#define STEP(i,H) (e[k + i] * (int32_t) H) - - /* Every one of these multiplications is done twice, - but I don't see an elegant way to optimize this. - Do you? - */ - result += STEP( 0, -134); - result += STEP( 1, -374); - /* += STEP( 2, 0 ); */ - result += STEP( 3, 2054); - result += STEP( 4, 5741); - result += STEP( 5, 8192); - result += STEP( 6, 5741); - result += STEP( 7, 2054); - /* += STEP( 8, 0 ); */ - result += STEP( 9, -374); - result += STEP(10, -134); - - /* 2 adds vs. >> 16 => 14, minus one shift to compensate for - those we lost when replacing L_MULT by '*'. */ - result >>= 13; - x[k] = saturate16(result); - } - /*endfor*/ -#endif -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.14 */ -static void rpe_grid_selection(int16_t x[40], int16_t xM[13], int16_t *Mc_out) -{ - int i; - int32_t L_result; - int32_t L_temp; - int32_t EM; /* xxx should be L_EM? */ - int16_t Mc; - int32_t L_common_0_3; - - /* The signal x[0..39] is used to select the RPE grid which is - represented by Mc. */ - Mc = 0; - -#undef STEP -#define STEP(m,i) \ - L_temp = x[m + 3*i] >> 2; \ - L_result += L_temp*L_temp; - - /* Common part of 0 and 3 */ - L_result = 0; - STEP(0, 1); - STEP(0, 2); - STEP(0, 3); - STEP(0, 4); - STEP(0, 5); - STEP(0, 6); - STEP(0, 7); - STEP(0, 8); - STEP(0, 9); - STEP(0, 10); - STEP(0, 11); - STEP(0, 12); - L_common_0_3 = L_result; - - /* i = 0 */ - - STEP(0, 0); - L_result <<= 1; /* implicit in L_MULT */ - EM = L_result; - - /* i = 1 */ - - L_result = 0; - STEP(1, 0); - STEP(1, 1); - STEP(1, 2); - STEP(1, 3); - STEP(1, 4); - STEP(1, 5); - STEP(1, 6); - STEP(1, 7); - STEP(1, 8); - STEP(1, 9); - STEP(1, 10); - STEP(1, 11); - STEP(1, 12); - L_result <<= 1; - if (L_result > EM) - { - Mc = 1; - EM = L_result; - } - /*endif*/ - - /* i = 2 */ - - L_result = 0; - STEP(2, 0); - STEP(2, 1); - STEP(2, 2); - STEP(2, 3); - STEP(2, 4); - STEP(2, 5); - STEP(2, 6); - STEP(2, 7); - STEP(2, 8); - STEP(2, 9); - STEP(2, 10); - STEP(2, 11); - STEP(2, 12); - L_result <<= 1; - if (L_result > EM) - { - Mc = 2; - EM = L_result; - } - /*endif*/ - - /* i = 3 */ - - L_result = L_common_0_3; - STEP(3, 12); - L_result <<= 1; - if (L_result > EM) - Mc = 3; - /*endif*/ - - /* Down-sampling by a factor 3 to get the selected xM[0..12] - RPE sequence. */ - for (i = 0; i < 13; i++) - xM[i] = x[Mc + 3*i]; - /*endfor*/ - *Mc_out = Mc; -} -/*- End of function --------------------------------------------------------*/ - -/* 4.12.15 */ -static void apcm_quantization_xmaxc_to_exp_mant(int16_t xmaxc, - int16_t *exp_out, - int16_t *mant_out) -{ - int16_t exp; - int16_t mant; - - /* Compute exponent and mantissa of the decoded version of xmaxc */ - exp = 0; - if (xmaxc > 15) - exp = (int16_t) ((xmaxc >> 3) - 1); - /*endif*/ - mant = xmaxc - (exp << 3); - - if (mant == 0) - { - exp = -4; - mant = 7; - } - else - { - while (mant <= 7) - { - mant = (int16_t) (mant << 1 | 1); - exp--; - } - /*endwhile*/ - mant -= 8; - } - /*endif*/ - - assert(exp >= -4 && exp <= 6); - assert(mant >= 0 && mant <= 7); - - *exp_out = exp; - *mant_out = mant; -} -/*- End of function --------------------------------------------------------*/ - -static void apcm_quantization(int16_t xM[13], - int16_t xMc[13], - int16_t *mant_out, - int16_t *exp_out, - int16_t *xmaxc_out) -{ - /* Table 4.5 Normalized inverse mantissa used to compute xM/xmax */ - static const int16_t gsm_NRFAC[8] = - { - 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 - }; - int i; - int itest; - int16_t xmax; - int16_t xmaxc; - int16_t temp; - int16_t temp1; - int16_t temp2; - int16_t exp; - int16_t mant; - - /* Find the maximum absolute value xmax of xM[0..12]. */ - xmax = 0; - for (i = 0; i < 13; i++) - { - temp = xM[i]; - temp = sat_abs16(temp); - if (temp > xmax) - xmax = temp; - /*endif*/ - } - /*endfor*/ - - /* Quantizing and coding of xmax to get xmaxc. */ - exp = 0; - temp = xmax >> 9; - itest = 0; - - for (i = 0; i <= 5; i++) - { - itest |= (temp <= 0); - temp >>= 1; - - assert(exp <= 5); - if (itest == 0) - exp++; - /*endif*/ - } - /*endfor*/ - - assert(exp <= 6 && exp >= 0); - temp = (int16_t) (exp + 5); - - assert(temp <= 11 && temp >= 0); - xmaxc = sat_add16((xmax >> temp), exp << 3); - - /* Quantizing and coding of the xM[0..12] RPE sequence - to get the xMc[0..12] */ - apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant); - - /* This computation uses the fact that the decoded version of xmaxc - can be calculated by using the exponent and the mantissa part of - xmaxc (logarithmic table). - So, this method avoids any division and uses only a scaling - of the RPE samples by a function of the exponent. A direct - multiplication by the inverse of the mantissa (NRFAC[0..7] - found in table 4.5) gives the 3 bit coded version xMc[0..12] - of the RPE samples. - */ - /* Direct computation of xMc[0..12] using table 4.5 */ - assert(exp <= 4096 && exp >= -4096); - assert(mant >= 0 && mant <= 7); - - temp1 = (int16_t) (6 - exp); /* Normalization by the exponent */ - temp2 = gsm_NRFAC[mant]; /* Inverse mantissa */ - - for (i = 0; i < 13; i++) - { - assert(temp1 >= 0 && temp1 < 16); - - temp = xM[i] << temp1; - temp = sat_mul16(temp, temp2); - temp >>= 12; - xMc[i] = (int16_t) (temp + 4); /* See note below */ - } - /*endfor*/ - - /* NOTE: This equation is used to make all the xMc[i] positive. */ - *mant_out = mant; - *exp_out = exp; - *xmaxc_out = xmaxc; -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.16 */ -static void apcm_inverse_quantization(int16_t xMc[13], - int16_t mant, - int16_t exp, - int16_t xMp[13]) -{ - /* Table 4.6 Normalized direct mantissa used to compute xM/xmax */ - static const int16_t gsm_fac[8] = - { - 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 - }; - int i; - int16_t temp; - int16_t temp1; - int16_t temp2; - int16_t temp3; - - /* This part is for decoding the RPE sequence of coded xMc[0..12] - samples to obtain the xMp[0..12] array. Table 4.6 is used to get - the mantissa of xmaxc (FAC[0..7]). - */ -#if 0 - assert(mant >= 0 && mant <= 7); -#endif - - temp1 = gsm_fac[mant]; /* See 4.2-15 for mant */ - temp2 = sat_sub16(6, exp); /* See 4.2-15 for exp */ - temp3 = gsm_asl(1, sat_sub16(temp2, 1)); - - for (i = 0; i < 13; i++) - { - assert(xMc[i] >= 0 && xMc[i] <= 7); /* 3 bit unsigned */ - - temp = (int16_t) ((xMc[i] << 1) - 7); /* Restore sign */ - assert(temp <= 7 && temp >= -7); /* 4 bit signed */ - - temp <<= 12; /* 16 bit signed */ - temp = gsm_mult_r(temp1, temp); - temp = sat_add16(temp, temp3); - xMp[i] = gsm_asr(temp, temp2); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.17 */ -static void rpe_grid_positioning(int16_t Mc, - int16_t xMp[13], - int16_t ep[40]) -{ - int i = 13; - - /* This procedure computes the reconstructed long term residual signal - ep[0..39] for the LTP analysis filter. The inputs are the Mc - which is the grid position selection and the xMp[0..12] decoded - RPE samples which are upsampled by a factor of 3 by inserting zero - values. - */ - assert(0 <= Mc && Mc <= 3); - - switch (Mc) - { - case 3: - *ep++ = 0; - case 2: - do - { - *ep++ = 0; - case 1: - *ep++ = 0; - case 0: - *ep++ = *xMp++; - } - while (--i); - } - /*endswitch*/ - while (++Mc < 4) - *ep++ = 0; - /*endwhile*/ -} -/*- End of function --------------------------------------------------------*/ - -void gsm0610_rpe_encoding(gsm0610_state_t *s, - int16_t *e, // [-5..-1][0..39][40..44] - int16_t *xmaxc, - int16_t *Mc, - int16_t xMc[13]) -{ - int16_t x[40] = {0}; - int16_t xM[13]; - int16_t xMp[13]; - int16_t mant; - int16_t exp; - - weighting_filter(x, e); - rpe_grid_selection(x, xM, Mc); - - apcm_quantization(xM, xMc, &mant, &exp, xmaxc); - apcm_inverse_quantization(xMc, mant, exp, xMp); - - rpe_grid_positioning(*Mc, xMp, e); -} -/*- End of function --------------------------------------------------------*/ - -void gsm0610_rpe_decoding(gsm0610_state_t *s, - int16_t xmaxc, - int16_t Mcr, - int16_t xMcr[13], - int16_t erp[40]) -{ - int16_t exp; - int16_t mant; - int16_t xMp[13]; - - apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant); - apcm_inverse_quantization(xMcr, mant, exp, xMp); - rpe_grid_positioning(Mcr, xMp, erp); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_short_term.c b/libs/spandsp/src/gsm0610_short_term.c deleted file mode 100644 index 62130fdf28..0000000000 --- a/libs/spandsp/src/gsm0610_short_term.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_short_term.c - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the widely used GSM 06.10 code available from - * http://kbs.cs.tu-berlin.de/~jutta/toast.html - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/bitstream.h" -#include "spandsp/saturated.h" -#include "spandsp/gsm0610.h" - -#include "gsm0610_local.h" - -/* SHORT TERM ANALYSIS FILTERING SECTION */ - -/* 4.2.8 */ -static void decode_log_area_ratios(int16_t LARc[8], int16_t *LARpp) -{ - int16_t temp1; - - /* This procedure requires for efficient implementation - two tables. - INVA[1..8] = integer((32768*8)/real_A[1..8]) - MIC[1..8] = minimum value of the LARc[1..8] - */ - - /* Compute the LARpp[1..8] */ - -#undef STEP -#define STEP(B,MIC,INVA) \ - temp1 = sat_add16(*LARc++, MIC) << 10; \ - temp1 = sat_sub16(temp1, B << 1); \ - temp1 = gsm_mult_r(INVA, temp1); \ - *LARpp++ = sat_add16(temp1, temp1); - - STEP( 0, -32, 13107); - STEP( 0, -32, 13107); - STEP( 2048, -16, 13107); - STEP(-2560, -16, 13107); - - STEP( 94, -8, 19223); - STEP(-1792, -8, 17476); - STEP( -341, -4, 31454); - STEP(-1144, -4, 29708); - - /* NOTE: the addition of *MIC is used to restore the sign of *LARc. */ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.9 */ - -/* Computation of the quantized reflection coefficients */ - -/* 4.2.9.1 Interpolation of the LARpp[1..8] to get the LARp[1..8] */ - -/* Within each frame of 160 analyzed speech samples the short term - analysis and synthesis filters operate with four different sets of - coefficients, derived from the previous set of decoded LARs(LARpp(j - 1)) - and the actual set of decoded LARs (LARpp(j)) - - (Initial value: LARpp(j - 1)[1..8] = 0.) -*/ - -static void coefficients_0_12(int16_t *LARpp_j_1, - int16_t *LARpp_j, - int16_t *LARp) -{ - int i; - - for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++) - { - *LARp = sat_add16(*LARpp_j_1 >> 2, *LARpp_j >> 2); - *LARp = sat_add16(*LARp, *LARpp_j_1 >> 1); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static void coefficients_13_26(int16_t *LARpp_j_1, - int16_t *LARpp_j, - int16_t *LARp) -{ - int i; - - for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) - *LARp = sat_add16(*LARpp_j_1 >> 1, *LARpp_j >> 1); - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static void coefficients_27_39(int16_t *LARpp_j_1, - int16_t *LARpp_j, - int16_t *LARp) -{ - int i; - - for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) - { - *LARp = sat_add16(*LARpp_j_1 >> 2, *LARpp_j >> 2); - *LARp = sat_add16(*LARp, *LARpp_j >> 1); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static void coefficients_40_159(int16_t *LARpp_j, int16_t *LARp) -{ - int i; - - for (i = 1; i <= 8; i++) - *LARp++ = *LARpp_j++; - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.9.2 */ -static void larp_to_rp(int16_t LARp[8]) -{ - int i; - int16_t *LARpx; - int16_t temp; - - /* The input to this procedure is the interpolated LARp[0..7] array. - The reflection coefficients, rp[i], are used in the analysis - filter and in the synthesis filter. - */ - - LARpx = LARp; - for (i = 1; i <= 8; i++, LARpx++) - { - temp = *LARpx; - if (temp < 0) - { - if (temp == INT16_MIN) - temp = INT16_MAX; - else - temp = -temp; - /*endif*/ - if (temp < 11059) - temp <<= 1; - else if (temp < 20070) - temp += 11059; - else - temp = sat_add16(temp >> 2, 26112); - /*endif*/ - *LARpx = -temp; - } - else - { - if (temp < 11059) - temp <<= 1; - else if (temp < 20070) - temp += 11059; - else - temp = sat_add16(temp >> 2, 26112); - /*endif*/ - *LARpx = temp; - } - /*endif*/ - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -/* 4.2.10 */ -static void short_term_analysis_filtering(gsm0610_state_t *s, - int16_t rp[8], - int k_n, // k_end - k_start - int16_t amp[]) // [0..n-1] IN/OUT -{ - /* This procedure computes the short term residual signal d[..] to be fed - to the RPE-LTP loop from the s[..] signal and from the local rp[..] - array (quantized reflection coefficients). As the call of this - procedure can be done in many ways (see the interpolation of the LAR - coefficient), it is assumed that the computation begins with index - k_start (for arrays d[..] and s[..]) and stops with index k_end - (k_start and k_end are defined in 4.2.9.1). This procedure also - needs to keep the array u[0..7] in memory for each call. - */ - int16_t *u0; - int16_t *u_top; - int i; - int16_t *u; - int16_t *rpx; - int32_t di; - int32_t u_out; - - u0 = s->u; - u_top = u0 + 8; - - for (i = 0; i < k_n; i++) - { - di = - u_out = amp[i]; - for (rpx = rp, u = u0; u < u_top; ) - { - int32_t ui; - int32_t rpi; - - ui = *u; - *u++ = (int16_t) u_out; - rpi = *rpx++; - u_out = ui + (((rpi*di) + 0x4000) >> 15); - di = di + (((rpi*ui) + 0x4000) >> 15); - u_out = saturate16(u_out); - di = saturate16(di); - } - /*endfor*/ - amp[i] = (int16_t) di; - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static void short_term_synthesis_filtering(gsm0610_state_t *s, - int16_t rrp[8], - int k, // k_end - k_start - int16_t *wt, // [0..k - 1] - int16_t *sr) // [0..k - 1] -{ - int16_t *v; - int i; - int16_t sri; - int16_t tmp1; - int16_t tmp2; - - v = s->v; - while (k--) - { - sri = *wt++; - for (i = 8; i--; ) - { - tmp1 = rrp[i]; - tmp2 = v[i]; - tmp2 = ((tmp1 == INT16_MIN && tmp2 == INT16_MIN) - ? - INT16_MAX - : - (int16_t) (((int32_t) tmp1*(int32_t) tmp2 + 16384) >> 15) & 0xFFFF); - - sri = sat_sub16(sri, tmp2); - - tmp1 = ((tmp1 == INT16_MIN && sri == INT16_MIN) - ? - INT16_MAX - : - (int16_t) (((int32_t) tmp1*(int32_t) sri + 16384) >> 15) & 0xFFFF); - - v[i + 1] = sat_add16(v[i], tmp1); - } - /*endfor*/ - *sr++ = - v[0] = sri; - } - /*endwhile*/ -} -/*- End of function --------------------------------------------------------*/ - -void gsm0610_short_term_analysis_filter(gsm0610_state_t *s, - int16_t LARc[8], - int16_t amp[GSM0610_FRAME_LEN]) -{ - int16_t *LARpp_j; - int16_t *LARpp_j_1; - int16_t LARp[8]; - - LARpp_j = s->LARpp[s->j]; - LARpp_j_1 = s->LARpp[s->j ^= 1]; - - decode_log_area_ratios(LARc, LARpp_j); - - coefficients_0_12(LARpp_j_1, LARpp_j, LARp); - larp_to_rp(LARp); - short_term_analysis_filtering(s, LARp, 13, amp); - - coefficients_13_26(LARpp_j_1, LARpp_j, LARp); - larp_to_rp(LARp); - short_term_analysis_filtering(s, LARp, 14, amp + 13); - - coefficients_27_39(LARpp_j_1, LARpp_j, LARp); - larp_to_rp(LARp); - short_term_analysis_filtering(s, LARp, 13, amp + 27); - - coefficients_40_159(LARpp_j, LARp); - larp_to_rp(LARp); - short_term_analysis_filtering(s, LARp, 120, amp + 40); -} -/*- End of function --------------------------------------------------------*/ - -void gsm0610_short_term_synthesis_filter(gsm0610_state_t *s, - int16_t LARcr[8], - int16_t wt[GSM0610_FRAME_LEN], - int16_t amp[GSM0610_FRAME_LEN]) -{ - int16_t *LARpp_j; - int16_t *LARpp_j_1; - int16_t LARp[8]; - - LARpp_j = s->LARpp[s->j]; - LARpp_j_1 = s->LARpp[s->j ^= 1]; - - decode_log_area_ratios(LARcr, LARpp_j); - - coefficients_0_12(LARpp_j_1, LARpp_j, LARp); - larp_to_rp(LARp); - short_term_synthesis_filtering(s, LARp, 13, wt, amp); - - coefficients_13_26(LARpp_j_1, LARpp_j, LARp); - larp_to_rp(LARp); - short_term_synthesis_filtering(s, LARp, 14, wt + 13, amp + 13); - - coefficients_27_39(LARpp_j_1, LARpp_j, LARp); - larp_to_rp(LARp); - short_term_synthesis_filtering(s, LARp, 13, wt + 27, amp + 27); - - coefficients_40_159(LARpp_j, LARp); - larp_to_rp(LARp); - short_term_synthesis_filtering(s, LARp, 120, wt + 40, amp + 40); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c deleted file mode 100644 index feefa5ad7d..0000000000 --- a/libs/spandsp/src/hdlc.c +++ /dev/null @@ -1,752 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * hdlc.c - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#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" -#include "spandsp/hdlc.h" -#include "spandsp/private/hdlc.h" - -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); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void rx_special_condition(hdlc_rx_state_t *s, int status) -{ - /* Special conditions */ - switch (status) - { - case SIG_STATUS_CARRIER_UP: - case SIG_STATUS_TRAINING_SUCCEEDED: - /* Reset the HDLC receiver. */ - s->raw_bit_stream = 0; - s->len = 0; - s->num_bits = 0; - s->flags_seen = 0; - s->framing_ok_announced = false; - /* Fall through */ - case SIG_STATUS_TRAINING_IN_PROGRESS: - case SIG_STATUS_TRAINING_FAILED: - case SIG_STATUS_CARRIER_DOWN: - case SIG_STATUS_END_OF_DATA: - report_status_change(s, status); - break; - default: - //printf("Eh!\n"); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void octet_set_and_count(hdlc_rx_state_t *s) -{ - if (s->octet_count_report_interval == 0) - return; - /*endif*/ - - /* If we are not in octet counting mode, we start it. - If we are in octet counting mode, we update it. */ - if (s->octet_counting_mode) - { - if (--s->octet_count <= 0) - { - s->octet_count = s->octet_count_report_interval; - report_status_change(s, SIG_STATUS_OCTET_REPORT); - } - /*endif*/ - } - else - { - s->octet_counting_mode = true; - s->octet_count = s->octet_count_report_interval; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void octet_count(hdlc_rx_state_t *s) -{ - if (s->octet_count_report_interval == 0) - return; - /*endif*/ - - /* If we are not in octet counting mode, we start it. - If we are in octet counting mode, we update it. */ - if (s->octet_counting_mode) - { - if (--s->octet_count <= 0) - { - s->octet_count = s->octet_count_report_interval; - report_status_change(s, SIG_STATUS_OCTET_REPORT); - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void rx_flag_or_abort(hdlc_rx_state_t *s) -{ - if ((s->raw_bit_stream & 0x0100)) - { - /* Hit HDLC abort */ - s->rx_aborts++; - report_status_change(s, SIG_STATUS_ABORT); - /* If we have not yet seen enough flags, restart the count. If we - are beyond that point, just back off one step, so we need to see - another flag before proceeding to collect frame octets. */ - if (s->flags_seen < s->framing_ok_threshold - 1) - s->flags_seen = 0; - else - s->flags_seen = s->framing_ok_threshold - 1; - /*endif*/ - /* An abort starts octet counting */ - octet_set_and_count(s); - } - else - { - /* Hit HDLC flag */ - /* A flag clears octet counting */ - 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 */ - if (s->len) - { - if (s->num_bits == 7 && s->len >= (size_t) s->crc_bytes && s->len <= s->max_frame_len) - { - if ((s->crc_bytes == 2 && crc_itu16_check(s->buffer, s->len)) - || - (s->crc_bytes != 2 && crc_itu32_check(s->buffer, s->len))) - { - s->rx_frames++; - 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); - } - else - { - s->rx_crc_errors++; - if (s->report_bad_frames) - { - s->len -= s->crc_bytes; - if (s->frame_handler) - s->frame_handler(s->frame_user_data, s->buffer, s->len, false); - /*endif*/ - } - /*endif*/ - } - /*endif*/ - } - else - { - /* Frame too short or too long, or the flag is misaligned with its octets. */ - if (s->report_bad_frames) - { - /* Don't let the length go below zero, or it will be confused - with one of the special conditions. */ - if (s->len >= (size_t) s->crc_bytes) - s->len -= s->crc_bytes; - else - s->len = 0; - /*endif*/ - if (s->frame_handler) - s->frame_handler(s->frame_user_data, s->buffer, s->len, false); - /*endif*/ - } - /*endif*/ - s->rx_length_errors++; - } - /*endif*/ - } - /*endif*/ - } - else - { - /* Check the flags are back-to-back when testing for valid preamble. This - greatly reduces the chances of false preamble detection, and anything - which doesn't send them back-to-back is badly broken. When we are one - flag away from OK we should not apply the back-to-back consition, as - between an abort and the following start of frame things might not be - octet aligned. */ - if (s->flags_seen != s->framing_ok_threshold - 1 && s->num_bits != 7) - { - /* Don't set the flags seen indicator back to zero too aggressively. - We want to pick up with the minimum of discarded data when there - is a bit error in the stream, and a bit error could emulate a - misaligned flag. */ - if (s->flags_seen < s->framing_ok_threshold - 1) - s->flags_seen = 0; - else - s->flags_seen = s->framing_ok_threshold - 1; - /*endif*/ - } - /*endif*/ - 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; - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ - s->len = 0; - s->num_bits = 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void hdlc_rx_put_bit_core(hdlc_rx_state_t *s) -{ - if ((s->raw_bit_stream & 0x3E00) == 0x3E00) - { - /* There are at least 5 ones in a row. We could be at a: - - point where stuffing occurs - - a flag - - an abort - - the result of bit errors */ - /* Is this a bit to be skipped for destuffing? */ - if ((s->raw_bit_stream & 0x4100) == 0) - return; - /*endif*/ - /* Is this a flag or abort? */ - if ((s->raw_bit_stream & 0xFE00) == 0x7E00) - { - rx_flag_or_abort(s); - return; - } - /*endif*/ - } - /*endif*/ - s->num_bits++; - if (s->flags_seen < s->framing_ok_threshold) - { - if ((s->num_bits & 0x7) == 0) - octet_count(s); - /*endif*/ - return; - } - /*endif*/ - s->byte_in_progress = (s->byte_in_progress | (s->raw_bit_stream & 0x100)) >> 1; - if (s->num_bits == 8) - { - /* Ensure we do not accept an overlength frame, and especially that - we do not overflow our buffer */ - if (s->len < s->max_frame_len) - { - s->buffer[s->len++] = (uint8_t) s->byte_in_progress; - } - else - { - /* This is too long. Abandon the frame, and wait for the next - flag octet. */ - s->len = sizeof(s->buffer) + 1; - s->flags_seen = s->framing_ok_threshold - 1; - octet_set_and_count(s); - } - /*endif*/ - s->num_bits = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit) -{ - if (new_bit < 0) - { - rx_special_condition(s, new_bit); - return; - } - /*endif*/ - s->raw_bit_stream = (s->raw_bit_stream << 1) | ((new_bit << 8) & 0x100); - hdlc_rx_put_bit_core(s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte) -{ - int i; - - if (new_byte < 0) - { - rx_special_condition(s, new_byte); - return; - } - /*endif*/ - s->raw_bit_stream |= new_byte; - for (i = 0; i < 8; i++) - { - s->raw_bit_stream <<= 1; - hdlc_rx_put_bit_core(s); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len) -{ - int i; - - for (i = 0; i < len; i++) - hdlc_rx_put_byte(s, buf[i]); - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_set_max_frame_len(hdlc_rx_state_t *s, size_t max_len) -{ - max_len += s->crc_bytes; - s->max_frame_len = (max_len <= sizeof(s->buffer)) ? max_len : sizeof(s->buffer); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s, int interval) -{ - s->octet_count_report_interval = interval; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_rx_restart(hdlc_rx_state_t *s) -{ - s->framing_ok_announced = false; - s->flags_seen = 0; - s->raw_bit_stream = 0; - s->byte_in_progress = 0; - s->num_bits = 0; - s->octet_counting_mode = false; - s->octet_count = 0; - s->len = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s, - bool crc32, - bool report_bad_frames, - int framing_ok_threshold, - hdlc_frame_handler_t handler, - void *user_data) -{ - if (s == NULL) - { - if ((s = (hdlc_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - s->frame_handler = handler; - s->frame_user_data = user_data; - s->crc_bytes = (crc32) ? 4 : 2; - s->report_bad_frames = report_bad_frames; - s->framing_ok_threshold = (framing_ok_threshold < 1) ? 1 : framing_ok_threshold; - s->max_frame_len = sizeof(s->buffer); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_handler_t handler, void *user_data) -{ - s->frame_handler = handler; - s->frame_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_rx_release(hdlc_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_rx_free(hdlc_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s, - hdlc_rx_stats_t *t) -{ - t->bytes = s->rx_bytes; - t->good_frames = s->rx_frames; - t->crc_errors = s->rx_crc_errors; - t->length_errors = s->rx_length_errors; - t->aborts = s->rx_aborts; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t len) -{ - if (len == 0) - { - s->tx_end = true; - return 0; - } - /*endif*/ - if (s->len + len > s->max_frame_len) - return -1; - /*endif*/ - if (s->progressive) - { - /* Only lock out if we are in the CRC section. */ - if (s->pos >= HDLC_MAXFRAME_LEN) - return -1; - /*endif*/ - } - else - { - /* Lock out if there is anything in the buffer. */ - if (s->len) - return -1; - /*endif*/ - } - /*endif*/ - memcpy(&s->buffer[s->len], frame, len); - if (s->crc_bytes == 2) - s->crc = crc_itu16_calc(frame, len, (uint16_t) s->crc); - else - s->crc = crc_itu32_calc(frame, len, s->crc); - /*endif*/ - if (s->progressive) - s->len += len; - else - s->len = len; - /*endif*/ - s->tx_end = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_flags(hdlc_tx_state_t *s, int len) -{ - /* Some HDLC applications require the ability to force a period of HDLC - flag words. */ - if (s->pos) - return -1; - /*endif*/ - if (len < 0) - s->flag_octets += -len; - else - s->flag_octets = len; - /*endif*/ - s->report_flag_underflow = true; - s->tx_end = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_abort(hdlc_tx_state_t *s) -{ - /* TODO: This is a really crude way of just fudging an abort out for simple - test purposes. */ - s->flag_octets++; - s->abort_octets++; - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_corrupt_frame(hdlc_tx_state_t *s) -{ - if (s->len <= 0) - return -1; - /*endif*/ - s->crc ^= 0xFFFF; - s->buffer[HDLC_MAXFRAME_LEN] ^= 0xFF; - s->buffer[HDLC_MAXFRAME_LEN + 1] ^= 0xFF; - s->buffer[HDLC_MAXFRAME_LEN + 2] ^= 0xFF; - s->buffer[HDLC_MAXFRAME_LEN + 3] ^= 0xFF; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_get_byte(hdlc_tx_state_t *s) -{ - int i; - int byte_in_progress; - int txbyte; - - if (s->flag_octets > 0) - { - /* 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; - if (s->len == 0) - { - /* The timed flags have finished, there is nothing else queued to go, - and we have been told to report this underflow. */ - if (s->underflow_handler) - s->underflow_handler(s->user_data); - /*endif*/ - } - /*endif*/ - } - /*endif*/ - if (s->abort_octets) - { - s->abort_octets = 0; - return 0x7F; - } - /*endif*/ - return s->idle_octet; - } - /*endif*/ - if (s->len) - { - if (s->num_bits >= 8) - { - s->num_bits -= 8; - return (s->octets_in_progress >> s->num_bits) & 0xFF; - } - /*endif*/ - if (s->pos >= s->len) - { - if (s->pos == s->len) - { - s->crc ^= 0xFFFFFFFF; - s->buffer[HDLC_MAXFRAME_LEN] = (uint8_t) s->crc; - s->buffer[HDLC_MAXFRAME_LEN + 1] = (uint8_t) (s->crc >> 8); - if (s->crc_bytes == 4) - { - s->buffer[HDLC_MAXFRAME_LEN + 2] = (uint8_t) (s->crc >> 16); - s->buffer[HDLC_MAXFRAME_LEN + 3] = (uint8_t) (s->crc >> 24); - } - /*endif*/ - s->pos = HDLC_MAXFRAME_LEN; - } - else if (s->pos == (size_t) (HDLC_MAXFRAME_LEN + s->crc_bytes)) - { - /* Finish off the current byte with some flag bits. If we are at the - start of a byte we need a at least one whole byte of flag to ensure - we cannot end up with back to back frames, and no flag octet at all */ - txbyte = (uint8_t) ((s->octets_in_progress << (8 - s->num_bits)) | (0x7E >> s->num_bits)); - /* Create a rotated octet of flag for idling... */ - s->idle_octet = (0x7E7E >> s->num_bits) & 0xFF; - /* ...and the partial flag octet needed to start off the next message. */ - s->octets_in_progress = s->idle_octet >> (8 - s->num_bits); - s->flag_octets = s->inter_frame_flags - 1; - s->len = 0; - s->pos = 0; - if (s->crc_bytes == 2) - s->crc = 0xFFFF; - else - s->crc = 0xFFFFFFFF; - /*endif*/ - /* 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; - 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 - in a new frame being sent. */ - if (s->len == 0 && s->flag_octets < 2) - s->flag_octets = 2; - /*endif*/ - return txbyte; - } - /*endif*/ - } - /*endif*/ - byte_in_progress = s->buffer[s->pos++]; - i = bottom_bit(byte_in_progress | 0x100); - s->octets_in_progress <<= i; - byte_in_progress >>= i; - for ( ; i < 8; i++) - { - s->octets_in_progress = (s->octets_in_progress << 1) | (byte_in_progress & 0x01); - byte_in_progress >>= 1; - if ((s->octets_in_progress & 0x1F) == 0x1F) - { - /* There are 5 ones - stuff */ - s->octets_in_progress <<= 1; - s->num_bits++; - } - /*endif*/ - } - /*endfor*/ - /* An input byte will generate between 8 and 10 output bits */ - return (s->octets_in_progress >> s->num_bits) & 0xFF; - } - /*endif*/ - /* Untimed idling on flags */ - if (s->tx_end) - { - s->tx_end = false; - return SIG_STATUS_END_OF_DATA; - } - /*endif*/ - return s->idle_octet; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_get_bit(hdlc_tx_state_t *s) -{ - int txbit; - - if (s->bits == 0) - { - if ((s->byte = hdlc_tx_get_byte(s)) < 0) - return s->byte; - /*endif*/ - s->bits = 8; - } - /*endif*/ - s->bits--; - txbit = (s->byte >> s->bits) & 0x01; - return txbit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len) -{ - size_t i; - int x; - - for (i = 0; i < max_len; i++) - { - if ((x = hdlc_tx_get_byte(s)) == SIG_STATUS_END_OF_DATA) - return i; - /*endif*/ - buf[i] = (uint8_t) x; - } - /*endfor*/ - return (int) i; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len) -{ - s->max_frame_len = (max_len <= HDLC_MAXFRAME_LEN) ? max_len : HDLC_MAXFRAME_LEN; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s) -{ - s->octets_in_progress = 0; - s->num_bits = 0; - s->idle_octet = 0x7E; - s->flag_octets = 0; - s->abort_octets = 0; - s->report_flag_underflow = false; - s->len = 0; - s->pos = 0; - if (s->crc_bytes == 2) - s->crc = 0xFFFF; - else - s->crc = 0xFFFFFFFF; - /*endif*/ - s->byte = 0; - s->bits = 0; - s->tx_end = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, - bool crc32, - int inter_frame_flags, - bool progressive, - hdlc_underflow_handler_t handler, - void *user_data) -{ - if (s == NULL) - { - if ((s = (hdlc_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - s->underflow_handler = handler; - s->user_data = user_data; - s->inter_frame_flags = (inter_frame_flags < 1) ? 1 : inter_frame_flags; - if (crc32) - { - s->crc_bytes = 4; - s->crc = 0xFFFFFFFF; - } - else - { - s->crc_bytes = 2; - s->crc = 0xFFFF; - } - /*endif*/ - s->idle_octet = 0x7E; - s->progressive = progressive; - s->max_frame_len = HDLC_MAXFRAME_LEN; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_release(hdlc_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) hdlc_tx_free(hdlc_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/ima_adpcm.c b/libs/spandsp/src/ima_adpcm.c deleted file mode 100644 index c974424cb4..0000000000 --- a/libs/spandsp/src/ima_adpcm.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * ima_adpcm.c - Conversion routines between linear 16 bit PCM data and - * IMA/DVI/Intel ADPCM format. - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 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(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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/saturated.h" -#include "spandsp/ima_adpcm.h" -#include "spandsp/private/ima_adpcm.h" - -/* - * Intel/DVI ADPCM coder/decoder. - * - * The algorithm for this coder was taken from the IMA Compatability Project - * proceedings, Vol 2, Number 2; May 1992. - * - * The RTP payload specs. reference a variant of DVI, called VDVI. This attempts to - * further compress, in a variable bit rate manner, by expressing the 4 bit codes - * from the DVI codec as: - * - * 0 00 - * 1 010 - * 2 1100 - * 3 11100 - * 4 111100 - * 5 1111100 - * 6 11111100 - * 7 11111110 - * 8 10 - * 9 011 - * 10 1101 - * 11 11101 - * 12 111101 - * 13 1111101 - * 14 11111101 - * 15 11111111 - * - * Any left over bits in the last octet of an encoded burst are set to one. - */ - -/* - DVI4 uses an adaptive delta pulse code modulation (ADPCM) encoding - scheme that was specified by the Interactive Multimedia Association - (IMA) as the "IMA ADPCM wave type". However, the encoding defined - here as DVI4 differs in three respects from the IMA specification: - - o The RTP DVI4 header contains the predicted value rather than the - first sample value contained the IMA ADPCM block header. - - o IMA ADPCM blocks contain an odd number of samples, since the first - sample of a block is contained just in the header (uncompressed), - followed by an even number of compressed samples. DVI4 has an - even number of compressed samples only, using the `predict' word - from the header to decode the first sample. - - o For DVI4, the 4-bit samples are packed with the first sample in - the four most significant bits and the second sample in the four - least significant bits. In the IMA ADPCM codec, the samples are - packed in the opposite order. - - Each packet contains a single DVI block. This profile only defines - the 4-bit-per-sample version, while IMA also specified a 3-bit-per- - sample encoding. - - The "header" word for each channel has the following structure: - - int16 predict; // predicted value of first sample - // from the previous block (L16 format) - u_int8 index; // current index into stepsize table - u_int8 reserved; // set to zero by sender, ignored by receiver - - Each octet following the header contains two 4-bit samples, thus the - number of samples per packet MUST be even because there is no means - to indicate a partially filled last octet. -*/ - -/*! The number of ADPCM step sizes */ -#define STEP_MAX 88 - -/* Intel ADPCM step variation table */ -static const int step_size[STEP_MAX + 1] = -{ - 7, 8, 9, 10, 11, 12, 13, 14, - 16, 17, 19, 21, 23, 25, 28, 31, - 34, 37, 41, 45, 50, 55, 60, 66, - 73, 80, 88, 97, 107, 118, 130, 143, - 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, - 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, - 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, - 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, - 32767 -}; - -static const int step_adjustment[8] = -{ - -1, -1, -1, -1, 2, 4, 6, 8 -}; - -static const struct -{ - uint8_t code; - uint8_t bits; -} vdvi_encode[] = -{ - {0x00, 2}, - {0x02, 3}, - {0x0C, 4}, - {0x1C, 5}, - {0x3C, 6}, - {0x7C, 7}, - {0xFC, 8}, - {0xFE, 8}, - {0x02, 2}, - {0x03, 3}, - {0x0D, 4}, - {0x1D, 5}, - {0x3D, 6}, - {0x7D, 7}, - {0xFD, 8}, - {0xFF, 8} -}; - -static const struct -{ - uint16_t code; - uint16_t mask; - uint8_t bits; -} vdvi_decode[] = -{ - {0x0000, 0xC000, 2}, - {0x4000, 0xE000, 3}, - {0xC000, 0xF000, 4}, - {0xE000, 0xF800, 5}, - {0xF000, 0xFC00, 6}, - {0xF800, 0xFE00, 7}, - {0xFC00, 0xFF00, 8}, - {0xFE00, 0xFF00, 8}, - {0x8000, 0xC000, 2}, - {0x6000, 0xE000, 3}, - {0xD000, 0xF000, 4}, - {0xE800, 0xF800, 5}, - {0xF400, 0xFC00, 6}, - {0xFA00, 0xFE00, 7}, - {0xFD00, 0xFF00, 8}, - {0xFF00, 0xFF00, 8} -}; - -static int16_t decode(ima_adpcm_state_t *s, uint8_t adpcm) -{ - int e; - int ss; - int16_t linear; - - /* e = (adpcm + 0.5)*step/4 */ - ss = step_size[s->step_index]; - e = ss >> 3; - if (adpcm & 0x01) - e += (ss >> 2); - /*endif*/ - if (adpcm & 0x02) - e += (ss >> 1); - /*endif*/ - if (adpcm & 0x04) - e += ss; - /*endif*/ - if (adpcm & 0x08) - e = -e; - /*endif*/ - linear = saturate16(s->last + e); - s->last = linear; - s->step_index += step_adjustment[adpcm & 0x07]; - if (s->step_index < 0) - s->step_index = 0; - else if (s->step_index > STEP_MAX) - s->step_index = STEP_MAX; - /*endif*/ - return linear; -} -/*- End of function --------------------------------------------------------*/ - -static uint8_t encode(ima_adpcm_state_t *s, int16_t linear) -{ - int e; - int ss; - int adpcm; - int diff; - int initial_e; - - ss = step_size[s->step_index]; - initial_e = - e = linear - s->last; - diff = ss >> 3; - adpcm = (uint8_t) 0x00; - if (e < 0) - { - adpcm = (uint8_t) 0x08; - e = -e; - } - /*endif*/ - if (e >= ss) - { - adpcm |= (uint8_t) 0x04; - e -= ss; - } - /*endif*/ - ss >>= 1; - if (e >= ss) - { - adpcm |= (uint8_t) 0x02; - e -= ss; - } - /*endif*/ - ss >>= 1; - if (e >= ss) - { - adpcm |= (uint8_t) 0x01; - e -= ss; - } - /*endif*/ - - if (initial_e < 0) - diff = -(diff - initial_e - e); - else - diff = diff + initial_e - e; - /*endif*/ - s->last = saturate16(diff + s->last); - s->step_index += step_adjustment[adpcm & 0x07]; - if (s->step_index < 0) - s->step_index = 0; - else if (s->step_index > STEP_MAX) - s->step_index = STEP_MAX; - /*endif*/ - return (uint8_t) adpcm; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(ima_adpcm_state_t *) ima_adpcm_init(ima_adpcm_state_t *s, - int variant, - int chunk_size) -{ - if (s == NULL) - { - if ((s = (ima_adpcm_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - /*endif*/ - memset(s, 0, sizeof(*s)); - s->variant = variant; - s->chunk_size = chunk_size; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ima_adpcm_release(ima_adpcm_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ima_adpcm_free(ima_adpcm_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ima_adpcm_decode(ima_adpcm_state_t *s, - int16_t amp[], - const uint8_t ima_data[], - int ima_bytes) -{ - int i; - int j; - int samples; - uint16_t code; - - samples = 0; - switch (s->variant) - { - case IMA_ADPCM_IMA4: - i = 0; - if (s->chunk_size == 0) - { - amp[samples++] = (ima_data[1] << 8) | ima_data[0]; - s->step_index = ima_data[2]; - s->last = amp[0]; - i = 4; - } - /*endif*/ - for ( ; i < ima_bytes; i++) - { - amp[samples++] = decode(s, ima_data[i] & 0xF); - amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); - } - /*endfor*/ - break; - case IMA_ADPCM_DVI4: - i = 0; - if (s->chunk_size == 0) - { - s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]); - s->step_index = ima_data[2]; - i = 4; - } - /*endif*/ - for ( ; i < ima_bytes; i++) - { - amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); - amp[samples++] = decode(s, ima_data[i] & 0xF); - } - /*endfor*/ - break; - case IMA_ADPCM_VDVI: - i = 0; - if (s->chunk_size == 0) - { - s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]); - s->step_index = ima_data[2]; - i = 4; - } - /*endif*/ - code = 0; - s->bits = 0; - for (;;) - { - if (s->bits <= 8) - { - if (i >= ima_bytes) - break; - /*endif*/ - code |= ((uint16_t) ima_data[i++] << (8 - s->bits)); - s->bits += 8; - } - /*endif*/ - for (j = 0; j < 8; j++) - { - if ((vdvi_decode[j].mask & code) == vdvi_decode[j].code) - break; - if ((vdvi_decode[j + 8].mask & code) == vdvi_decode[j + 8].code) - { - j += 8; - break; - } - /*endif*/ - } - /*endfor*/ - amp[samples++] = decode(s, (uint8_t) j); - code <<= vdvi_decode[j].bits; - s->bits -= vdvi_decode[j].bits; - } - /*endfor*/ - /* Use up the remanents of the last octet */ - while (s->bits > 0) - { - for (j = 0; j < 8; j++) - { - if ((vdvi_decode[j].mask & code) == vdvi_decode[j].code) - break; - /*endif*/ - if ((vdvi_decode[j + 8].mask & code) == vdvi_decode[j + 8].code) - { - j += 8; - break; - } - /*endif*/ - } - /*endfor*/ - if (vdvi_decode[j].bits > s->bits) - break; - /*endif*/ - amp[samples++] = decode(s, (uint8_t) j); - code <<= vdvi_decode[j].bits; - s->bits -= vdvi_decode[j].bits; - } - /*endwhile*/ - break; - } - /*endswitch*/ - return samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) ima_adpcm_encode(ima_adpcm_state_t *s, - uint8_t ima_data[], - const int16_t amp[], - int len) -{ - int i; - int bytes; - uint8_t code; - - bytes = 0; - switch (s->variant) - { - case IMA_ADPCM_IMA4: - i = 0; - if (s->chunk_size == 0) - { - ima_data[bytes++] = (uint8_t) amp[0]; - ima_data[bytes++] = (uint8_t) (amp[0] >> 8); - ima_data[bytes++] = (uint8_t) s->step_index; - ima_data[bytes++] = 0; - s->last = amp[0]; - s->bits = 0; - i = 1; - } - /*endif*/ - for ( ; i < len; i++) - { - s->ima_byte = (uint8_t) ((s->ima_byte >> 4) | (encode(s, amp[i]) << 4)); - if ((s->bits++ & 1)) - ima_data[bytes++] = (uint8_t) s->ima_byte; - /*endif*/ - } - /*endfor*/ - break; - case IMA_ADPCM_DVI4: - if (s->chunk_size == 0) - { - ima_data[bytes++] = (uint8_t) (s->last >> 8); - ima_data[bytes++] = (uint8_t) s->last; - ima_data[bytes++] = (uint8_t) s->step_index; - ima_data[bytes++] = 0; - } - /*endif*/ - for (i = 0; i < len; i++) - { - s->ima_byte = (uint8_t) ((s->ima_byte << 4) | encode(s, amp[i])); - if ((s->bits++ & 1)) - ima_data[bytes++] = (uint8_t) s->ima_byte; - /*endif*/ - } - /*endfor*/ - break; - case IMA_ADPCM_VDVI: - if (s->chunk_size == 0) - { - ima_data[bytes++] = (uint8_t) (s->last >> 8); - ima_data[bytes++] = (uint8_t) s->last; - ima_data[bytes++] = (uint8_t) s->step_index; - ima_data[bytes++] = 0; - } - /*endif*/ - s->bits = 0; - for (i = 0; i < len; i++) - { - code = encode(s, amp[i]); - s->ima_byte = (s->ima_byte << vdvi_encode[code].bits) | vdvi_encode[code].code; - s->bits += vdvi_encode[code].bits; - if (s->bits >= 8) - { - s->bits -= 8; - ima_data[bytes++] = (uint8_t) (s->ima_byte >> s->bits); - } - /*endif*/ - } - /*endfor*/ - if (s->bits) - ima_data[bytes++] = (uint8_t) (((s->ima_byte << 8) | 0xFF) >> s->bits); - /*endif*/ - break; - } - /*endswitch*/ - return bytes; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c deleted file mode 100644 index ecb218bb85..0000000000 --- a/libs/spandsp/src/image_translate.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * image_translate.c - Image translation routines for reworking colour - * and gray scale images to be colour, gray scale or - * bi-level images of an appropriate size to be FAX - * compatible. - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/saturated.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/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/image_translate.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" - -static int image_colour16_to_colour8_row(uint8_t colour8[], uint16_t colour16[], int pixels) -{ - int i; - - for (i = 0; i < 3*pixels; i++) - colour8[i] = colour16[i] >> 8; - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_colour16_to_gray16_row(uint16_t gray16[], uint16_t colour16[], int pixels) -{ - int i; - uint32_t gray; - - for (i = 0; i < pixels; i++) - { - gray = colour16[3*i]*19595 + colour16[3*i + 1]*38469 + colour16[3*i + 2]*7472; - gray16[i] = saturateu16(gray >> 16); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_colour16_to_gray8_row(uint8_t gray8[], uint16_t colour16[], int pixels) -{ - int i; - uint32_t gray; - - for (i = 0; i < pixels; i++) - { - gray = colour16[3*i]*19595 + colour16[3*i + 1]*38469 + colour16[3*i + 2]*7472; - gray8[i] = saturateu8(gray >> 24); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_colour8_to_gray16_row(uint16_t gray16[], uint8_t colour8[], int pixels) -{ - int i; - uint32_t gray; - - for (i = 0; i < pixels; i++) - { - gray = colour8[3*i]*19595 + colour8[3*i + 1]*38469 + colour8[3*i + 2]*7472; - gray16[i] = saturateu16(gray >> 8); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_colour8_to_gray8_row(uint8_t gray8[], uint8_t colour8[], int pixels) -{ - int i; - uint32_t gray; - - for (i = 0; i < pixels; i++) - { - gray = colour8[3*i]*19595 + colour8[3*i + 1]*38469 + colour8[3*i + 2]*7472; - gray8[i] = saturateu8(gray >> 16); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_colour8_to_colour16_row(uint16_t colour16[], uint8_t colour8[], int pixels) -{ - int i; - - for (i = 3*pixels - 1; i >= 0; i--) - colour16[i] = colour8[i] << 8; - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_gray16_to_colour16_row(uint16_t colour16[], uint16_t gray16[], int pixels) -{ - int i; - - for (i = pixels - 1; i >= 0; i--) - { - colour16[3*i] = saturateu16((gray16[i]*36532U) >> 15); - colour16[3*i + 1] = saturateu16((gray16[i]*37216U) >> 16); - colour16[3*i + 2] = saturateu16((gray16[i]*47900U) >> 14); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_gray16_to_colour8_row(uint8_t colour8[], uint16_t gray16[], int pixels) -{ - int i; - - for (i = pixels - 1; i >= 0; i--) - { - colour8[3*i] = saturateu8((gray16[i]*36532U) >> 23); - colour8[3*i + 1] = saturateu8((gray16[i]*37216U) >> 24); - colour8[3*i + 2] = saturateu8((gray16[i]*47900U) >> 22); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_gray16_to_gray8_row(uint8_t gray8[], uint16_t gray16[], int pixels) -{ - int i; - - for (i = 0; i < pixels; i++) - gray8[i] = gray16[i] >> 8; - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_gray8_to_colour16_row(uint16_t colour16[], uint8_t gray8[], int pixels) -{ - int i; - - for (i = pixels - 1; i >= 0; i--) - { - colour16[3*i] = saturateu16((gray8[i]*36532U) >> 7); - colour16[3*i + 1] = saturateu16((gray8[i]*37216U) >> 8); - colour16[3*i + 2] = saturateu16((gray8[i]*47900U) >> 6); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_gray8_to_colour8_row(uint8_t colour8[], uint8_t gray8[], int pixels) -{ - int i; - - for (i = pixels - 1; i >= 0; i--) - { - colour8[3*i] = saturateu8((gray8[i]*36532U) >> 15); - colour8[3*i + 1] = saturateu8((gray8[i]*37216U) >> 16); - colour8[3*i + 2] = saturateu8((gray8[i]*47900U) >> 14); - } - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int image_gray8_to_gray16_row(uint16_t gray16[], uint8_t gray8[], int pixels) -{ - int i; - - for (i = pixels - 1; i >= 0; i--) - gray16[i] = gray8[i] << 8; - return pixels; -} -/*- End of function --------------------------------------------------------*/ - -static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[]) -{ - int input_row_len; - - input_row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->input_bytes_per_pixel); - if (input_row_len != s->input_width*s->input_bytes_per_pixel) - return 0; - /* Scrunch colour down to gray, vice versa. Scrunch 16 bit pixels down to 8 bit pixels, or vice versa. */ - switch (s->input_format) - { - case T4_IMAGE_TYPE_GRAY_12BIT: - switch (s->output_format) - { - case T4_IMAGE_TYPE_BILEVEL: - case T4_IMAGE_TYPE_GRAY_8BIT: - image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width); - break; - 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; - } - break; - case T4_IMAGE_TYPE_GRAY_8BIT: - switch (s->output_format) - { - case T4_IMAGE_TYPE_GRAY_12BIT: - image_gray8_to_gray16_row((uint16_t *) buf, buf, s->input_width); - break; - 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; - } - break; - case T4_IMAGE_TYPE_COLOUR_12BIT: - switch (s->output_format) - { - case T4_IMAGE_TYPE_GRAY_12BIT: - image_colour16_to_gray16_row((uint16_t *) buf, (uint16_t *) buf, s->input_width); - break; - case T4_IMAGE_TYPE_BILEVEL: - 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) - { - case T4_IMAGE_TYPE_GRAY_12BIT: - image_colour8_to_gray16_row((uint16_t *) buf, buf, s->input_width); - break; - case T4_IMAGE_TYPE_BILEVEL: - case T4_IMAGE_TYPE_GRAY_8BIT: - image_colour8_to_gray8_row(buf, buf, s->input_width); - break; - case T4_IMAGE_TYPE_COLOUR_12BIT: - image_colour8_to_colour16_row((uint16_t *) buf, buf, s->input_width); - break; - } - break; - } - return s->output_width; -} -/*- End of function --------------------------------------------------------*/ - -static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) -{ - int i; - int j; - int output_width; - int output_length; - int input_width; - int input_length; - int x; -#if defined(SPANDSP_USE_FIXED_POINT) - int c1; - int c2; - int frac_row; - int frac_col; -#else - double c1; - double c2; - double int_part; - double frac_row; - double frac_col; - double width_scaling; -#endif - uint8_t *row8[2]; - uint16_t *row16[2]; - uint16_t *buf16; - int row_len; - int skip; - uint8_t *p; - - if (s->raw_output_row < 0) - return 0; - output_width = s->output_width - 1; - output_length = s->output_length - 1; - input_width = s->input_width - 1; - input_length = s->input_length - 1; - - skip = s->raw_output_row*input_length/output_length + 1; - if (skip >= s->raw_input_row) - { - while (skip >= s->raw_input_row) - { - if (s->raw_input_row >= s->input_length) - break; - row_len = get_and_scrunch_row(s, s->raw_pixel_row[0]); - if (row_len != s->output_width) - { - s->raw_output_row = -1; - return 0; - } - s->raw_input_row++; - p = s->raw_pixel_row[0]; - s->raw_pixel_row[0] = s->raw_pixel_row[1]; - s->raw_pixel_row[1] = p; - } - } - -#if defined(SPANDSP_USE_FIXED_POINT) - 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]; - for (i = 0; i < output_width; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - x = i*256*input_width/output_width; - frac_col = x & 0xFF; - x >>= 8; - x = 3*x; - for (j = 0; j < 3; j++) - { - c1 = row8[0][x + j] + (((row8[0][x + j + 3] - row8[0][x + j])*frac_col) >> 8); - c2 = row8[1][x + j] + (((row8[1][x + j + 3] - row8[1][x + j])*frac_col) >> 8); - buf[3*i + j] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8)); - } -#else - frac_col = modf(width_scaling*i, &int_part); - x = 3*int_part; - for (j = 0; j < 3; j++) - { - c1 = row8[0][x + j] + (row8[0][x + j + 3] - row8[0][x + j])*frac_col; - c2 = row8[1][x + j] + (row8[1][x + j + 3] - row8[1][x + j])*frac_col; - buf[3*i + j] = saturateu8(c1 + (c2 - c1)*frac_row); - } -#endif - } - break; - case T4_IMAGE_TYPE_COLOUR_12BIT: - row16[0] = (uint16_t *) s->raw_pixel_row[0]; - row16[1] = (uint16_t *) s->raw_pixel_row[1]; - buf16 = (uint16_t *) buf; - for (i = 0; i < output_width; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - x = i*256*input_width/output_width; - frac_col = x & 0xFF; - x >>= 8; - x = 3*x; - for (j = 0; j < 3; j++) - { - c1 = row16[0][x + j] + (((row16[0][x + j + 3] - row16[0][x + j])*frac_col) >> 8); - c2 = row16[1][x + j] + (((row16[1][x + j + 3] - row16[1][x + j])*frac_col) >> 8); - buf16[3*i + j] = saturateu16(c1 + (((c2 - c1)*frac_row) >> 8)); - } -#else - frac_col = modf(width_scaling*i, &int_part); - x = 3*int_part; - for (j = 0; j < 3; j++) - { - c1 = row16[0][x + j] + (row16[0][x + j + 3] - row16[0][x + j])*frac_col; - c2 = row16[1][x + j] + (row16[1][x + j + 3] - row16[1][x + j])*frac_col; - buf16[3*i + j] = saturateu16(c1 + (c2 - c1)*frac_row); - } -#endif - } - break; - case T4_IMAGE_TYPE_BILEVEL: - case T4_IMAGE_TYPE_GRAY_8BIT: - row8[0] = s->raw_pixel_row[0]; - row8[1] = s->raw_pixel_row[1]; - for (i = 0; i < output_width; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - x = i*256*input_width/output_width; - frac_col = x & 0xFF; - x >>= 8; - c1 = row8[0][x] + (((row8[0][x + 1] - row8[0][x])*frac_col) >> 8); - 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(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; - buf[i] = saturateu8(c1 + (c2 - c1)*frac_row); -#endif - } - break; - case T4_IMAGE_TYPE_GRAY_12BIT: - row16[0] = (uint16_t *) s->raw_pixel_row[0]; - row16[1] = (uint16_t *) s->raw_pixel_row[1]; - for (i = 0; i < output_width; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - x = i*256*input_width/output_width; - frac_col = x & 0xFF; - x >>= 8; - c1 = row16[0][x] + (((row16[0][x + 1] - row16[0][x])*frac_col) >> 8); - 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(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; - buf[i] = saturateu8(c1 + (c2 - c1)*frac_row); -#endif - } - break; - } - if (++s->raw_output_row >= s->output_length) - s->raw_output_row = -1; - return s->output_width; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint8_t find_closest_palette_color(int in) -{ - return (in >= 128) ? 255 : 0; -} -/*- End of function --------------------------------------------------------*/ - -static int floyd_steinberg_dither_row(image_translate_state_t *s, uint8_t buf[]) -{ - int x; - int y; - int i; - int j; - int limit; - int old_pixel; - int new_pixel; - int quant_error; - uint8_t xx; - uint8_t *p; - - y = s->output_row++; - /* This algorithm works over two rows, and outputs the earlier of the two. To - make this work: - - At row 0 we grab and scrunch two rows. - - From row 1 up to the last row we grab one new additional row each time. - - At the last row we dither and output, without getting an extra row in. */ - for (i = (y == 0) ? 0 : 1; i < 2; i++) - { - /* Swap the row buffers */ - p = s->pixel_row[0]; - s->pixel_row[0] = s->pixel_row[1]; - s->pixel_row[1] = p; - - /* If this is the end of the image just ignore that there is now rubbish in pixel_row[1]. - Mark that the end has occurred. This row will be properly output, and the next one - will fail, with the end of image condition (i.e. returning zero length) */ - if (s->resize) - { - if (image_resize_row(s, s->pixel_row[1]) != s->output_width) - s->output_row = -1; - } - else - { - if (get_and_scrunch_row(s, s->pixel_row[1]) != s->output_width) - s->output_row = -1; - } - } - /* Apply Floyd-Steinberg dithering to the 8 bit pixels, using a bustrophedontic - scan, to reduce the grayscale image to pure black and white */ - /* The first and last pixels in each row need special treatment, so we do not - step outside the row. */ - if ((y & 1)) - { - x = s->output_width - 1; - old_pixel = s->pixel_row[0][x]; - new_pixel = find_closest_palette_color(old_pixel); - quant_error = old_pixel - new_pixel; - s->pixel_row[0][x + 0] = new_pixel; - s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16); - s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); - s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16); - while (--x > 0) - { - old_pixel = s->pixel_row[0][x]; - new_pixel = find_closest_palette_color(old_pixel); - quant_error = old_pixel - new_pixel; - s->pixel_row[0][x + 0] = new_pixel; - s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16); - s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (3*quant_error)/16); - s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); - s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16); - } - old_pixel = s->pixel_row[0][x]; - new_pixel = find_closest_palette_color(old_pixel); - quant_error = old_pixel - new_pixel; - s->pixel_row[0][x + 0] = new_pixel; - s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (3*quant_error)/16); - s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); - } - else - { - x = 0; - old_pixel = s->pixel_row[0][x]; - new_pixel = find_closest_palette_color(old_pixel); - quant_error = old_pixel - new_pixel; - s->pixel_row[0][x + 0] = new_pixel; - s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16); - s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); - s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16); - while (++x < s->output_width - 1) - { - old_pixel = s->pixel_row[0][x]; - new_pixel = find_closest_palette_color(old_pixel); - quant_error = old_pixel - new_pixel; - s->pixel_row[0][x + 0] = new_pixel; - s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16); - s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (3*quant_error)/16); - s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); - s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16); - } - old_pixel = s->pixel_row[0][x]; - new_pixel = find_closest_palette_color(old_pixel); - quant_error = old_pixel - new_pixel; - s->pixel_row[0][x + 0] = new_pixel; - s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (3*quant_error)/16); - s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); - } - /* Now bit pack the pixel per byte row into a pixel per bit row. */ - for (i = 0, x = 0; x < s->output_width; i++, x += 8) - { - xx = 0; - /* Allow for the possibility that the width is not a multiple of 8 */ - limit = (8 <= s->output_width - x) ? 8 : (s->output_width - x); - for (j = 0; j < limit; j++) - { - if (s->pixel_row[0][x + j] <= 128) - xx |= (1 << (7 - j)); - } - buf[i] = xx; - } - return i; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], size_t len) -{ - int i; - - if (s->output_row < 0) - return 0; - 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); - break; - default: - s->output_row++; - if (s->resize) - { - if (image_resize_row(s, buf) != s->output_width) - s->output_row = -1; - } - else - { - if (get_and_scrunch_row(s, buf) != s->output_width) - s->output_row = -1; - } - if (s->output_row < 0) - return 0; - i = s->output_width*s->output_bytes_per_pixel; - break; - } - return i; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s) -{ - return s->output_width; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s) -{ - return s->output_length; -} -/*- End of function --------------------------------------------------------*/ - -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) - { - 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; - - s->input_length = input_length; - if (s->resize) - s->output_length = (s->input_length*s->output_width)/s->input_width; - else - s->output_length = s->input_length; - - /* 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; - row_size = s->output_width*s->output_bytes_per_pixel; - if (raw_row_size < row_size) - raw_row_size = row_size; - if (s->resize) - { - for (i = 0; i < 2; i++) - { - 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); - } - } - 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] == 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->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); - s->output_width = (s->resize) ? output_width : s->input_width; - - if (image_translate_restart(s, input_length)) - return NULL; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s) -{ - int i; - - for (i = 0; i < 2; i++) - { - if (s->raw_pixel_row[i]) - { - span_free(s->raw_pixel_row[i]); - s->raw_pixel_row[i] = NULL; - } - if (s->pixel_row[i]) - { - span_free(s->pixel_row[i]); - s->pixel_row[i] = NULL; - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s) -{ - int res; - - res = image_translate_release(s); - span_free(s); - return res; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/libspandsp.2005.vcproj b/libs/spandsp/src/libspandsp.2005.vcproj deleted file mode 100644 index a89a59b23d..0000000000 --- a/libs/spandsp/src/libspandsp.2005.vcproj +++ /dev/null @@ -1,367 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/libspandsp.2008.vcproj b/libs/spandsp/src/libspandsp.2008.vcproj deleted file mode 100644 index 96af303167..0000000000 --- a/libs/spandsp/src/libspandsp.2008.vcproj +++ /dev/null @@ -1,1346 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/libspandsp.2010.vcxproj.filters b/libs/spandsp/src/libspandsp.2010.vcxproj.filters deleted file mode 100644 index dea495c328..0000000000 --- a/libs/spandsp/src/libspandsp.2010.vcxproj.filters +++ /dev/null @@ -1,741 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {23b008e2-8d2d-475f-bdb4-f3f067ff16e3} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - - \ No newline at end of file diff --git a/libs/spandsp/src/libspandsp.2012.sln b/libs/spandsp/src/libspandsp.2012.sln deleted file mode 100644 index 6063a30635..0000000000 --- a/libs/spandsp/src/libspandsp.2012.sln +++ /dev/null @@ -1,322 +0,0 @@ - -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}") = "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}") = "dtmf_rx_tests", "..\tests\msvc\dtmf_rx_tests.2012.vcxproj", "{24E7EF80-7854-4A21-80FB-31C4E71109DE}" -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}") = "queue_tests", "..\tests\msvc\queue_tests.2012.vcxproj", "{D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}" -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}") = "v22bis_tests", "..\tests\msvc\v22bis_tests.2012.vcxproj", "{DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}" -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}") = "v8_tests", "..\tests\msvc\v8_tests.2012.vcxproj", "{0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}" -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}") = "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("{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.2017.vcxproj b/libs/spandsp/src/libspandsp.2017.vcxproj deleted file mode 100644 index b8a847f361..0000000000 --- a/libs/spandsp/src/libspandsp.2017.vcxproj +++ /dev/null @@ -1,470 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - libspandsp - {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} - libspandsp - Win32Proj - - - - DynamicLibrary - Unicode - true - $(DefaultPlatformToolset) - - - DynamicLibrary - Unicode - $(DefaultPlatformToolset) - - - DynamicLibrary - Unicode - true - $(DefaultPlatformToolset) - - - DynamicLibrary - Unicode - $(DefaultPlatformToolset) - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - true - false - true - false - - - - $(IntDir)BuildLog $(ProjectName).htm - - - Disabled - .;..\..\src\spandsp;..\..\src;..\..\src\msvc;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - CompileAsC - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - false - MachineX86 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - .;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - MultiThreadedDLL - Level4 - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - true - true - false - MachineX86 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - Disabled - .;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - CompileAsC - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - false - MachineX64 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - .;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - MultiThreadedDLL - Level4 - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - true - true - false - MachineX64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - - - - - {019dbd2a-273d-4ba4-bf86-b5efe2ed76b1} - true - false - false - true - false - - - {401a40cd-5db4-4e34-ac68-fa99e9fac014} - false - - - {dee932ab-5911-4700-9eeb-8c7090a0a330} - false - - - {85f0cf8c-c7ab-48f6-ba19-cc94cf87f981} - - - {2386b892-35f5-46cf-a0f0-10394d2fbf9b} - - - {329a6fa0-0fcc-4435-a950-e670aefa9838} - false - - - {eddb8ab9-c53e-44c0-a620-0e86c2cbd5d5} - false - - - - - - \ No newline at end of file diff --git a/libs/spandsp/src/libtiff.2005.vcproj b/libs/spandsp/src/libtiff.2005.vcproj deleted file mode 100644 index 94594bb42d..0000000000 --- a/libs/spandsp/src/libtiff.2005.vcproj +++ /dev/null @@ -1,352 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/libtiff.2008.vcproj b/libs/spandsp/src/libtiff.2008.vcproj deleted file mode 100644 index 4a29650333..0000000000 --- a/libs/spandsp/src/libtiff.2008.vcproj +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/libtiff.2010.vcxproj.filters b/libs/spandsp/src/libtiff.2010.vcxproj.filters deleted file mode 100644 index adb3ae4c27..0000000000 --- a/libs/spandsp/src/libtiff.2010.vcxproj.filters +++ /dev/null @@ -1,157 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {ac6743e4-3ae7-4b7b-bc52-d1700047dc05} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/libs/spandsp/src/logging.c b/libs/spandsp/src/logging.c deleted file mode 100644 index 808ee7e392..0000000000 --- a/libs/spandsp/src/logging.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * logging.c - error and debug logging. - * - * 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. - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#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" - -static void default_message_handler(void *user_data, int level, const char *text); - -static message_handler_func_t __span_message = &default_message_handler; -static void *__user_data = NULL; - -/* Note that this list *must* match the enum definition in logging.h */ -static const char *severities[] = -{ - "NONE", - "ERROR", - "WARNING", - "PROTOCOL_ERROR", - "PROTOCOL_WARNING", - "FLOW", - "FLOW 2", - "FLOW 3", - "DEBUG 1", - "DEBUG 2", - "DEBUG 3" -}; - -static void default_message_handler(void *user_data, int level, const char *text) -{ - fprintf(stderr, "%s", text); -} -/*- End of function --------------------------------------------------------*/ - -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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log(logging_state_t *s, int level, const char *format, ...) -{ - char msg[1024 + 1]; - va_list arg_ptr; - int len; - struct tm *tim; - struct timeval nowx; - time_t now; - - if (span_log_test(s, level)) - { - va_start(arg_ptr, format); - len = 0; - if ((level & SPAN_LOG_SUPPRESS_LABELLING) == 0) - { - if ((s->level & SPAN_LOG_SHOW_DATE)) - { - gettimeofday(&nowx, NULL); - now = nowx.tv_sec; - tim = gmtime(&now); - len += snprintf(msg + len, - 1024 - len, - "%04d/%02d/%02d %02d:%02d:%02d.%03d ", - tim->tm_year + 1900, - tim->tm_mon + 1, - tim->tm_mday, - tim->tm_hour, - tim->tm_min, - tim->tm_sec, - (int) nowx.tv_usec/1000); - } - /*endif*/ - if ((s->level & SPAN_LOG_SHOW_SAMPLE_TIME)) - { - now = s->elapsed_samples/s->samples_per_second; - tim = gmtime(&now); - len += snprintf(msg + len, - 1024 - len, - "%02d:%02d:%02d.%03d ", - tim->tm_hour, - tim->tm_min, - tim->tm_sec, - (int) (s->elapsed_samples%s->samples_per_second)*1000/s->samples_per_second); - } - /*endif*/ - if ((s->level & SPAN_LOG_SHOW_SEVERITY) && (level & SPAN_LOG_SEVERITY_MASK) <= SPAN_LOG_DEBUG_3) - len += snprintf(msg + len, 1024 - len, "%s ", severities[level & SPAN_LOG_SEVERITY_MASK]); - /*endif*/ - if ((s->level & SPAN_LOG_SHOW_PROTOCOL) && s->protocol) - len += snprintf(msg + len, 1024 - len, "%s ", s->protocol); - /*endif*/ - if ((s->level & SPAN_LOG_SHOW_TAG) && s->tag) - len += snprintf(msg + len, 1024 - len, "%s ", s->tag); - /*endif*/ - } - /*endif*/ - vsnprintf(msg + len, 1024 - len, format, arg_ptr); - if (s->span_message) - s->span_message(s->user_data, level, msg); - else if (__span_message) - __span_message(s->user_data, level, msg); - /*endif*/ - va_end(arg_ptr); - return 1; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_buf(logging_state_t *s, int level, const char *tag, const uint8_t *buf, int len) -{ - char msg[1024]; - int i; - int msg_len; - - if (span_log_test(s, level)) - { - msg_len = 0; - if (tag) - msg_len += snprintf(msg + msg_len, 1024 - msg_len, "%s", tag); - for (i = 0; i < len && msg_len < 800; i++) - msg_len += snprintf(msg + msg_len, 1024 - msg_len, " %02x", buf[i]); - snprintf(msg + msg_len, 1024 - msg_len, "\n"); - return span_log(s, level, msg); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_get_level(logging_state_t *s) -{ - return s->level; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_set_level(logging_state_t *s, int level) -{ - s->level = level; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) span_log_get_tag(logging_state_t *s) -{ - return s->tag; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_set_tag(logging_state_t *s, const char *tag) -{ - s->tag = tag; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) span_log_get_protocol(logging_state_t *s) -{ - return s->protocol; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_set_protocol(logging_state_t *s, const char *protocol) -{ - s->protocol = protocol; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_set_sample_rate(logging_state_t *s, int samples_per_second) -{ - s->samples_per_second = samples_per_second; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_bump_samples(logging_state_t *s, int samples) -{ - s->elapsed_samples += samples; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) span_log_set_message_handler(logging_state_t *s, message_handler_func_t func, void *user_data) -{ - s->span_message = func; - s->user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) span_set_message_handler(message_handler_func_t func, void *user_data) -{ - __span_message = func; - __user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) span_log_init(logging_state_t *s, int level, const char *tag) -{ - if (s == NULL) - { - if ((s = (logging_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - s->span_message = __span_message; - s->level = level; - s->tag = tag; - s->protocol = NULL; - s->samples_per_second = SAMPLE_RATE; - s->elapsed_samples = 0; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_release(logging_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_log_free(logging_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_analyse.c b/libs/spandsp/src/lpc10_analyse.c deleted file mode 100644 index 74125aa8c4..0000000000 --- a/libs/spandsp/src/lpc10_analyse.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_analyse.c - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the U.S. Department of Defense reference - * implementation of the LPC-10 2400 bps Voice Coder. They do not - * exert copyright claims on their code, and it may be freely used. - */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/lpc10.h" -#include "spandsp/private/lpc10.h" - -#include "lpc10_encdecs.h" - -static __inline__ float energyf(float amp[], int len) -{ - int i; - float rms; - - rms = 0.0f; - for (i = 0; i < len; i++) - rms += amp[i]*amp[i]; - rms = sqrtf(rms/len); - return rms; -} -/*- End of function --------------------------------------------------------*/ - -static void remove_dc_bias(float speech[], int len, float sigout[]) -{ - float bias; - int i; - - bias = 0.0f; - for (i = 0; i < len; i++) - bias += speech[i]; - bias /= len; - for (i = 0; i < len; i++) - sigout[i] = speech[i] - bias; -} -/*- End of function --------------------------------------------------------*/ - -static void eval_amdf(float speech[], - int32_t lpita, - const int32_t tau[], - int32_t ltau, - int32_t maxlag, - float amdf[], - int32_t *minptr, - int32_t *maxptr) -{ - float sum; - int i; - int j; - int n1; - int n2; - - *minptr = 0; - *maxptr = 0; - for (i = 0; i < ltau; i++) - { - n1 = (maxlag - tau[i])/2 + 1; - n2 = n1 + lpita - 1; - sum = 0.0f; - for (j = n1; j <= n2; j += 4) - sum += fabsf(speech[j - 1] - speech[j + tau[i] - 1]); - amdf[i] = sum; - if (amdf[i] < amdf[*minptr]) - *minptr = i; - if (amdf[i] > amdf[*maxptr]) - *maxptr = i; - } -} -/*- End of function --------------------------------------------------------*/ - -static void eval_highres_amdf(float speech[], - int32_t lpita, - const int32_t tau[], - int32_t ltau, - float amdf[], - int32_t *minptr, - int32_t *maxptr, - int32_t *mintau) -{ - float amdf2[6]; - int32_t tau2[6]; - int32_t minp2; - int32_t ltau2; - int32_t maxp2; - int32_t minamd; - int i; - int i2; - int ptr; - - /* Compute full AMDF using log spaced lags, find coarse minimum */ - eval_amdf(speech, lpita, tau, ltau, tau[ltau - 1], amdf, minptr, maxptr); - *mintau = tau[*minptr]; - minamd = (int32_t) amdf[*minptr]; - - /* Build table containing all lags within +/- 3 of the AMDF minimum, - excluding all that have already been computed */ - ltau2 = 0; - ptr = *minptr - 2; - i2 = min(*mintau + 4, tau[ltau - 1]); - for (i = max(*mintau - 3, 41); i < i2; i++) - { - while (tau[ptr] < i) - ptr++; - if (tau[ptr] != i) - tau2[ltau2++] = i; - } - /* Compute AMDF of the new lags, if there are any, and choose one - if it is better than the coarse minimum */ - if (ltau2 > 0) - { - eval_amdf(speech, lpita, tau2, ltau2, tau[ltau - 1], amdf2, &minp2, &maxp2); - if (amdf2[minp2] < (float) minamd) - { - *mintau = tau2[minp2]; - minamd = (int32_t) amdf2[minp2]; - } - } - /* Check one octave up, if there are any lags not yet computed */ - if (*mintau >= 80) - { - i = *mintau/2; - if ((i & 1) == 0) - { - ltau2 = 2; - tau2[0] = i - 1; - tau2[1] = i + 1; - } - else - { - ltau2 = 1; - tau2[0] = i; - } - eval_amdf(speech, lpita, tau2, ltau2, tau[ltau - 1], amdf2, &minp2, &maxp2); - if (amdf2[minp2] < (float) minamd) - { - *mintau = tau2[minp2]; - minamd = (int32_t) amdf2[minp2]; - *minptr -= 20; - } - } - /* Force minimum of the AMDF array to the high resolution minimum */ - amdf[*minptr] = (float) minamd; - /* Find maximum of AMDF within 1/2 octave of minimum */ - *maxptr = max(*minptr - 5, 0); - i2 = min(*minptr + 6, ltau); - for (i = *maxptr; i < i2; i++) - { - if (amdf[i] > amdf[*maxptr]) - *maxptr = i; - } -} -/*- End of function --------------------------------------------------------*/ - -static void dynamic_pitch_tracking(lpc10_encode_state_t *s, - float amdf[], - int32_t ltau, - int32_t *minptr, - int32_t voice, - int32_t *pitch, - int32_t *midx) -{ - int32_t pbar; - float sbar; - int32_t i; - int32_t j; - float alpha; - float minsc; - float maxsc; - - /* Calculate the confidence factor ALPHA, used as a threshold slope in */ - /* SEESAW. If unvoiced, set high slope so that every point in P array */ - /*is marked as a potential pitch frequency. A scaled up version (ALPHAX )*/ - /* is used to maintain arithmetic precision. */ - if (voice == 1) - s->alphax = s->alphax*0.75f + amdf[*minptr - 1]*0.5f; - else - s->alphax *= 0.984375f; - alpha = s->alphax/16; - if (voice == 0 && s->alphax < 128.0f) - alpha = 8.0f; - /* SEESAW: Construct a pitch pointer array and intermediate winner function */ - /* Left to right pass: */ - s->p[s->ipoint][0] = 1; - pbar = 1; - sbar = s->s[0]; - for (i = 0; i < ltau; i++) - { - sbar += alpha; - if (sbar < s->s[i]) - { - s->s[i] = sbar; - } - else - { - pbar = i + 1; - sbar = s->s[i]; - } - s->p[s->ipoint][i] = pbar; - } - /* Right to left pass: */ - sbar = s->s[pbar - 1]; - for (i = pbar - 2; i >= 0; i--) - { - sbar += alpha; - if (sbar < s->s[i]) - { - s->s[i] = sbar; - s->p[s->ipoint][i] = pbar; - } - else - { - pbar = s->p[s->ipoint][i]; - i = pbar - 1; - sbar = s->s[i]; - } - } - /* Update S using AMDF */ - /* Find maximum, minimum, and location of minimum */ - s->s[0] += amdf[0]/2; - minsc = s->s[0]; - maxsc = minsc; - *midx = 1; - for (i = 1; i < ltau; i++) - { - s->s[i] += amdf[i]/2; - if (s->s[i] > maxsc) - maxsc = s->s[i]; - if (s->s[i] < minsc) - { - *midx = i + 1; - minsc = s->s[i]; - } - } - /* Subtract MINSC from S to prevent overflow */ - for (i = 0; i < ltau; i++) - s->s[i] -= minsc; - maxsc -= minsc; - /* Use higher octave pitch if significant null there */ - j = 0; - for (i = 20; i <= 40; i += 10) - { - if (*midx > i) - { - if (s->s[*midx - i - 1] < maxsc / 4) - j = i; - } - } - *midx -= j; - /* TRACE: look back two frames to find minimum cost pitch estimate */ - *pitch = *midx; - for (i = 0, j = s->ipoint; i < 2; i++, j++) - *pitch = s->p[j & 1][*pitch - 1]; - - /* The following statement subtracts one from IPOINT, mod DEPTH. I */ - /* think the author chose to add DEPTH-1, instead of subtracting 1, */ - /* because then it will work even if MOD doesn't work as desired on */ - /* negative arguments. */ - s->ipoint = (s->ipoint + 1) & 1; -} -/*- End of function --------------------------------------------------------*/ - -/* Detection of onsets in (or slightly preceding) the futuremost frame of speech. */ -static void onset(lpc10_encode_state_t *s, - float *pebuf, - int32_t osbuf[], - int32_t *osptr, - int32_t oslen, - int32_t sbufl, - int32_t sbufh, - int32_t lframe) -{ - int32_t i; - float r1; - float l2sum2; - - pebuf -= sbufl; - - if (s->hyst) - s->lasti -= lframe; - for (i = sbufh - lframe + 1; i <= sbufh; i++) - { - /* Compute FPC; Use old FPC on divide by zero; Clamp FPC to +/- 1. */ - s->n = (pebuf[i]*pebuf[i - 1] + s->n*63.0f)/64.0f; - /* Computing 2nd power */ - r1 = pebuf[i - 1]; - s->d__ = (r1*r1 + s->d__*63.0f)/64.0f; - if (s->d__ != 0.0f) - { - if (fabsf(s->n) > s->d__) - s->fpc = r_sign(1.0f, s->n); - else - s->fpc = s->n/s->d__; - } - /* Filter FPC */ - l2sum2 = s->l2buf[s->l2ptr1 - 1]; - s->l2sum1 = s->l2sum1 - s->l2buf[s->l2ptr2 - 1] + s->fpc; - s->l2buf[s->l2ptr2 - 1] = s->l2sum1; - s->l2buf[s->l2ptr1 - 1] = s->fpc; - s->l2ptr1 = (s->l2ptr1 & 0xF) + 1; - s->l2ptr2 = (s->l2ptr2 & 0xF) + 1; - if (fabsf(s->l2sum1 - l2sum2) > 1.7f) - { - if (!s->hyst) - { - /* Ignore if buffer full */ - if (*osptr <= oslen) - { - osbuf[*osptr - 1] = i - 9; - (*osptr)++; - } - s->hyst = true; - } - s->lasti = i; - /* After one onset detection, at least OSHYST sample times must go */ - /* by before another is allowed to occur. */ - } - else if (s->hyst && i - s->lasti >= 10) - { - s->hyst = false; - } - } -} -/*- End of function --------------------------------------------------------*/ - -/* Load a covariance matrix. */ -static void mload(int32_t order, int32_t awins, int32_t awinf, float speech[], float phi[], float psi[]) -{ - int32_t start; - int i; - int r; - - start = awins + order; - for (r = 1; r <= order; r++) - { - phi[r - 1] = 0.0f; - for (i = start; i <= awinf; i++) - phi[r - 1] += speech[i - 2]*speech[i - r - 1]; - } - - /* Load last element of vector PSI */ - psi[order - 1] = 0.0f; - for (i = start - 1; i < awinf; i++) - psi[order - 1] += speech[i]*speech[i - order]; - /* End correct to get additional columns of phi */ - for (r = 1; r < order; r++) - { - for (i = 1; i <= r; i++) - { - phi[i*order + r] = phi[(i - 1)*order + r - 1] - - speech[awinf - (r + 1)]*speech[awinf - (i + 1)] - + speech[start - (r + 2)]*speech[start - (i + 2)]; - } - } - /* End correct to get additional elements of PSI */ - for (i = 0; i < order - 1; i++) - { - psi[i] = phi[i + 1] - - speech[start - 2]*speech[start - i - 3] - + speech[awinf - 1]*speech[awinf - i - 2]; - } -} -/*- End of function --------------------------------------------------------*/ - -/* Preemphasize speech with a single-zero filter. */ -/* (When coef = .9375, preemphasis is as in LPC43.) */ -static float preemp(float inbuf[], float pebuf[], int nsamp, float coeff, float z) -{ - float temp; - int i; - - for (i = 0; i < nsamp; i++) - { - temp = inbuf[i] - coeff*z; - z = inbuf[i]; - pebuf[i] = temp; - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -/* Invert a covariance matrix using Choleski decomposition method. */ -static void invert(int32_t order, float phi[], float psi[], float rc[]) -{ - float r1; - int32_t i; - int32_t j; - int32_t k; - float v[10][10]; - - for (j = 0; j < order; j++) - { - for (i = j; i < order; i++) - v[j][i] = phi[i + j*order]; - for (k = 0; k < j; k++) - { - r1 = v[k][j]*v[k][k]; - for (i = j; i <= order; i++) - v[j][i] -= v[k][i]*r1; - } - /* Compute intermediate results, which are similar to RC's */ - if (fabsf(v[j][j]) < 1.0e-10f) - { - for (i = j; i < order; i++) - rc[i] = 0.0f; - return; - } - rc[j] = psi[j]; - for (k = 0; k < j; k++) - rc[j] -= rc[k]*v[k][j]; - v[j][j] = 1.0f/v[j][j]; - rc[j] *= v[j][j]; - r1 = min(rc[j], 0.999f); - rc[j] = max(r1, -0.999f); - } -} -/*- End of function --------------------------------------------------------*/ - -/* Check RC's, repeat previous frame's RC's if unstable */ -static int rcchk(int order, float rc1f[], float rc2f[]) -{ - int i; - - for (i = 0; i < order; i++) - { - if (fabsf(rc2f[i]) > 0.99f) - { - for (i = 0; i < order; i++) - rc2f[i] = rc1f[i]; - break; - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void lpfilt(float inbuf[], float lpbuf[], int32_t len, int32_t nsamp) -{ - int32_t j; - float t; - - /* 31 point equiripple FIR LPF */ - /* Linear phase, delay = 15 samples */ - /* Passband: ripple = 0.25 dB, cutoff = 800 Hz */ - /* Stopband: atten. = 40. dB, cutoff = 1240 Hz */ - - for (j = len - nsamp; j < len; j++) - { - t = (inbuf[j] + inbuf[j - 30]) * -0.0097201988f; - t += (inbuf[j - 1] + inbuf[j - 29]) * -0.0105179986f; - t += (inbuf[j - 2] + inbuf[j - 28]) * -0.0083479648f; - t += (inbuf[j - 3] + inbuf[j - 27]) * 5.860774e-4f; - t += (inbuf[j - 4] + inbuf[j - 26]) * 0.0130892089f; - t += (inbuf[j - 5] + inbuf[j - 25]) * 0.0217052232f; - t += (inbuf[j - 6] + inbuf[j - 24]) * 0.0184161253f; - t += (inbuf[j - 7] + inbuf[j - 23]) * 3.39723e-4f; - t += (inbuf[j - 8] + inbuf[j - 22]) * -0.0260797087f; - t += (inbuf[j - 9] + inbuf[j - 21]) * -0.0455563702f; - t += (inbuf[j - 10] + inbuf[j - 20]) * -0.040306855f; - t += (inbuf[j - 11] + inbuf[j - 19]) * 5.029835e-4f; - t += (inbuf[j - 12] + inbuf[j - 18]) * 0.0729262903f; - t += (inbuf[j - 13] + inbuf[j - 17]) * 0.1572008878f; - t += (inbuf[j - 14] + inbuf[j - 16]) * 0.2247288674f; - t += inbuf[j - 15] * 0.250535965f; - lpbuf[j] = t; - } -} -/*- End of function --------------------------------------------------------*/ - -/* 2nd order inverse filter, speech is decimated 4:1 */ -static void ivfilt(float lpbuf[], float ivbuf[], int32_t len, int32_t nsamp, float ivrc[]) -{ - int32_t i; - int32_t j; - int32_t k; - float r[3]; - float pc1; - float pc2; - - /* Calculate autocorrelations */ - for (i = 1; i <= 3; i++) - { - r[i - 1] = 0.0f; - k = (i - 1) << 2; - for (j = (i << 2) + len - nsamp; j <= len; j += 2) - r[i - 1] += lpbuf[j - 1]*lpbuf[j - k - 1]; - } - /* Calculate predictor coefficients */ - pc1 = 0.0f; - pc2 = 0.0f; - ivrc[0] = 0.0f; - ivrc[1] = 0.0f; - if (r[0] > 1.0e-10f) - { - ivrc[0] = r[1]/r[0]; - ivrc[1] = (r[2] - ivrc[0]*r[1])/(r[0] - ivrc[0]*r[1]); - pc1 = ivrc[0] - ivrc[0]*ivrc[1]; - pc2 = ivrc[1]; - } - /* Inverse filter LPBUF into IVBUF */ - for (i = len - nsamp; i < len; i++) - ivbuf[i] = lpbuf[i] - pc1*lpbuf[i - 4] - pc2*lpbuf[i - 8]; -} -/*- End of function --------------------------------------------------------*/ - -void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int32_t *pitch, float *rms, float rc[]) -{ - static const int32_t tau[60] = - { - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, - 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 84, 88, 92, 96, - 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156 - }; - static const int32_t buflim[4] = - { - 181, 720, 25, 720 - }; - static const float precoef = 0.9375f; - - float amdf[60]; - float abuf[LPC10_MIN_PITCH]; - float ivrc[2]; - float temp; - float phi[100] /* was [10][10] */; - float psi[10]; - int32_t half; - int32_t midx; - int32_t ewin[3][2]; - int32_t i; - int32_t j; - int32_t lanal; - int32_t ipitch; - int32_t mintau; - int32_t minptr; - int32_t maxptr; - - /* Calculations are done on future frame due to requirements - of the pitch tracker. Delay RMS and RC's 2 frames to give - current frame parameters on return. */ - - for (i = 0; i <= 720 - LPC10_SAMPLES_PER_FRAME - 181; i++) - { - s->inbuf[i] = s->inbuf[LPC10_SAMPLES_PER_FRAME + i]; - s->pebuf[i] = s->pebuf[LPC10_SAMPLES_PER_FRAME + i]; - } - for (i = 0; i <= 540 - LPC10_SAMPLES_PER_FRAME - 229; i++) - s->ivbuf[i] = s->ivbuf[LPC10_SAMPLES_PER_FRAME + i]; - for (i = 0; i <= 720 - LPC10_SAMPLES_PER_FRAME - 25; i++) - s->lpbuf[i] = s->lpbuf[LPC10_SAMPLES_PER_FRAME + i]; - for (i = 0, j = 0; i < s->osptr - 1; i++) - { - if (s->osbuf[i] > LPC10_SAMPLES_PER_FRAME) - s->osbuf[j++] = s->osbuf[i] - LPC10_SAMPLES_PER_FRAME; - } - s->osptr = j + 1; - s->voibuf[0][0] = s->voibuf[1][0]; - s->voibuf[0][1] = s->voibuf[1][1]; - for (i = 0; i < 2; i++) - { - s->vwin[i][0] = s->vwin[i + 1][0] - LPC10_SAMPLES_PER_FRAME; - s->vwin[i][1] = s->vwin[i + 1][1] - LPC10_SAMPLES_PER_FRAME; - s->awin[i][0] = s->awin[i + 1][0] - LPC10_SAMPLES_PER_FRAME; - s->awin[i][1] = s->awin[i + 1][1] - LPC10_SAMPLES_PER_FRAME; - s->obound[i] = s->obound[i + 1]; - s->voibuf[i + 1][0] = s->voibuf[i + 2][0]; - s->voibuf[i + 1][1] = s->voibuf[i + 2][1]; - s->rmsbuf[i] = s->rmsbuf[i + 1]; - for (j = 0; j < LPC10_ORDER; j++) - s->rcbuf[i][j] = s->rcbuf[i + 1][j]; - } - /* If the average value in the frame was over 1/4096 (after current - BIAS correction), then subtract that much more from samples in the - next frame. If the average value in the frame was under - -1/4096, add 1/4096 more to samples in next frame. In all other - cases, keep BIAS the same. */ - temp = 0.0f; - for (i = 0; i < LPC10_SAMPLES_PER_FRAME; i++) - { - s->inbuf[720 - 2*LPC10_SAMPLES_PER_FRAME + i] = speech[i]*4096.0f - s->bias; - temp += s->inbuf[720 - 2*LPC10_SAMPLES_PER_FRAME + i]; - } - if (temp > (float) LPC10_SAMPLES_PER_FRAME) - s->bias++; - else if (temp < (float) (-LPC10_SAMPLES_PER_FRAME)) - s->bias--; - /* Place voicing window */ - i = 721 - LPC10_SAMPLES_PER_FRAME; - s->zpre = preemp(&s->inbuf[i - 181], &s->pebuf[i - 181], LPC10_SAMPLES_PER_FRAME, precoef, s->zpre); - onset(s, s->pebuf, s->osbuf, &s->osptr, 10, 181, 720, LPC10_SAMPLES_PER_FRAME); - - lpc10_placev(s->osbuf, &s->osptr, 10, &s->obound[2], s->vwin, 3, LPC10_SAMPLES_PER_FRAME, 90, LPC10_MIN_PITCH, 307, 462); - /* The Pitch Extraction algorithm estimates the pitch for a frame - of speech by locating the minimum of the average magnitude difference - function (AMDF). The AMDF operates on low-pass, inverse filtered - speech. (The low-pass filter is an 800 Hz, 19 tap, equiripple, FIR - filter and the inverse filter is a 2nd-order LPC filter.) The pitch - estimate is later refined by dynamic tracking. However, since some - of the tracking parameters are a function of the voicing decisions, - a voicing decision must precede the final pitch estimation. */ - /* See subroutines LPFILT, IVFILT, and eval_highres_amdf. */ - /* LPFILT reads indices LBUFH-LFRAME-29 = 511 through LBUFH = 720 - of INBUF, and writes indices LBUFH+1-LFRAME = 541 through LBUFH - = 720 of LPBUF. */ - lpfilt(&s->inbuf[228], &s->lpbuf[384], 312, LPC10_SAMPLES_PER_FRAME); - /* IVFILT reads indices (PWINH-LFRAME-7) = 353 through PWINH = 540 - of LPBUF, and writes indices (PWINH-LFRAME+1) = 361 through - PWINH = 540 of IVBUF. */ - ivfilt(&s->lpbuf[204], s->ivbuf, 312, LPC10_SAMPLES_PER_FRAME, ivrc); - /* eval_highres_amdf reads indices PWINL = 229 through - (PWINL-1)+MAXWIN+(TAU(LTAU)-TAU(1))/2 = 452 of IVBUF, and writes - indices 1 through LTAU = 60 of AMDF. */ - eval_highres_amdf(s->ivbuf, LPC10_MIN_PITCH, tau, 60, amdf, &minptr, &maxptr, &mintau); - /* Voicing decisions are made for each half frame of input speech. - An initial voicing classification is made for each half of the - analysis frame, and the voicing decisions for the present frame - are finalized. See subroutine VOICIN. */ - /* The voicing detector (VOICIN) classifies the input signal as - unvoiced (including silence) or voiced using the AMDF windowed - maximum-to-minimum ratio, the zero crossing rate, energy measures, - reflection coefficients, and prediction gains. */ - /* The pitch and voicing rules apply smoothing and isolated - corrections to the pitch and voicing estimates and, in the process, - introduce two frames of delay into the corrected pitch estimates and - voicing decisions. */ - for (half = 0; half < 2; half++) - { - lpc10_voicing(s, - &s->vwin[2][0], - s->inbuf, - s->lpbuf, - buflim, - half, - &amdf[minptr], - &amdf[maxptr], - &mintau, - ivrc, - s->obound); - } - /* Find the minimum cost pitch decision over several frames, - given the current voicing decision and the AMDF array */ - minptr++; - dynamic_pitch_tracking(s, amdf, 60, &minptr, s->voibuf[3][1], pitch, &midx); - ipitch = tau[midx - 1]; - /* Place spectrum analysis and energy windows */ - lpc10_placea(&ipitch, s->voibuf, &s->obound[2], 3, s->vwin, s->awin, ewin, LPC10_SAMPLES_PER_FRAME, LPC10_MIN_PITCH); - /* Remove short term DC bias over the analysis window. */ - lanal = s->awin[2][1] + 1 - s->awin[2][0]; - remove_dc_bias(&s->pebuf[s->awin[2][0] - 181], lanal, abuf); - /* Compute RMS over integer number of pitch periods within the analysis window. */ - /* Note that in a hardware implementation this computation may be - simplified by using diagonal elements of phi computed by mload(). */ - s->rmsbuf[2] = energyf(&abuf[ewin[2][0] - s->awin[2][0]], ewin[2][1] - ewin[2][0] + 1); - /* Matrix load and invert, check RC's for stability */ - mload(LPC10_ORDER, 1, lanal, abuf, phi, psi); - invert(LPC10_ORDER, phi, psi, &s->rcbuf[2][0]); - rcchk(LPC10_ORDER, &s->rcbuf[1][0], &s->rcbuf[2][0]); - /* Set return parameters */ - voice[0] = s->voibuf[1][0]; - voice[1] = s->voibuf[1][1]; - *rms = s->rmsbuf[0]; - for (i = 0; i < LPC10_ORDER; i++) - rc[i] = s->rcbuf[0][i]; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_decode.c b/libs/spandsp/src/lpc10_decode.c deleted file mode 100644 index 6b7f7ebb2e..0000000000 --- a/libs/spandsp/src/lpc10_decode.c +++ /dev/null @@ -1,1084 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_decode.c - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the U.S. Department of Defense reference - * implementation of the LPC-10 2400 bps Voice Coder. They do not - * exert copyright claims on their code, and it may be freely used. - */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/lpc10.h" -#include "spandsp/private/lpc10.h" - -#include "lpc10_encdecs.h" - -#if !defined(min) -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#endif -#if !defined(max) -#define max(a,b) ((a) >= (b) ? (a) : (b)) -#endif - -/* Pseudo random number generator based on Knuth, Vol 2, p. 27. */ -/* lpc10_random - int32_t variable, uniformly distributed over -32768 to 32767 */ -static int32_t lpc10_random(lpc10_decode_state_t *s) -{ - int32_t ret_val; - - /* The following is a 16 bit 2's complement addition, - with overflow checking disabled */ - s->y[s->k] += s->y[s->j]; - ret_val = s->y[s->k]; - if (--s->k < 0) - s->k = 4; - if (--s->j < 0) - s->j = 4; - return ret_val; -} -/*- End of function --------------------------------------------------------*/ - -/* Synthesize one pitch epoch */ -static void bsynz(lpc10_decode_state_t *s, - float coef[], - int32_t ip, - int32_t *iv, - float sout[], - float rms, - float ratio, - float g2pass) -{ - static const int32_t kexc[25] = - { - 8, -16, 26, -48, 86, -162, 294, -502, 718, -728, 184, - 672, -610, -672, 184, 728, 718, 502, 294, 162, 86, 48, - 26, 16, 8 - }; - int32_t i; - int32_t j; - int32_t k; - int32_t px; - float noise[LPC10_MIN_PITCH]; - float pulse; - float r1; - float gain; - float xssq; - float sscale; - float xy; - float sum; - float ssq; - float lpi0; - float hpi0; - - /* MAXPIT + MAXORD = 166 */ - /* Calculate history scale factor XY and scale filter state */ - /* Computing MIN */ - r1 = s->rmso_bsynz/(rms + 1.0e-6f); - xy = min(r1, 8.0f); - s->rmso_bsynz = rms; - for (i = 0; i < LPC10_ORDER; i++) - s->exc2[i] = s->exc2[s->ipo + i]*xy; - s->ipo = ip; - if (*iv == 0) - { - /* Generate white noise for unvoiced */ - for (i = 0; i < ip; i++) - s->exc[LPC10_ORDER + i] = (float) (lpc10_random(s)/64); - /* Impulse double excitation for plosives */ - px = (lpc10_random(s) + 32768)*(ip - 1)/65536 + LPC10_ORDER + 1; - r1 = ratio/4.0f; - pulse = r1*342; - if (pulse > 2.0e3f) - pulse = 2.0e3f; - s->exc[px - 1] += pulse; - s->exc[px] -= pulse; - } - else - { - sscale = sqrtf((float) ip)/6.928f; - for (i = 0; i < ip; i++) - { - s->exc[LPC10_ORDER + i] = 0.0f; - if (i < 25) - s->exc[LPC10_ORDER + i] = sscale*kexc[i]; - lpi0 = s->exc[LPC10_ORDER + i]; - s->exc[LPC10_ORDER + i] = s->exc[LPC10_ORDER + i]*0.125f + s->lpi[0]*0.75f + s->lpi[1]*0.125f; - s->lpi[1] = s->lpi[0]; - s->lpi[0] = lpi0; - } - for (i = 0; i < ip; i++) - { - hpi0 = lpc10_random(s)/64.0f; - noise[i] = hpi0*-0.125f + s->hpi[0]*0.25f + s->hpi[1]*-0.125f; - s->hpi[1] = s->hpi[0]; - s->hpi[0] = hpi0; - } - for (i = 0; i < ip; i++) - s->exc[LPC10_ORDER + i] += noise[i]; - } - /* Synthesis filters: */ - /* Modify the excitation with all-zero filter 1 + G*SUM */ - xssq = 0.0f; - for (i = 0; i < ip; i++) - { - k = LPC10_ORDER + i; - sum = 0.0f; - for (j = 0; j < LPC10_ORDER; j++) - sum += coef[j]*s->exc[k - j - 1]; - sum *= g2pass; - s->exc2[k] = sum + s->exc[k]; - } - /* Synthesize using the all pole filter 1/(1 - SUM) */ - for (i = 0; i < ip; i++) - { - k = LPC10_ORDER + i; - sum = 0.0f; - for (j = 0; j < LPC10_ORDER; j++) - sum += coef[j]*s->exc2[k - j - 1]; - s->exc2[k] = sum + s->exc2[k]; - xssq += s->exc2[k]*s->exc2[k]; - } - /* Save filter history for next epoch */ - for (i = 0; i < LPC10_ORDER; i++) - { - s->exc[i] = s->exc[ip + i]; - s->exc2[i] = s->exc2[ip + i]; - } - /* Apply gain to match RMS */ - ssq = rms*rms*ip; - gain = sqrtf(ssq/xssq); - for (i = 0; i < ip; i++) - sout[i] = gain*s->exc2[LPC10_ORDER + i]; -} -/*- End of function --------------------------------------------------------*/ - -/* Synthesize a single pitch epoch */ -static int pitsyn(lpc10_decode_state_t *s, - int voice[2], - int32_t *pitch, - float rms, - float rc[LPC10_ORDER], - int32_t ivuv[16], - int32_t ipiti[16], - float rmsi[16], - float rci[16*LPC10_ORDER], - int32_t *nout, - float *ratio) -{ - int32_t i; - int32_t j; - int32_t vflag; - int32_t jused; - int32_t lsamp; - int32_t ip; - int32_t nl; - int32_t ivoice; - int32_t istart; - float r1; - float alrn; - float alro; - float yarc[10]; - float prop; - float slope; - float uvpit; - float xxy; - float msix; - - if (rms < 1.0f) - rms = 1.0f; - if (s->rmso < 1.0f) - s->rmso = 1.0f; - uvpit = 0.0f; - *ratio = rms/(s->rmso + 8.0f); - if (s->first_pitsyn) - { - ivoice = voice[1]; - if (ivoice == 0) - *pitch = LPC10_SAMPLES_PER_FRAME/4; - *nout = LPC10_SAMPLES_PER_FRAME / *pitch; - s->jsamp = LPC10_SAMPLES_PER_FRAME - *nout * *pitch; - - for (i = 0; i < *nout; i++) - { - for (j = 0; j < LPC10_ORDER; j++) - rci[j + i*LPC10_ORDER] = rc[j]; - ivuv[i] = ivoice; - ipiti[i] = *pitch; - rmsi[i] = rms; - } - s->first_pitsyn = false; - } - else - { - vflag = 0; - lsamp = LPC10_SAMPLES_PER_FRAME + s->jsamp; - *nout = 0; - jused = 0; - istart = 1; - if (voice[0] == s->ivoico && voice[1] == voice[0]) - { - if (voice[1] == 0) - { - /* SSUV - - 0 , 0 , 0 */ - *pitch = LPC10_SAMPLES_PER_FRAME/4; - s->ipito = *pitch; - if (*ratio > 8.0f) - s->rmso = rms; - } - /* SSVC - - 1 , 1 , 1 */ - slope = (*pitch - s->ipito)/(float) lsamp; - ivoice = voice[1]; - } - else - { - if (s->ivoico != 1) - { - if (s->ivoico == voice[0]) - { - /* UV2VC2 - - 0 , 0 , 1 */ - nl = lsamp - LPC10_SAMPLES_PER_FRAME/4; - } - else - { - /* UV2VC1 - - 0 , 1 , 1 */ - nl = lsamp - LPC10_SAMPLES_PER_FRAME*3/4; - } - ipiti[0] = nl/2; - ipiti[1] = nl - ipiti[0]; - ivuv[0] = 0; - ivuv[1] = 0; - rmsi[0] = s->rmso; - rmsi[1] = s->rmso; - for (i = 0; i < LPC10_ORDER; i++) - { - rci[i] = s->rco[i]; - rci[i + LPC10_ORDER] = s->rco[i]; - s->rco[i] = rc[i]; - } - *nout = 2; - s->ipito = *pitch; - jused = nl; - istart = nl + 1; - ivoice = 1; - } - else - { - if (s->ivoico != voice[0]) - { - /* VC2UV1 - - 1 , 0 , 0 */ - lsamp = LPC10_SAMPLES_PER_FRAME/4 + s->jsamp; - } - else - { - /* VC2UV2 - - 1 , 1 , 0 */ - lsamp = LPC10_SAMPLES_PER_FRAME*3/4 + s->jsamp; - } - for (i = 0; i < LPC10_ORDER; i++) - { - yarc[i] = rc[i]; - rc[i] = s->rco[i]; - } - ivoice = 1; - vflag = 1; - } - slope = 0.0f; - } - /* Here is the value of most variables that are used below, depending on */ - /* the values of IVOICO, VOICE(1), and VOICE(2). VOICE(1) and VOICE(2) */ - /* are input arguments, and IVOICO is the value of VOICE(2) on the */ - /* previous call (see notes for the IF (NOUT .NE. 0) statement near the */ - /* end). Each of these three values is either 0 or 1. These three */ - /* values below are given as 3-bit long strings, in the order IVOICO, */ - /* VOICE(1), and VOICE(2). It appears that the code above assumes that */ - /* the bit sequences 010 and 101 never occur, but I wonder whether a */ - /* large enough number of bit errors in the channel could cause such a */ - /* thing to happen, and if so, could that cause NOUT to ever go over 11? */ - - /* Note that all of the 180 values in the table are floatly LFRAME, but */ - /* 180 has fewer characters, and it makes the table a little more */ - /* concrete. If LFRAME is ever changed, keep this in mind. Similarly, */ - /* 135's are 3*LFRAME/4, and 45's are LFRAME/4. If LFRAME is not a */ - /* multiple of 4, then the 135 for NL-JSAMP is actually LFRAME-LFRAME/4, */ - /* and the 45 for NL-JSAMP is actually LFRAME-3*LFRAME/4. */ - - /* Note that LSAMP-JSAMP is given as the variable. This was just for */ - /* brevity, to avoid adding "+JSAMP" to all of the column entries. */ - /* Similarly for NL-JSAMP. */ - - /* Variable | 000 001 011,010 111 110 100,101 */ - /* ------------+-------------------------------------------------- */ - /* ISTART | 1 NL+1 NL+1 1 1 1 */ - /* LSAMP-JSAMP | 180 180 180 180 135 45 */ - /* IPITO | 45 PITCH PITCH oldPITCH oldPITCH oldPITCH */ - /* SLOPE | 0 0 0 seebelow 0 0 */ - /* JUSED | 0 NL NL 0 0 0 */ - /* PITCH | 45 PITCH PITCH PITCH PITCH PITCH */ - /* NL-JSAMP | -- 135 45 -- -- -- */ - /* VFLAG | 0 0 0 0 1 1 */ - /* NOUT | 0 2 2 0 0 0 */ - /* IVOICE | 0 1 1 1 1 1 */ - - /* while_loop | once once once once twice twice */ - - /* ISTART | -- -- -- -- JUSED+1 JUSED+1 */ - /* LSAMP-JSAMP | -- -- -- -- 180 180 */ - /* IPITO | -- -- -- -- oldPITCH oldPITCH */ - /* SLOPE | -- -- -- -- 0 0 */ - /* JUSED | -- -- -- -- ?? ?? */ - /* PITCH | -- -- -- -- PITCH PITCH */ - /* NL-JSAMP | -- -- -- -- -- -- */ - /* VFLAG | -- -- -- -- 0 0 */ - /* NOUT | -- -- -- -- ?? ?? */ - /* IVOICE | -- -- -- -- 0 0 */ - - /* 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 - (PITCH-IPITO)/FLOAT(LSAMP) */ - - /* Column 101 is identical to 100. Any good properties we can prove - for 100 will also hold for 101. Similarly for 010 and 011. */ - - /* synths() calls this subroutine with PITCH restricted to the range 20 to - 156. IPITO is similarly restricted to this range, after the first - call. IP below is also restricted to this range, given the - definitions of IPITO, SLOPE, UVPIT, and that I is in the range ISTART - to LSAMP. */ - - for (;;) - { - for (i = istart; i <= lsamp; i++) - { - r1 = s->ipito + slope*i; - ip = (int32_t) (r1 + 0.5f); - if (uvpit != 0.0f) - ip = (int32_t) uvpit; - if (ip <= i - jused) - { - ipiti[*nout] = ip; - *pitch = ip; - ivuv[*nout] = ivoice; - jused += ip; - prop = (jused - ip/2)/(float) lsamp; - for (j = 0; j < LPC10_ORDER; j++) - { - alro = logf((s->rco[j] + 1)/(1 - s->rco[j])); - alrn = logf((rc[j] + 1)/(1 - rc[j])); - xxy = alro + prop*(alrn - alro); - xxy = expf(xxy); - rci[j + *nout*LPC10_ORDER] = (xxy - 1.0f)/(xxy + 1.0f); - } - msix = logf(rms) - logf(s->rmso); - msix = prop*msix; - msix = logf(s->rmso) + msix; - rmsi[*nout] = expf(msix); - (*nout)++; - } - } - if (vflag != 1) - break; - - vflag = 0; - istart = jused + 1; - lsamp = LPC10_SAMPLES_PER_FRAME + s->jsamp; - slope = 0.0f; - ivoice = 0; - uvpit = (float) ((lsamp - istart)/2); - if (uvpit > 90.0f) - uvpit /= 2; - s->rmso = rms; - for (i = 0; i < LPC10_ORDER; i++) - { - rc[i] = yarc[i]; - s->rco[i] = yarc[i]; - } - } - s->jsamp = lsamp - jused; - } - if (*nout != 0) - { - s->ivoico = voice[1]; - s->ipito = *pitch; - s->rmso = rms; - for (i = 0; i < LPC10_ORDER; i++) - s->rco[i] = rc[i]; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void deemp(lpc10_decode_state_t *s, float x[], int len) -{ - int i; - float r1; - float dei0; - - for (i = 0; i < len; i++) - { - dei0 = x[i]; - r1 = x[i] - s->dei[0]*1.9998f + s->dei[1]; - x[i] = r1 + s->deo[0]*2.5f - s->deo[1]*2.0925f + s->deo[2]*0.585f; - s->dei[1] = s->dei[0]; - s->dei[0] = dei0; - s->deo[2] = s->deo[1]; - s->deo[1] = s->deo[0]; - s->deo[0] = x[i]; - } -} -/*- End of function --------------------------------------------------------*/ - -/* Convert reflection coefficients to predictor coefficients */ -static float reflection_coeffs_to_predictor_coeffs(float rc[], float pc[], float gprime) -{ - float temp[10]; - float g2pass; - int i; - int j; - - g2pass = 1.0f; - for (i = 0; i < LPC10_ORDER; i++) - g2pass *= 1.0f - rc[i]*rc[i]; - g2pass = gprime*sqrtf(g2pass); - pc[0] = rc[0]; - for (i = 1; i < LPC10_ORDER; i++) - { - for (j = 0; j < i; j++) - temp[j] = pc[j] - rc[i]*pc[i - j - 1]; - for (j = 0; j < i; j++) - pc[j] = temp[j]; - pc[i] = rc[i]; - } - return g2pass; -} -/*- End of function --------------------------------------------------------*/ - -static int synths(lpc10_decode_state_t *s, - int voice[2], - int32_t *pitch, - float rms, - float rc[LPC10_ORDER], - float speech[]) -{ - int32_t ivuv[16]; - int32_t ipiti[16]; - int32_t nout; - int32_t i; - int32_t j; - float rmsi[16]; - float ratio; - float g2pass; - float pc[LPC10_ORDER]; - float rci[16*LPC10_ORDER]; - - *pitch = max(min(*pitch, LPC10_MIN_PITCH), LPC10_MAX_PITCH); - for (i = 0; i < LPC10_ORDER; i++) - rc[i] = max(min(rc[i], 0.99f), -0.99f); - pitsyn(s, voice, pitch, rms, rc, ivuv, ipiti, rmsi, rci, &nout, &ratio); - if (nout > 0) - { - for (j = 0; j < nout; j++) - { - /* Add synthesized speech for pitch period J to the end of s->buf. */ - g2pass = reflection_coeffs_to_predictor_coeffs(&rci[j*LPC10_ORDER], pc, 0.7f); - bsynz(s, pc, ipiti[j], &ivuv[j], &s->buf[s->buflen], rmsi[j], ratio, g2pass); - deemp(s, &s->buf[s->buflen], ipiti[j]); - s->buflen += ipiti[j]; - } - /* Copy first MAXFRM samples from BUF to output array speech (scaling them), - and then remove them from the beginning of s->buf. */ - for (i = 0; i < LPC10_SAMPLES_PER_FRAME; i++) - speech[i] = s->buf[i]/4096.0f; - s->buflen -= LPC10_SAMPLES_PER_FRAME; - for (i = 0; i < s->buflen; i++) - s->buf[i] = s->buf[i + LPC10_SAMPLES_PER_FRAME]; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void lpc10_unpack(lpc10_frame_t *t, const uint8_t ibits[]) -{ - static const int bit[10] = - { - 2, 4, 8, 8, 8, 8, 16, 16, 16, 16 - }; - static const int iblist[53] = - { - 13, 12, 11, 1, 2, 13, 12, 11, 1, 2, - 13, 10, 11, 2, 1, 10, 13, 12, 11, 10, - 2, 13, 12, 11, 10, 2, 1, 12, 7, 6, - 1, 10, 9, 8, 7, 4, 6, 9, 8, 7, - 5, 1, 9, 8, 4, 6, 1, 5, 9, 8, - 7, 5, 6 - }; - int32_t itab[13]; - int x; - int i; - - /* ibits is 54 bits of LPC data ordered as follows: */ - /* R1-0, R2-0, R3-0, P-0, A-0, */ - /* R1-1, R2-1, R3-1, P-1, A-1, */ - /* R1-2, R4-0, R3-2, A-2, P-2, R4-1, */ - /* R1-3, R2-2, R3-3, R4-2, A-3, */ - /* R1-4, R2-3, R3-4, R4-3, A-4, */ - /* P-3, R2-4, R7-0, R8-0, P-4, R4-4, */ - /* R5-0, R6-0, R7-1,R10-0, R8-1, */ - /* R5-1, R6-1, R7-2, R9-0, P-5, */ - /* R5-2, R6-2,R10-1, R8-2, P-6, R9-1, */ - /* R5-3, R6-3, R7-3, R9-2, R8-3, SYNC */ - - /* Reconstruct ITAB */ - for (i = 0; i < 13; i++) - itab[i] = 0; - for (i = 0; i < 53; i++) - { - x = 52 - i; - x = (ibits[x >> 3] >> (7 - (x & 7))) & 1; - itab[iblist[52 - i] - 1] = (itab[iblist[52 - i] - 1] << 1) | x; - } - /* Sign extend the RC's */ - for (i = 0; i < LPC10_ORDER; i++) - { - if ((itab[i + 3] & bit[i])) - itab[i + 3] -= (bit[i] << 1); - } - /* Restore variables */ - t->ipitch = itab[0]; - t->irms = itab[1]; - for (i = 0; i < LPC10_ORDER; i++) - t->irc[i] = itab[LPC10_ORDER - 1 - i + 3]; -} -/*- End of function --------------------------------------------------------*/ - -/* Hamming 8, 4 decoder - can correct 1 out of seven bits - and can detect up to two errors. */ - -/* This subroutine is entered with an eight bit word in INPUT. The 8th */ -/* bit is parity and is stripped off. The remaining 7 bits address the */ -/* hamming 8, 4 table and the output OUTPUT from the table gives the 4 */ -/* bits of corrected data. If bit 4 is set, no error was detected. */ -/* ERRCNT is the number of errors counted. */ - -static int32_t hamming_84_decode(int32_t input, int *errcnt) -{ - static const uint8_t dactab[128] = - { - 16, 0, 0, 3, 0, 5, 14, 7, 0, 9, 14, 11, 14, 13, 30, 14, - 0, 9, 2, 7, 4, 7, 7, 23, 9, 25, 10, 9, 12, 9, 14, 7, - 0, 5, 2, 11, 5, 21, 6, 5, 8, 11, 11, 27, 12, 5, 14, 11, - 2, 1, 18, 2, 12, 5, 2, 7, 12, 9, 2, 11, 28, 12, 12, 15, - 0, 3, 3, 19, 4, 13, 6, 3, 8, 13, 10, 3, 13, 29, 14, 13, - 4, 1, 10, 3, 20, 4, 4, 7, 10, 9, 26, 10, 4, 13, 10, 15, - 8, 1, 6, 3, 6, 5, 22, 6, 24, 8, 8, 11, 8, 13, 6, 15, - 1, 17 , 2, 1, 4, 1, 6, 15, 8, 1, 10, 15, 12, 15, 15, 31 - }; - int i; - int parity; - int32_t output; - - parity = input & 255; - parity ^= parity >> 4; - parity ^= parity >> 2; - parity ^= parity >> 1; - parity &= 1; - i = dactab[input & 127]; - output = i & 15; - if ((i & 16)) - { - /* No errors detected in seven bits */ - if (parity) - (*errcnt)++; - } - else - { - /* One or two errors detected */ - (*errcnt)++; - if (parity == 0) - { - /* Two errors detected */ - (*errcnt)++; - output = -1; - } - } - return output; -} -/*- End of function --------------------------------------------------------*/ - -static int32_t median(int32_t d1, int32_t d2, int32_t d3) -{ - int32_t ret_val; - - ret_val = d2; - if (d2 > d1 && d2 > d3) - { - ret_val = d1; - if (d3 > d1) - ret_val = d3; - } - else if (d2 < d1 && d2 < d3) - { - ret_val = d1; - if (d3 < d1) - ret_val = d3; - } - return ret_val; -} -/*- End of function --------------------------------------------------------*/ - -static void decode(lpc10_decode_state_t *s, - lpc10_frame_t *t, - int voice[2], - int32_t *pitch, - float *rms, - float rc[]) -{ - static const int32_t ivtab[32] = - { - 24960, 24960, 24960, 24960, 25480, 25480, 25483, 25480, - 16640, 1560, 1560, 1560, 16640, 1816, 1563, 1560, - 24960, 24960, 24859, 24856, 26001, 25881, 25915, 25913, - 1560, 1560, 7800, 3640, 1561, 1561, 3643, 3641 - }; - static const float corth[32] = - { - 32767.0f, 10.0f, 5.0f, 0.0f, 32767.0f, 8.0f, 4.0f, 0.0f, - 32.0f, 6.4f, 3.2f, 0.0f, 32.0f, 6.4f, 3.2f, 0.0f, - 32.0f, 11.2f, 6.4f, 0.0f, 32.0f, 11.2f, 6.4f, 0.0f, - 16.0f, 5.6f, 3.2f, 0.0f, 16.0f, 5.6f, 3.2f, 0.0f - }; - static const int32_t detau[128] = - { - 0, 0, 0, 3, 0, 3, 3, 31, - 0, 3, 3, 21, 3, 3, 29, 30, - 0, 3, 3, 20, 3, 25, 27, 26, - 3, 23, 58, 22, 3, 24, 28, 3, - 0, 3, 3, 3, 3, 39, 33, 32, - 3, 37, 35, 36, 3, 38, 34, 3, - 3, 42, 46, 44, 50, 40, 48, 3, - 54, 3, 56, 3, 52, 3, 3, 1, - 0, 3, 3, 108, 3, 78, 100, 104, - 3, 84, 92, 88, 156, 80, 96, 3, - 3, 74, 70, 72, 66, 76, 68, 3, - 62, 3, 60, 3, 64, 3, 3, 1, - 3, 116, 132, 112, 148, 152, 3, 3, - 140, 3, 136, 3, 144, 3, 3, 1, - 124, 120, 128, 3, 3, 3, 3, 1, - 3, 3, 3, 1, 3, 1, 1, 1 - }; - static const int32_t rmst[64] = - { - 1024, 936, 856, 784, 718, 656, 600, 550, - 502, 460, 420, 384, 352, 328, 294, 270, - 246, 226, 206, 188, 172, 158, 144, 132, - 120, 110, 102, 92, 84, 78, 70, 64, - 60, 54, 50, 46, 42, 38, 34, 32, - 30, 26, 24, 22, 20, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - }; - static const int32_t detab7[32] = - { - 4, 11, 18, 25, 32, 39, 46, 53, - 60, 66, 72, 77, 82, 87, 92, 96, - 101, 104, 108, 111, 114, 115, 117, 119, - 121, 122, 123, 124, 125, 126, 127, 127 - }; - static const float descl[8] = - { - 0.6953f, 0.625f, 0.5781f, 0.5469f, 0.5312f, 0.5391f, 0.4688f, 0.3828f - }; - static const int32_t deadd[8] = - { - 1152, -2816, -1536, -3584, -1280, -2432, 768, -1920 - }; - static const int32_t qb[8] = - { - 511, 511, 1023, 1023, 1023, 1023, 2047, 4095 - }; - static const int32_t nbit[10] = - { - 8, 8, 5, 5, 4, 4, 4, 4, 3, 2 - }; - static const int32_t zrc[10] = - { - 0, 0, 0, 0, 0, 3, 0, 2, 0, 0 - }; - static const int32_t bit[5] = - { - 2, 4, 8, 16, 32 - }; - int32_t ipit; - int32_t iout; - int32_t i; - int32_t icorf; - int32_t index; - int32_t ivoic; - int32_t ixcor; - int32_t i1; - int32_t i2; - int32_t i4; - int32_t ishift; - int32_t lsb; - int errcnt; - - /* If no error correction, do pitch and voicing then jump to decode */ - i4 = detau[t->ipitch]; - if (!s->error_correction) - { - voice[0] = 1; - voice[1] = 1; - if (t->ipitch <= 1) - voice[0] = 0; - if (t->ipitch == 0 || t->ipitch == 2) - voice[1] = 0; - if (i4 <= 4) - i4 = s->iptold; - *pitch = i4; - if (voice[0] == 1 && voice[1] == 1) - s->iptold = *pitch; - if (voice[0] != voice[1]) - *pitch = s->iptold; - } - else - { - /* Do error correction pitch and voicing */ - if (i4 > 4) - { - s->dpit[0] = i4; - ivoic = 2; - s->iavgp = (s->iavgp*15 + i4 + 8)/16; - } - else - { - s->dpit[0] = s->iavgp; - ivoic = i4; - } - s->drms[0] = t->irms; - for (i = 0; i < LPC10_ORDER; i++) - s->drc[i][0] = t->irc[i]; - /* Determine index to IVTAB from V/UV decision */ - /* If error rate is high then use alternate table */ - index = (s->ivp2h << 4) + (s->iovoic << 2) + ivoic + 1; - i1 = ivtab[index - 1]; - ipit = i1 & 3; - icorf = i1 >> 3; - if (s->erate < 2048) - icorf /= 64; - /* Determine error rate: 4=high 1=low */ - ixcor = 4; - if (s->erate < 2048) - ixcor = 3; - if (s->erate < 1024) - ixcor = 2; - if (s->erate < 128) - ixcor = 1; - /* Voice/unvoice decision determined from bits 0 and 1 of IVTAB */ - voice[0] = icorf/2 & 1; - voice[1] = icorf & 1; - /* Skip decoding on first frame because present data not yet available */ - if (s->first) - { - 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 */ - /* reasonable thing to do for the first call. */ - if (i4 <= 4) - i4 = s->iptold; - *pitch = i4; - } - else - { - /* If bit 4 of ICORF is set then correct RMS and RC(1) - RC(4). */ - /* Determine error rate and correct errors using a Hamming 8,4 code */ - /* during transition of unvoiced frames. If IOUT is negative, */ - /* more than 1 error occurred, use previous frame's parameters. */ - if ((icorf & bit[3]) != 0) - { - errcnt = 0; - lsb = s->drms[1] & 1; - index = (s->drc[7][1] << 4) + s->drms[1]/2; - iout = hamming_84_decode(index, &errcnt); - s->drms[1] = s->drms[2]; - if (iout >= 0) - s->drms[1] = (iout << 1) + lsb; - for (i = 1; i <= 4; i++) - { - if (i == 1) - i1 = ((s->drc[8][1] & 7) << 1) + (s->drc[9][1] & 1); - else - i1 = s->drc[8 - i][1] & 15; - i2 = s->drc[4 - i][1] & 31; - lsb = i2 & 1; - index = (i1 << 4) + (i2 >> 1); - iout = hamming_84_decode(index, &errcnt); - if (iout >= 0) - { - iout = (iout << 1) + lsb; - if ((iout & 16) == 16) - iout -= 32; - } - else - { - iout = s->drc[4 - i][2]; - } - s->drc[4 - i][1] = iout; - } - /* Determine error rate */ - s->erate = (int32_t) (s->erate*0.96875f + errcnt*102.0f); - } - /* Get unsmoothed RMS, RC's, and PITCH */ - t->irms = s->drms[1]; - for (i = 0; i < LPC10_ORDER; i++) - t->irc[i] = s->drc[i][1]; - if (ipit == 1) - s->dpit[1] = s->dpit[2]; - if (ipit == 3) - s->dpit[1] = s->dpit[0]; - *pitch = s->dpit[1]; - /* If bit 2 of ICORF is set then smooth RMS and RC's, */ - if ((icorf & bit[1]) != 0) - { - if ((float) abs(s->drms[1] - s->drms[0]) >= corth[ixcor + 3] - && - (float) abs(s->drms[1] - s->drms[2]) >= corth[ixcor + 3]) - { - t->irms = median(s->drms[2], s->drms[1], s->drms[0]); - } - for (i = 0; i < 6; i++) - { - if ((float) abs(s->drc[i][1] - s->drc[i][0]) >= corth[ixcor + ((i + 3) << 2) - 5] - && - (float) abs(s->drc[i][1] - s->drc[i][2]) >= corth[ixcor + ((i + 3) << 2) - 5]) - { - t->irc[i] = median(s->drc[i][2], s->drc[i][1], s->drc[i][0]); - } - } - } - /* If bit 3 of ICORF is set then smooth pitch */ - if ((icorf & bit[2]) != 0) - { - if ((float) abs(s->dpit[1] - s->dpit[0]) >= corth[ixcor - 1] - && - (float) abs(s->dpit[1] - s->dpit[2]) >= corth[ixcor - 1]) - { - *pitch = median(s->dpit[2], s->dpit[1], s->dpit[0]); - } - } - /* If bit 5 of ICORF is set then RC(5) - RC(10) are loaded with - values so that after quantization bias is removed in decode - the values will be zero. */ - } - if ((icorf & bit[4]) != 0) - { - for (i = 4; i < LPC10_ORDER; i++) - t->irc[i] = zrc[i]; - } - /* Housekeeping - one frame delay */ - s->iovoic = ivoic; - s->ivp2h = voice[1]; - s->dpit[2] = s->dpit[1]; - s->dpit[1] = s->dpit[0]; - s->drms[2] = s->drms[1]; - s->drms[1] = s->drms[0]; - for (i = 0; i < LPC10_ORDER; i++) - { - s->drc[i][2] = s->drc[i][1]; - s->drc[i][1] = s->drc[i][0]; - } - } - /* Decode RMS */ - t->irms = rmst[(31 - t->irms)*2]; - /* Decode RC(1) and RC(2) from log-area-ratios */ - /* Protect from illegal coded value (-16) caused by bit errors */ - for (i = 0; i < 2; i++) - { - i2 = t->irc[i]; - i1 = 0; - if (i2 < 0) - { - i1 = 1; - i2 = -i2; - if (i2 > 15) - i2 = 0; - } - i2 = detab7[i2*2]; - if (i1 == 1) - i2 = -i2; - ishift = 15 - nbit[i]; - t->irc[i] = i2*pow_ii(2, ishift); - } - /* Decode RC(3)-RC(10) to sign plus 14 bits */ - for (i = 2; i < LPC10_ORDER; i++) - { - ishift = 15 - nbit[i]; - i2 = t->irc[i]*pow_ii(2, ishift) + qb[i - 2]; - t->irc[i] = (int32_t) (i2*descl[i - 2] + deadd[i - 2]); - } - /* Scale RMS and RC's to floats */ - *rms = (float) t->irms; - for (i = 0; i < LPC10_ORDER; i++) - rc[i] = t->irc[i]/16384.0f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(lpc10_decode_state_t *) lpc10_decode_init(lpc10_decode_state_t *s, int error_correction) -{ - static const int16_t rand_init[] = - { - -21161, - -8478, - 30892, - -10216, - 16950 - }; - int i; - int j; - - if (s == NULL) - { - if ((s = (lpc10_decode_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - - s->error_correction = error_correction; - - /* State used by function decode */ - s->iptold = 60; - s->first = true; - s->ivp2h = 0; - s->iovoic = 0; - s->iavgp = 60; - s->erate = 0; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 10; j++) - s->drc[j][i] = 0; - s->dpit[i] = 0; - s->drms[i] = 0; - } - - /* State used by function synths */ - for (i = 0; i < 360; i++) - s->buf[i] = 0.0f; - s->buflen = LPC10_SAMPLES_PER_FRAME; - - /* State used by function pitsyn */ - s->rmso = 1.0f; - s->first_pitsyn = true; - - /* State used by function bsynz */ - s->ipo = 0; - for (i = 0; i < 166; i++) - { - s->exc[i] = 0.0f; - s->exc2[i] = 0.0f; - } - for (i = 0; i < 3; i++) - { - s->lpi[i] = 0.0f; - s->hpi[i] = 0.0f; - } - s->rmso_bsynz = 0.0f; - - /* State used by function lpc10_random */ - s->j = 1; - s->k = 4; - for (i = 0; i < 5; i++) - s->y[i] = rand_init[i]; - - /* State used by function deemp */ - for (i = 0; i < 2; i++) - s->dei[i] = 0.0f; - for (i = 0; i < 3; i++) - s->deo[i] = 0.0f; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lpc10_decode_release(lpc10_decode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lpc10_decode_free(lpc10_decode_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lpc10_decode(lpc10_decode_state_t *s, int16_t amp[], const uint8_t code[], int len) -{ - int voice[2]; - int32_t pitch; - float speech[LPC10_SAMPLES_PER_FRAME]; - float rc[LPC10_ORDER]; - lpc10_frame_t frame; - float rms; - int i; - int j; - int base; - - /* Decode 54 bits in 7 bytes to LPC10_SAMPLES_PER_FRAME speech samples. */ - len /= 7; - for (i = 0; i < len; i++) - { - lpc10_unpack(&frame, &code[i*7]); - decode(s, &frame, voice, &pitch, &rms, rc); - synths(s, voice, &pitch, rms, rc, speech); - base = i*LPC10_SAMPLES_PER_FRAME; - for (j = 0; j < LPC10_SAMPLES_PER_FRAME; j++) - amp[base + j] = (int16_t) lfastrintf(32768.0f*speech[j]); - } - - return len*LPC10_SAMPLES_PER_FRAME; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_encdecs.h b/libs/spandsp/src/lpc10_encdecs.h deleted file mode 100644 index f8aa85c2eb..0000000000 --- a/libs/spandsp/src/lpc10_encdecs.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_encdecs.h - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -#define LPC10_ORDER 10 -#define LPC10_MAX_PITCH 20 -#define LPC10_MIN_PITCH 156 - -#if !defined(min) -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#endif -#if !defined(max) -#define max(a,b) ((a) >= (b) ? (a) : (b)) -#endif - -void lpc10_placea(int32_t *ipitch, - int32_t voibuf[4][2], - int32_t *obound, - int32_t af, - int32_t vwin[3][2], - int32_t awin[3][2], - int32_t ewin[3][2], - int32_t lframe, - int32_t maxwin); - -void lpc10_placev(int32_t *osbuf, - int32_t *osptr, - int32_t oslen, - int32_t *obound, - int32_t vwin[3][2], - int32_t af, - int32_t lframe, - int32_t minwin, - int32_t maxwin, - int32_t dvwinl, - int32_t dvwinh); - -void lpc10_voicing(lpc10_encode_state_t *st, - int32_t *vwin, - float *inbuf, - float *lpbuf, - const int32_t buflim[], - int32_t half, - float *minamd, - float *maxamd, - int32_t *mintau, - float *ivrc, - int32_t *obound); - -void lpc10_analyse(lpc10_encode_state_t *st, float *speech, int32_t *voice, int32_t *pitch, float *rms, float rc[]); - -static __inline__ int32_t pow_ii(int32_t x, int32_t n) -{ - int32_t pow; - uint32_t u; - - if (n <= 0) - { - if (n == 0 || x == 1) - return 1; - if (x != -1) - return (x != 0) ? 1/x : 0; - n = -n; - } - u = n; - for (pow = 1; ; ) - { - if ((u & 1)) - pow *= x; - if ((u >>= 1) == 0) - break; - x *= x; - } - return pow; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ float r_sign(float a, float b) -{ - float x; - - x = fabsf(a); - return (b >= 0.0f) ? x : -x; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_encode.c b/libs/spandsp/src/lpc10_encode.c deleted file mode 100644 index 27bf10c9b1..0000000000 --- a/libs/spandsp/src/lpc10_encode.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_encode.c - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the U.S. Department of Defense reference - * implementation of the LPC-10 2400 bps Voice Coder. They do not - * exert copyright claims on their code, and it may be freely used. - */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/lpc10.h" -#include "spandsp/private/lpc10.h" - -#include "lpc10_encdecs.h" - -static void lpc10_pack(lpc10_encode_state_t *s, uint8_t ibits[], lpc10_frame_t *t) -{ - static const int iblist[53] = - { - 13, 12, 11, 1, 2, 13, 12, 11, 1, 2, - 13, 10, 11, 2, 1, 10, 13, 12, 11, 10, - 2, 13, 12, 11, 10, 2, 1, 12, 7, 6, - 1, 10, 9, 8, 7, 4, 6, 9, 8, 7, - 5, 1, 9, 8, 4, 6, 1, 5, 9, 8, - 7, 5, 6 - }; - int32_t itab[13]; - int x; - int i; - - /* ibits is 54 bits of LPC data ordered as follows: */ - /* R1-0, R2-0, R3-0, P-0, A-0, */ - /* R1-1, R2-1, R3-1, P-1, A-1, */ - /* R1-2, R4-0, R3-2, A-2, P-2, R4-1, */ - /* R1-3, R2-2, R3-3, R4-2, A-3, */ - /* R1-4, R2-3, R3-4, R4-3, A-4, */ - /* P-3, R2-4, R7-0, R8-0, P-4, R4-4, */ - /* R5-0, R6-0, R7-1,R10-0, R8-1, */ - /* R5-1, R6-1, R7-2, R9-0, P-5, */ - /* R5-2, R6-2,R10-1, R8-2, P-6, R9-1, */ - /* R5-3, R6-3, R7-3, R9-2, R8-3, SYNC */ - - itab[0] = t->ipitch; - itab[1] = t->irms; - itab[2] = 0; - for (i = 0; i < LPC10_ORDER; i++) - itab[i + 3] = t->irc[LPC10_ORDER - 1 - i] & 0x7FFF; - /* Put 54 bits into the output buffer */ - x = 0; - for (i = 0; i < 53; i++) - { - x = (x << 1) | (itab[iblist[i] - 1] & 1); - if ((i & 7) == 7) - ibits[i >> 3] = (uint8_t) (x & 0xFF); - itab[iblist[i] - 1] >>= 1; - } - x = (x << 1) | (s->isync & 1); - s->isync ^= 1; - x <<= 2; - ibits[6] = (uint8_t) (x & 0xFF); -} -/*- End of function --------------------------------------------------------*/ - -/* Quantize LPC parameters for transmission */ -static int encode(lpc10_encode_state_t *s, - lpc10_frame_t *t, - int32_t *voice, - int32_t pitch, - float rms, - float *rc) -{ - static const int32_t enctab[16] = - { - 0, 7, 11, 12, 13, 10, 6, 1, 14, 9, 5, 2, 3, 4, 8, 15 - }; - static const int32_t entau[60] = - { - 19, 11, 27, 25, 29, 21, 23, 22, 30, 14, 15, 7, 39, 38, 46, - 42, 43, 41, 45, 37, 53, 49, 51, 50, 54, 52, 60, 56, 58, 26, - 90, 88, 92, 84, 86, 82, 83, 81, 85, 69, 77, 73, 75, 74, 78, - 70, 71, 67, 99, 97, 113, 112, 114, 98, 106, 104, 108, 100, 101, 76 - }; - static const int32_t enadd[8] = - { - 1920, -768, 2432, 1280, 3584, 1536, 2816, -1152 - }; - static const float enscl[8] = - { - 0.0204f, 0.0167f, 0.0145f, 0.0147f, 0.0143f, 0.0135f, 0.0125f, 0.0112f - }; - static const int32_t enbits[8] = - { - 6, 5, 4, 4, 4, 4, 3, 3 - }; - static const int32_t entab6[64] = - { - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 13, 14, 15 - }; - static const int32_t rmst[64] = - { - 1024, 936, 856, 784, 718, 656, 600, 550, - 502, 460, 420, 384, 352, 328, 294, 270, - 246, 226, 206, 188, 172, 158, 144, 132, - 120, 110, 102, 92, 84, 78, 70, 64, - 60, 54, 50, 46, 42, 38, 34, 32, - 30, 26, 24, 22, 20, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 - }; - - int32_t idel; - int32_t nbit; - int32_t i; - int32_t j; - int32_t i2; - int32_t i3; - int32_t mrk; - - /* Scale RMS and RC's to int32_ts */ - t->irms = (int32_t) rms; - for (i = 0; i < LPC10_ORDER; i++) - t->irc[i] = (int32_t) (rc[i]*32768.0f); - if (voice[0] != 0 && voice[1] != 0) - { - t->ipitch = entau[pitch - 1]; - } - else - { - if (s->error_correction) - { - t->ipitch = 0; - if (voice[0] != voice[1]) - t->ipitch = 127; - } - else - { - t->ipitch = (voice[0] << 1) + voice[1]; - } - } - /* Encode RMS by binary table search */ - j = 32; - idel = 16; - t->irms = min(t->irms, 1023); - while (idel > 0) - { - if (t->irms > rmst[j - 1]) - j -= idel; - if (t->irms < rmst[j - 1]) - j += idel; - idel /= 2; - } - if (t->irms > rmst[j - 1]) - --j; - t->irms = 31 - j/2; - /* Encode RC(1) and (2) as log-area-ratios */ - for (i = 0; i < 2; i++) - { - i2 = t->irc[i]; - mrk = 0; - if (i2 < 0) - { - i2 = -i2; - mrk = 1; - } - i2 = min(i2/512, 63); - i2 = entab6[i2]; - if (mrk != 0) - i2 = -i2; - t->irc[i] = i2; - } - /* Encode RC(3) - (10) linearly, remove bias then scale */ - for (i = 2; i < LPC10_ORDER; i++) - { - i2 = (int32_t) ((t->irc[i]/2 + enadd[LPC10_ORDER - 1 - i])*enscl[LPC10_ORDER - 1 - i]); - i2 = max(i2, -127); - i2 = min(i2, 127); - nbit = enbits[LPC10_ORDER - 1 - i]; - i3 = (i2 < 0); - i2 /= pow_ii(2, nbit); - if (i3) - i2--; - t->irc[i] = i2; - } - /* Protect the most significant bits of the most - important parameters during non-voiced frames. - RC(1) - RC(4) are protected using 20 parity bits - replacing RC(5) - RC(10). */ - if (s->error_correction) - { - if (t->ipitch == 0 || t->ipitch == 127) - { - t->irc[4] = enctab[(t->irc[0] & 0x1E) >> 1]; - t->irc[5] = enctab[(t->irc[1] & 0x1E) >> 1]; - t->irc[6] = enctab[(t->irc[2] & 0x1E) >> 1]; - t->irc[7] = enctab[(t->irms & 0x1E) >> 1]; - t->irc[8] = enctab[(t->irc[3] & 0x1E) >> 1] >> 1; - t->irc[9] = enctab[(t->irc[3] & 0x1E) >> 1] & 1; - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void high_pass_100hz(lpc10_encode_state_t *s, float speech[], int start, int len) -{ - float si; - float err; - int i; - - /* 100 Hz high pass filter */ - for (i = start; i < len; i++) - { - si = speech[i]; - err = si + s->z11*1.859076f - s->z21*0.8648249f; - si = err - s->z11*2.0f + s->z21; - s->z21 = s->z11; - s->z11 = err; - err = si + s->z12*1.935715f - s->z22*0.9417004f; - si = err - s->z12*2.0f + s->z22; - s->z22 = s->z12; - s->z12 = err; - speech[i] = si*0.902428f; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(lpc10_encode_state_t *) lpc10_encode_init(lpc10_encode_state_t *s, int error_correction) -{ - int i; - int j; - - if (s == NULL) - { - if ((s = (lpc10_encode_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - - s->error_correction = error_correction; - - /* State used only by function high_pass_100hz */ - s->z11 = 0.0f; - s->z21 = 0.0f; - s->z12 = 0.0f; - s->z22 = 0.0f; - - /* State used by function lpc10_analyse */ - for (i = 0; i < 540; i++) - { - s->inbuf[i] = 0.0f; - s->pebuf[i] = 0.0f; - } - for (i = 0; i < 696; i++) - s->lpbuf[i] = 0.0f; - for (i = 0; i < 312; i++) - s->ivbuf[i] = 0.0f; - s->bias = 0.0f; - s->osptr = 1; - for (i = 0; i < 3; i++) - s->obound[i] = 0; - s->vwin[2][0] = 307; - s->vwin[2][1] = 462; - s->awin[2][0] = 307; - s->awin[2][1] = 462; - for (i = 0; i < 4; i++) - { - s->voibuf[i][0] = 0; - s->voibuf[i][1] = 0; - } - for (i = 0; i < 3; i++) - s->rmsbuf[i] = 0.0f; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 10; j++) - s->rcbuf[i][j] = 0.0f; - } - s->zpre = 0.0f; - - /* State used by function onset */ - s->n = 0.0f; - s->d__ = 1.0f; - for (i = 0; i < 16; i++) - s->l2buf[i] = 0.0f; - s->l2sum1 = 0.0f; - s->l2ptr1 = 1; - s->l2ptr2 = 9; - s->hyst = false; - - /* State used by function lpc10_voicing */ - s->dither = 20.0f; - s->maxmin = 0.0f; - for (i = 0; i < 3; i++) - { - s->voice[i][0] = 0.0f; - s->voice[i][1] = 0.0f; - } - s->lbve = 3000; - s->fbve = 3000; - s->fbue = 187; - s->ofbue = 187; - s->sfbue = 187; - s->lbue = 93; - s->olbue = 93; - s->slbue = 93; - s->snr = (float) (s->fbve / s->fbue << 6); - - /* State used by function dynamic_pitch_tracking */ - for (i = 0; i < 60; i++) - s->s[i] = 0.0f; - for (i = 0; i < 2; i++) - { - for (j = 0; j < 60; j++) - s->p[i][j] = 0; - } - s->ipoint = 0; - s->alphax = 0.0f; - - /* State used by function lpc10_pack */ - s->isync = 0; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lpc10_encode_release(lpc10_encode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lpc10_encode_free(lpc10_encode_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lpc10_encode(lpc10_encode_state_t *s, uint8_t code[], const int16_t amp[], int len) -{ - int32_t voice[2]; - int32_t pitch; - float speech[LPC10_SAMPLES_PER_FRAME]; - float rc[LPC10_ORDER]; - float rms; - lpc10_frame_t frame; - int i; - int j; - - len /= LPC10_SAMPLES_PER_FRAME; - for (i = 0; i < len; i++) - { - for (j = 0; j < LPC10_SAMPLES_PER_FRAME; j++) - speech[j] = (float) amp[i*LPC10_SAMPLES_PER_FRAME + j]/32768.0f; - high_pass_100hz(s, speech, 0, LPC10_SAMPLES_PER_FRAME); - lpc10_analyse(s, speech, voice, &pitch, &rms, rc); - encode(s, &frame, voice, pitch, rms, rc); - lpc10_pack(s, &code[7*i], &frame); - } - return len*7; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_placev.c b/libs/spandsp/src/lpc10_placev.c deleted file mode 100644 index 339e241563..0000000000 --- a/libs/spandsp/src/lpc10_placev.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_placev.c - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the U.S. Department of Defense reference - * implementation of the LPC-10 2400 bps Voice Coder. They do not - * exert copyright claims on their code, and it may be freely used. - */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/lpc10.h" - -#include "lpc10_encdecs.h" - -#define subsc(x,y) (((x) << 1) + (y)) - -void lpc10_placea(int32_t *ipitch, - int32_t voibuf[3][2], - int32_t *obound, - int32_t af, - int32_t vwin[3][2], - int32_t awin[3][2], - int32_t ewin[3][2], - int32_t lframe, - int32_t maxwin) -{ - int allv; - int winv; - int32_t i; - int32_t j; - int32_t k; - int32_t l; - int32_t hrange; - bool ephase; - int32_t lrange; - - lrange = (af - 2)*lframe + 1; - hrange = af*lframe; - - /* Place the analysis window based on the voicing window placement, - onsets, tentative voicing decision, and pitch. */ - - /* Case 1: Sustained voiced speech - If the five most recent voicing decisions are - voiced, then the window is placed phase-synchronously with the - previous window, as close to the present voicing window if possible. - If onsets bound the voicing window, then preference is given to - a phase-synchronous placement which does not overlap these onsets. */ - - /* Case 2: Voiced transition - If at least one voicing decision in AF is voicied, and there are no - onsets, then the window is placed as in case 1. */ - - /* Case 3: Unvoiced speech or onsets - If both voicing decisions in AF are unvoiced, or there are onsets - then the window is placed coincident with the voicing window. */ - - /* Note: During phase-synchronous placement of windows, the length - is not altered from MAXWIN, since this would defeat the purpose - of phase-synchronous placement. */ - - /* Check for case 1 and case 2 */ - allv = voibuf[af - 2][1] == 1 - && - voibuf[af - 1][0] == 1 - && - voibuf[af - 1][1] == 1 - && - voibuf[af][0] == 1 - && - voibuf[af][1] == 1; - winv = voibuf[af][0] == 1 || voibuf[af][1] == 1; - if (allv || (winv && *obound == 0)) - { - /* APHASE: Phase synchronous window placement. */ - /* Get minimum lower index of the window. */ - i = (lrange + *ipitch - 1 - awin[af - 2][0]) / *ipitch; - i *= *ipitch; - i += awin[af - 2][0]; - /* l = the actual length of this frame's analysis window. */ - l = maxwin; - /* Calculate the location where a perfectly centered window would start. */ - k = (vwin[af - 1][0] + vwin[af - 1][1] + 1 - l)/2; - /* Choose the actual location to be the pitch multiple closest to this */ - awin[af - 1][0] = i + ((int) floorf((float) (k - i)/(float) *ipitch + 0.5f))*(*ipitch); - awin[af - 1][1] = awin[af - 1][0] + l - 1; - /* If there is an onset bounding the right of the voicing window and the - analysis window overlaps that, then move the analysis window backward - to avoid this onset. */ - if (*obound >= 2 && awin[af - 1][1] > vwin[af - 1][1]) - { - awin[af - 1][0] -= *ipitch; - awin[af - 1][1] -= *ipitch; - } - /* Similarly for the left of the voicing window. */ - if ((*obound == 1 || *obound == 3) && awin[af - 1][0] < vwin[af - 1][0]) - { - awin[af - 1][0] += *ipitch; - awin[af - 1][1] += *ipitch; - } - /* If this placement puts the analysis window above HRANGE, then - move it backward an integer number of pitch periods. */ - while (awin[af - 1][1] > hrange) - { - awin[af - 1][0] -= *ipitch; - awin[af - 1][1] -= *ipitch; - } - /* Similarly if the placement puts the analysis window below LRANGE. */ - while (awin[af - 1][0] < lrange) - { - awin[af - 1][0] += *ipitch; - awin[af - 1][1] += *ipitch; - } - /* Make energy window be phase-synchronous. */ - ephase = true; - } - else - { - /* Case 3 */ - awin[af - 1][0] = vwin[af - 1][0]; - awin[af - 1][1] = vwin[af - 1][1]; - 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 - as possible to onsets. */ - j = (awin[af - 1][1] - awin[af - 1][0] + 1) / *ipitch * *ipitch; - if (j == 0 || !winv) - { - ewin[af - 1][0] = vwin[af - 1][0]; - ewin[af - 1][1] = vwin[af - 1][1]; - } - else if (!ephase && *obound == 2) - { - ewin[af - 1][0] = awin[af - 1][1] - j + 1; - ewin[af - 1][1] = awin[af - 1][1]; - } - else - { - ewin[af - 1][0] = awin[af - 1][0]; - ewin[af - 1][1] = awin[af - 1][0] + j - 1; - } -} -/*- End of function --------------------------------------------------------*/ - -void lpc10_placev(int32_t *osbuf, - int32_t *osptr, - int32_t oslen, - int32_t *obound, - int32_t vwin[3][2], - int32_t af, - int32_t lframe, - int32_t minwin, - int32_t maxwin, - int32_t dvwinl, - int32_t dvwinh) -{ - int32_t i1; - int32_t i2; - bool crit; - int32_t q; - int32_t osptr1; - int32_t hrange; - int32_t lrange; - int i; - - /* Voicing window placement */ - - /* __________________ __________________ ______________ */ - /* | | | */ - /* | 1F | 2F | 3F ... */ - /* |__________________|__________________|______________ */ - - /* Previous | */ - /* Window | */ - /* ...________| */ - - /* | | */ - /* ------>| This window's placement range |<------ */ - /* | | */ - - /* There are three cases. Note these are different from those - given in the LPC-10e phase 1 report. */ - - /* 1. If there are no onsets in this range, then the voicing window - is centered in the pitch window. If such a placement is not within - the window's placement range, then the window is placed in the left-most - portion of the placement range. Its length is always MAXWIN. */ - - /* 2. If the first onset is in 2F and there is sufficient room to place - the window immediately before this onset, then the window is placed - there, and its length is set to the maximum possible under these - constraints. */ - - /* "Critical Region Exception": If there is another onset in 2F - such that a window can be placed between the two onsets, the - window is placed there (ie, as in case 3). */ - - /* 3. Otherwise, the window is placed immediately after the onset. The - window's length is the longest length that can fit in the range under these - constraints, except that the window may be shortened even further to avoid - overlapping other onsets in the placement range. In any case, the window's - length is at least MINWIN. */ - - /* Note that the values of MINWIN and LFRAME must be chosen such - that case 2 = false implies case 3 = true. This means that - MINWIN <= LFRAME/2. If this were not the case, then a fourth case - would have to be added for when the window cannot fit either before - or after the onset. */ - - /* Note also that onsets which weren't in 2F last time may be in 1F this - time, due to the filter delays in computing onsets. The result is that - occasionally a voicing window will overlap that onset. The only way - to circumvent this problem is to add more delay in processing input - speech. In the trade-off between delay and window-placement, window - placement lost. */ - - /* Compute the placement range */ - - /* Computing MAX */ - i1 = vwin[af - 2][1] + 1; - i2 = (af - 2)*lframe + 1; - lrange = max(i1, i2); - hrange = af*lframe; - /* Compute OSPTR1, so the following code only looks at relevant onsets. */ - for (osptr1 = *osptr - 1; osptr1 >= 1; osptr1--) - { - if (osbuf[osptr1 - 1] <= hrange) - break; - } - osptr1++; - /* Check for case 1 first (fast case) */ - if (osptr1 <= 1 || osbuf[osptr1 - 2] < lrange) - { - /* Compute max */ - i1 = vwin[af - 2][1] + 1; - vwin[af - 1][0] = max(i1, dvwinl); - vwin[af - 1][1] = vwin[af - 1][0] + maxwin - 1; - *obound = 0; - } - else - { - /* Search backward in OSBUF for first onset in range. */ - /* This code relies on the above check being performed first. */ - for (q = osptr1 - 1; q >= 1; q--) - { - if (osbuf[q - 1] < lrange) - break; - } - q++; - /* Check for case 2 (placement before onset): */ - /* Check for critical region exception: */ - crit = false; - for (i = q + 1; i < osptr1; i++) - { - if (osbuf[i - 1] - osbuf[q - 1] >= minwin) - { - crit = true; - break; - } - } - /* Compute max */ - i1 = (af - 1)*lframe; - i2 = lrange + minwin - 1; - if (!crit && osbuf[q - 1] > max(i1, i2)) - { - vwin[af - 1][1] = osbuf[q - 1] - 1; - /* Compute max */ - i2 = vwin[af - 1][1] - maxwin + 1; - vwin[af - 1][0] = max(lrange, i2); - *obound = 2; - } - else - { - /* Case 3 (placement after onset) */ - vwin[af - 1][0] = osbuf[q - 1]; - do - { - if (++q >= osptr1 - || - osbuf[q - 1] > vwin[af - 1][0] + maxwin) - { - /* Compute min */ - i1 = vwin[af - 1][0] + maxwin - 1; - vwin[af - 1][1] = min(i1, hrange); - *obound = 1; - return; - } - } - while (osbuf[q - 1] < vwin[af - 1][0] + minwin); - vwin[af - 1][1] = osbuf[q - 1] - 1; - *obound = 3; - } - } -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_voicing.c b/libs/spandsp/src/lpc10_voicing.c deleted file mode 100644 index cb668a5acc..0000000000 --- a/libs/spandsp/src/lpc10_voicing.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_voicing.c - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - * - * This code is based on the U.S. Department of Defense reference - * implementation of the LPC-10 2400 bps Voice Coder. They do not - * exert copyright claims on their code, and it may be freely used. - */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/fast_convert.h" -#include "spandsp/lpc10.h" -#include "spandsp/private/lpc10.h" - -#include "lpc10_encdecs.h" - -static void vparms(int32_t vwin[], - float *inbuf, - float *lpbuf, - const int32_t buflim[], - int32_t half, - float *dither, - int32_t *mintau, - int32_t *zc, - int32_t *lbe, - int32_t *fbe, - float *qs, - float *rc1, - float *ar_b, - float *ar_f) -{ - int32_t inbuf_offset; - int32_t lpbuf_offset; - int32_t vlen; - int32_t stop; - int32_t i; - int32_t start; - float r1; - float r2; - float e_pre; - float ap_rms; - float e_0; - float oldsgn; - float lp_rms; - float e_b; - float e_f; - float r_b; - float r_f; - float e0ap; - - /* Calculate zero crossings (ZC) and several energy and correlation */ - /* measures on low band and full band speech. Each measure is taken */ - /* over either the first or the second half of the voicing window, */ - /* depending on the variable HALF. */ - lpbuf_offset = buflim[2]; - lpbuf -= lpbuf_offset; - inbuf_offset = buflim[0]; - inbuf -= inbuf_offset; - - lp_rms = 0.0f; - ap_rms = 0.0f; - e_pre = 0.0f; - e0ap = 0.0f; - *rc1 = 0.0f; - e_0 = 0.0f; - e_b = 0.0f; - e_f = 0.0f; - r_f = 0.0f; - r_b = 0.0f; - *zc = 0; - vlen = vwin[1] - vwin[0] + 1; - start = vwin[0] + half*vlen/2 + 1; - stop = start + vlen/2 - 1; - - /* I'll use the symbol HVL in the table below to represent the value */ - /* VLEN/2. Note that if VLEN is odd, then HVL should be rounded down, */ - /* i.e., HVL = (VLEN-1)/2. */ - - /* HALF START STOP */ - - /* 1 VWIN(1)+1 VWIN(1)+HVL */ - /* 2 VWIN(1)+HVL+1 VWIN(1)+2*HVL */ - oldsgn = r_sign(1.0f, inbuf[start - 1] - *dither); - for (i = start; i <= stop; i++) - { - lp_rms += fabsf(lpbuf[i]); - ap_rms += fabsf(inbuf[i]); - e_pre += fabsf(inbuf[i] - inbuf[i - 1]); - r1 = inbuf[i]; - e0ap += r1*r1; - *rc1 += inbuf[i]*inbuf[i - 1]; - r1 = lpbuf[i]; - e_0 += r1*r1; - r1 = lpbuf[i - *mintau]; - e_b += r1*r1; - r1 = lpbuf[i + *mintau]; - e_f += r1*r1; - r_f += lpbuf[i]*lpbuf[i + *mintau]; - r_b += lpbuf[i]*lpbuf[i - *mintau]; - r1 = inbuf[i] + *dither; - if (r_sign(1.0f, r1) != oldsgn) - { - ++(*zc); - oldsgn = -oldsgn; - } - *dither = -(*dither); - } - /* Normalized short-term autocovariance coefficient at unit sample delay */ - *rc1 /= max(e0ap, 1.0f); - /* Ratio of the energy of the first difference signal (6 dB/oct preemphasis)*/ - /* to the energy of the full band signal */ - /* Computing MAX */ - r1 = ap_rms*2.0f; - *qs = e_pre/max(r1, 1.0f); - /* aR_b is the product of the forward and reverse prediction gains, */ - /* looking backward in time (the causal case). */ - *ar_b = r_b/max(e_b, 1.0f)*(r_b/max(e_0, 1.0f)); - /* aR_f is the same as aR_b, but looking forward in time (non causal case).*/ - *ar_f = r_f/max(e_f, 1.0f)*(r_f/max(e_0, 1.0f)); - /* Normalize ZC, LBE, and FBE to old fixed window length of 180. */ - /* (The fraction 90/VLEN has a range of 0.58 to 1) */ - r2 = (float) (*zc << 1); - *zc = lfastrintf(r2*(90.0f/vlen)); - r1 = lp_rms/4*(90.0f/vlen); - *lbe = min(lfastrintf(r1), 32767); - r1 = ap_rms/4*(90.0f/vlen); - *fbe = min(lfastrintf(r1), 32767); -} -/*- End of function --------------------------------------------------------*/ - -/* Voicing detection makes voicing decisions for each half */ -/* frame of input speech. Tentative voicing decisions are made two frames*/ -/* in the future (2F) for each half frame. These decisions are carried */ -/* through one frame in the future (1F) to the present (P) frame where */ -/* they are examined and smoothed, resulting in the final voicing */ -/* decisions for each half frame. */ - -/* The voicing parameter (signal measurement) column vector (VALUE) */ -/* is based on a rectangular window of speech samples determined by the */ -/* window placement algorithm. The voicing parameter vector contains the*/ -/* AMDF windowed maximum-to-minimum ratio, the zero crossing rate, energy*/ -/* measures, reflection coefficients, and prediction gains. The voicing */ -/* window is placed to avoid contamination of the voicing parameter vector*/ -/* with speech onsets. */ - -/* The input signal is then classified as unvoiced (including */ -/* silence) or voiced. This decision is made by a linear discriminant */ -/* function consisting of a dot product of the voicing decision */ -/* coefficient (VDC) row vector with the measurement column vector */ -/* (VALUE). The VDC vector is 2-dimensional, each row vector is optimized*/ -/* for a particular signal-to-noise ratio (SNR). So, before the dot */ -/* product is performed, the SNR is estimated to select the appropriate */ -/* VDC vector. */ - -/* The smoothing algorithm is a modified median smoother. The */ -/* voicing discriminant function is used by the smoother to determine how*/ -/* strongly voiced or unvoiced a signal is. The smoothing is further */ -/* modified if a speech onset and a voicing decision transition occur */ -/* within one half frame. In this case, the voicing decision transition */ -/* is extended to the speech onset. For transmission purposes, there are*/ -/* constraints on the duration and transition of voicing decisions. The */ -/* smoother takes these constraints into account. */ - -/* Finally, the energy estimates are updated along with the dither */ -/* threshold used to calculate the zero crossing rate (ZC). */ - -void lpc10_voicing(lpc10_encode_state_t *s, - int32_t vwin[], - float *inbuf, - float *lpbuf, - const int32_t buflim[], - int32_t half, - float *minamd, - float *maxamd, - int32_t *mintau, - float ivrc[], - int32_t obound[]) -{ - static const float vdc[100] = - { - 0.0f, 1714.0f, -110.0f, 334.0f, -4096.0f, -654.0f, 3752.0f, 3769.0f, 0.0f, 1181.0f, - 0.0f, 874.0f, -97.0f, 300.0f, -4096.0f, -1021.0f, 2451.0f, 2527.0f, 0.0f, -500.0f, - 0.0f, 510.0f, -70.0f, 250.0f, -4096.0f, -1270.0f, 2194.0f, 2491.0f, 0.0f, -1500.0f, - 0.0f, 500.0f, -10.0f, 200.0f, -4096.0f, -1300.0f, 2.0e3f, 2.0e3f, 0.0f, -2.0e3f, - 0.0f, 500.0f, 0.0f, 0.0f, -4096.0f, -1300.0f, 2.0e3f, 2.0e3f, 0.0f, -2500.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f - }; - static const int nvdcl = 5; - static const float vdcl[10] = - { - 600.0f, 450.0f, 300.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f - }; - - int32_t inbuf_offset; - int32_t lpbuf_offset; - int32_t i1; - float r1; - float r2; - float ar_b; - float ar_f; - int32_t snrl; - int32_t i; - float value[9]; - int32_t zc; - int ot; - float qs; - int32_t vstate; - float rc1; - int32_t fbe; - int32_t lbe; - float snr2; - -#if (_MSC_VER >= 1400) - __analysis_assume(half >= 0 && half < 2); -#endif - inbuf_offset = 0; - lpbuf_offset = 0; - if (inbuf) - { - inbuf_offset = buflim[0]; - inbuf -= inbuf_offset; - } - if (lpbuf) - { - lpbuf_offset = buflim[2]; - lpbuf -= lpbuf_offset; - } - - /* Voicing Decision Parameter vector (* denotes zero coefficient): */ - - /* * MAXMIN */ - /* LBE/LBVE */ - /* ZC */ - /* RC1 */ - /* QS */ - /* IVRC2 */ - /* aR_B */ - /* aR_F */ - /* * LOG(LBE/LBVE) */ - /* Define 2-D voicing decision coefficient vector according to the voicing */ - /* parameter order above. Each row (VDC vector) is optimized for a specific */ - /* SNR. The last element of the vector is the constant. */ - /* E ZC RC1 Qs IVRC2 aRb aRf c */ - - /* The VOICE array contains the result of the linear discriminant function*/ - /* (analog values). The VOIBUF array contains the hard-limited binary */ - /* voicing decisions. The VOICE and VOIBUF arrays, according to FORTRAN */ - /* memory allocation, are addressed as: */ - - /* (half-frame number, future-frame number) */ - - /* | Past | Present | Future1 | Future2 | */ - /* | 1,0 | 2,0 | 1,1 | 2,1 | 1,2 | 2,2 | 1,3 | 2,3 | ---> time */ - - /* Update linear discriminant function history each frame: */ - if (half == 0) - { - s->voice[0][0] = s->voice[1][0]; - s->voice[0][1] = s->voice[1][1]; - s->voice[1][0] = s->voice[2][0]; - s->voice[1][1] = s->voice[2][1]; - s->maxmin = *maxamd / max(*minamd, 1.0f); - } - /* Calculate voicing parameters twice per frame */ - vparms(vwin, - &inbuf[inbuf_offset], - &lpbuf[lpbuf_offset], - buflim, - half, - &s->dither, - mintau, - &zc, - &lbe, - &fbe, - &qs, - &rc1, - &ar_b, - &ar_f); - /* Estimate signal-to-noise ratio to select the appropriate VDC vector. */ - /* The SNR is estimated as the running average of the ratio of the */ - /* running average full-band voiced energy to the running average */ - /* full-band unvoiced energy. SNR filter has gain of 63. */ - r1 = (s->snr + s->fbve/(float) max(s->fbue, 1))*63/64.0f; - s->snr = (float) lfastrintf(r1); - snr2 = s->snr*s->fbue/max(s->lbue, 1); - /* Quantize SNR to SNRL according to VDCL thresholds. */ - i1 = nvdcl - 1; - for (snrl = 0; snrl < i1; snrl++) - { - if (snr2 > vdcl[snrl]) - break; - } - /* (Note: SNRL = NVDCL here) */ - /* Linear discriminant voicing parameters: */ - value[0] = s->maxmin; - value[1] = (float) lbe/max(s->lbve, 1); - value[2] = (float) zc; - value[3] = rc1; - value[4] = qs; - value[5] = ivrc[1]; - value[6] = ar_b; - value[7] = ar_f; - /* Evaluation of linear discriminant function: */ - s->voice[2][half] = vdc[snrl*10 + 9]; - for (i = 0; i < 8; i++) - s->voice[2][half] += vdc[snrl*10 + i]*value[i]; - /* Classify as voiced if discriminant > 0, otherwise unvoiced */ - /* Voicing decision for current half-frame: 1 = Voiced; 0 = Unvoiced */ - s->voibuf[3][half] = (s->voice[2][half] > 0.0f) ? 1 : 0; - /* Skip voicing decision smoothing in first half-frame: */ - if (half != 0) - { - /* Voicing decision smoothing rules (override of linear combination): */ - - /* Unvoiced half-frames: At least two in a row. */ - /* -------------------- */ - - /* Voiced half-frames: At least two in a row in one frame. */ - /* ------------------- Otherwise at least three in a row. */ - /* (Due to the way transition frames are encoded) */ - - /* In many cases, the discriminant function determines how to smooth. */ - /* In the following chart, the decisions marked with a * may be overridden. */ - - /* Voicing override of transitions at onsets: */ - /* If a V/UV or UV/V voicing decision transition occurs within one-half */ - /* frame of an onset bounding a voicing window, then the transition is */ - /* moved to occur at the onset. */ - - /* P 1F */ - /* ----- ----- */ - /* 0 0 0 0 */ - /* 0 0 0* 1 (If there is an onset there) */ - /* 0 0 1* 0* (Based on 2F and discriminant distance) */ - /* 0 0 1 1 */ - /* 0 1* 0 0 (Always) */ - /* 0 1* 0* 1 (Based on discriminant distance) */ - /* 0* 1 1 0* (Based on past, 2F, and discriminant distance) */ - /* 0 1* 1 1 (If there is an onset there) */ - /* 1 0* 0 0 (If there is an onset there) */ - /* 1 0 0 1 */ - /* 1 0* 1* 0 (Based on discriminant distance) */ - /* 1 0* 1 1 (Always) */ - /* 1 1 0 0 */ - /* 1 1 0* 1* (Based on 2F and discriminant distance) */ - /* 1 1 1* 0 (If there is an onset there) */ - /* 1 1 1 1 */ - - /* Determine if there is an onset transition between P and 1F. */ - /* OT (Onset Transition) is true if there is an onset between */ - /* P and 1F but not after 1F. */ - ot = ((obound[0] & 2) != 0 || obound[1] == 1) && (obound[2] & 1) == 0; - /* Multi-way dispatch on voicing decision history: */ - vstate = (s->voibuf[1][0] << 3) + (s->voibuf[1][1] << 2) + (s->voibuf[2][0] << 1) + s->voibuf[2][1]; - switch (vstate + 1) - { - case 2: - if (ot && s->voibuf[3][0] == 1) - s->voibuf[2][0] = 1; - break; - case 3: - if (s->voibuf[3][0] == 0 || s->voice[1][0] < -s->voice[1][1]) - s->voibuf[2][0] = 0; - else - s->voibuf[2][1] = 1; - break; - case 5: - s->voibuf[1][1] = 0; - break; - case 6: - if (s->voice[0][1] < -s->voice[1][0]) - s->voibuf[1][1] = 0; - else - s->voibuf[2][0] = 1; - break; - case 7: - if (s->voibuf[0][0] == 1 || s->voibuf[3][0] == 1 || s->voice[1][1] > s->voice[0][0]) - s->voibuf[2][1] = 1; - else - s->voibuf[1][0] = 1; - break; - case 8: - if (ot) - s->voibuf[1][1] = 0; - break; - case 9: - if (ot) - s->voibuf[1][1] = 1; - break; - case 11: - if (s->voice[1][0] < -s->voice[0][1]) - s->voibuf[2][0] = 0; - else - s->voibuf[1][1] = 1; - break; - case 12: - s->voibuf[1][1] = 1; - break; - case 14: - if (s->voibuf[3][0] == 0 && s->voice[1][1] < -s->voice[1][0]) - s->voibuf[2][1] = 0; - else - s->voibuf[2][0] = 1; - break; - case 15: - if (ot && s->voibuf[3][0] == 0) - s->voibuf[2][0] = 0; - break; - } - } - /* During unvoiced half-frames, update the low band and full band unvoiced*/ - /* energy estimates (LBUE and FBUE) and also the zero crossing */ - /* threshold (DITHER). (The input to the unvoiced energy filters is */ - /* restricted to be less than 10dB above the previous inputs of the */ - /* filters.) */ - /* During voiced half-frames, update the low-pass (LBVE) and all-pass */ - /* (FBVE) voiced energy estimates. */ - if (s->voibuf[3][half] == 0) - { - r1 = (s->sfbue*63 + (min(fbe, s->ofbue*3) << 3))/64.0f; - s->sfbue = lfastrintf(r1); - s->fbue = s->sfbue/8; - s->ofbue = fbe; - r1 = (s->slbue*63 + (min(lbe, s->olbue*3) << 3))/64.0f; - s->slbue = lfastrintf(r1); - s->lbue = s->slbue/8; - s->olbue = lbe; - } - else - { - s->lbve = lfastrintf((s->lbve*63 + lbe)/64.0f); - s->fbve = lfastrintf((s->fbve*63 + fbe)/64.0f); - } - /* Set dither threshold to yield proper zero crossing rates in the */ - /* presence of low frequency noise and low level signal input. */ - /* NOTE: The divisor is a function of REF, the expected energies. */ - /* Computing MIN */ - /* Computing MAX */ - r2 = sqrtf((float) (s->lbue*s->lbve))*64/3000; - r1 = max(r2, 1.0f); - s->dither = min(r1, 20.0f); - /* Voicing decisions are returned in VOIBUF. */ -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/make_at_dictionary.c b/libs/spandsp/src/make_at_dictionary.c deleted file mode 100644 index de50294ed1..0000000000 --- a/libs/spandsp/src/make_at_dictionary.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * make_at_dictionary.c - Generate a trie based dictionary for the AT - * commands supported by the AT interpreter. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 - -const char *wordlist[] = -{ - " ", /* Dummy to absorb spaces in commands */ - "&C", /* V.250 6.2.8 - Circuit 109 (received line signal detector), behaviour */ - "&D", /* V.250 6.2.9 - Circuit 108 (data terminal ready) behaviour */ - "&F", /* V.250 6.1.2 - Set to factory-defined configuration */ - "+A8A", /* V.251 6.3 - V.8 calling tone indication */ - "+A8C", /* V.251 6.2 - V.8 answer signal indication */ - "+A8E", /* V.251 5.1 - V.8 and V.8bis operation controls */ - "+A8I", /* V.251 6.1 - V.8 CI signal indication */ - "+A8J", /* V.251 6.4 - V.8 negotiation complete */ - "+A8M", /* V.251 5.2 - Send V.8 menu signals */ - "+A8R", /* V.251 6.6 - V.8bis signal and message reporting */ - "+A8T", /* V.251 5.3 - Send V.8bis signal and/or message(s) */ - "+ASTO", /* V.250 6.3.15 - Store telephone number */ - "+CAAP", /* 3GPP TS 27.007 7.25 - Automatic answer for eMLPP Service */ - "+CACM", /* 3GPP TS 27.007 8.25 - Accumulated call meter */ - "+CACSP", /* 3GPP TS 27.007 11.1.7 - Voice Group or Voice Broadcast Call State Attribute Presentation */ - "+CAD", /* IS-99 5.6.3 - Query analogue or digital service */ - "+CAEMLPP", /* 3GPP TS 27.007 7.22 - eMLPP Priority Registration and Interrogation */ - "+CAHLD", /* 3GPP TS 27.007 11.1.3 - Leave an ongoing Voice Group or Voice Broadcast Call */ - "+CAJOIN", /* 3GPP TS 27.007 11.1.1 - Accept an incoming Voice Group or Voice Broadcast Call */ - "+CALA", /* 3GPP TS 27.007 8.16 - Alarm */ - "+CALCC", /* 3GPP TS 27.007 11.1.6 - List current Voice Group and Voice Broadcast Calls */ - "+CALD", /* 3GPP TS 27.007 8.38 - Delete alar m */ - "+CALM", /* 3GPP TS 27.007 8.20 - Alert sound mode */ - "+CAMM", /* 3GPP TS 27.007 8.26 - Accumulated call meter maximum */ - "+CANCHEV", /* 3GPP TS 27.007 11.1.8 - NCH Support Indication */ - "+CAOC", /* 3GPP TS 27.007 7.16 - Advice of Charge */ - "+CAPD", /* 3GPP TS 27.007 8.39 - Postpone or dismiss an alarm */ - "+CAPTT", /* 3GPP TS 27.007 11.1.4 - Talker Access for Voice Group Call */ - "+CAREJ", /* 3GPP TS 27.007 11.1.2 - Reject an incoming Voice Group or Voice Broadcast Call */ - "+CAULEV", /* 3GPP TS 27.007 11.1.5 - Voice Group Call Uplink Status Presentation */ - "+CBC", /* 3GPP TS 27.007 8.4 - Battery charge */ - "+CBCS", /* 3GPP TS 27.007 11.3.2 - VBS subscriptions and GId status */ - "+CBIP", /* IS-99 5.6 - Base station IP address */ - "+CBST", /* 3GPP TS 27.007 6.7 - Select bearer service type */ - "+CCFC", /* 3GPP TS 27.007 7.11 - Call forwarding number and conditions */ - "+CCLK", /* 3GPP TS 27.007 8.15 - Clock */ - "+CCS", /* IS-135 4.1.22 - Compression status */ - "+CCUG", /* 3GPP TS 27.007 7.10 - Closed user group */ - "+CCWA", /* 3GPP TS 27.007 7.12 - Call waiting */ - "+CCWE", /* 3GPP TS 27.007 8.28 - Call Meter maximum event */ - "+CDIP", /* 3GPP TS 27.007 7.9 - Called line identification presentation */ - "+CDIS", /* 3GPP TS 27.007 8.8 - Display control */ - "+CDV", /* IS-99 5.6 - Dial command for voice call */ - "+CEER", /* 3GPP TS 27.007 6.10 - Extended error report */ - "+CESP", /* GSM07.05 3.2.4 - Enter SMS block mode protocol */ - "+CFCS", /* 3GPP TS 27.007 7.24 - Fast call setup conditions */ - "+CFG", /* IS-99 5.6 - Configuration string */ - "+CFUN", /* 3GPP TS 27.007 8.2 - Set phone functionality */ - "+CGACT", /* 3GPP TS 27.007 10.1.10 - PDP context activate or deactivate */ - "+CGANS", /* 3GPP TS 27.007 10.1.16 - Manual response to a network request for PDP context activation */ - "+CGATT", /* 3GPP TS 27.007 10.1.9 - PS attach or detach */ - "+CGAUTO", /* 3GPP TS 27.007 10.1.15 - Automatic response to a network request for PDP context activation */ - "+CGCAP", /* IS-99 5.6 - Request complete capabilities list */ - "+CGCLASS", /* 3GPP TS 27.007 10.1.17 - GPRS mobile station class (GPRS only) */ - "+CGCLOSP", /* 3GPP TS 27.007 10.1.13 - Configure local octet stream PAD parameters (Obsolete) */ - "+CGCLPAD", /* 3GPP TS 27.007 10.1.12 - Configure local triple-X PAD parameters (GPRS only) (Obsolete) */ - "+CGCMOD", /* 3GPP TS 27.007 10.1.11 - PDP Context Modify */ - "+CGCS", /* 3GPP TS 27.007 11.3.1 - VGCS subscriptions and GId status */ - "+CGDATA", /* 3GPP TS 27.007 10.1.12 - Enter data state */ - "+CGDCONT", /* 3GPP TS 27.007 10.1.1 - Define PDP Context */ - "+CGDSCONT",/* 3GPP TS 27.007 10.1.2 - Define Secondary PDP Context */ - "+CGEQMIN", /* 3GPP TS 27.007 10.1.7 - 3G Quality of Service Profile (Minimum acceptable) */ - "+CGEQNEG", /* 3GPP TS 27.007 10.1.8 - 3G Quality of Service Profile (Negotiated) */ - "+CGEQREQ", /* 3GPP TS 27.007 10.1.6 - 3G Quality of Service Profile (Requested) */ - "+CGEREP", /* 3GPP TS 27.007 10.1.18 - Packet Domain event reporting */ - "+CGMI", /* 3GPP TS 27.007 5.1 - Request manufacturer identification */ - "+CGMM", /* 3GPP TS 27.007 5.2 - Request model identification */ - "+CGMR", /* 3GPP TS 27.007 5.3 - Request revision identification */ - "+CGOI", /* IS-99 5.6 - Request global object identification */ - "+CGPADDR", /* 3GPP TS 27.007 10.1.14 - Show PDP address */ - "+CGQMIN", /* 3GPP TS 27.007 10.1.5 - Quality of Service Profile (Minimum acceptable) */ - "+CGQREQ", /* 3GPP TS 27.007 10.1.4 - Quality of Service Profile (Requested) */ - "+CGREG", /* 3GPP TS 27.007 10.1.19 - GPRS network registration status */ - "+CGSMS", /* 3GPP TS 27.007 10.1.20 - Select service for MO SMS messages */ - "+CGSN", /* 3GPP TS 27.007 5.4 - Request product serial number identification */ - "+CGTFT", /* 3GPP TS 27.007 10.1.3 - Traffic Flow Template */ - "+CHLD", /* 3GPP TS 27.007 7.13 - Call related supplementary services */ - "+CHSA", /* 3GPP TS 27.007 6.18 - HSCSD non-transparent asymmetry configuration */ - "+CHSC", /* 3GPP TS 27.007 6.15 - HSCSD current call parameters */ - "+CHSD", /* 3GPP TS 27.007 6.12 - HSCSD device parameters */ - "+CHSN", /* 3GPP TS 27.007 6.14 - HSCSD non-transparent call configuration */ - "+CHSR", /* 3GPP TS 27.007 6.16 - HSCSD parameters report */ - "+CHST", /* 3GPP TS 27.007 6.13 - HSCSD transparent call configuration */ - "+CHSU", /* 3GPP TS 27.007 6.17 - HSCSD automatic user initiated upgrading */ - "+CHUP", /* 3GPP TS 27.007 6.5 - Hangup call */ - "+CHV", /* IS-99 5.6 - Hang-up voice */ - "+CIMI", /* 3GPP TS 27.007 5.6 - Request international mobile subscriber identity */ - "+CIND", /* 3GPP TS 27.007 8.9 - Indicator control */ - "+CIT", /* IS-99 5.6 - Command state inactivity timer */ - "+CKPD", /* 3GPP TS 27.007 8.7 - Keypad control */ - "+CLAC", /* 3GPP TS 27.007 8.37 - List all available AT commands */ - "+CLAE", /* 3GPP TS 27.007 8.31 - Language Event */ - "+CLAN", /* 3GPP TS 27.007 8.30 - Set Language */ - "+CLCC", /* 3GPP TS 27.007 7.18 - List current calls */ - "+CLCK", /* 3GPP TS 27.007 7.4 - Facility lock */ - "+CLIP", /* 3GPP TS 27.007 7.6 - Calling line identification presentation */ - "+CLIR", /* 3GPP TS 27.007 7.7 - Calling line identification restriction */ - "+CLVL", /* 3GPP TS 27.007 8.23 - Loudspeaker volume level */ - "+CMAR", /* 3GPP TS 27.007 8.36 - Master reset */ - "+CMEC", /* 3GPP TS 27.007 8.6 - Mobile termination control mode */ - "+CMEE", /* GSM07.07 9.1 - Report mobile equipment error */ - "+CMER", /* 3GPP TS 27.007 8.10 - Mobile termination event reporting */ - "+CMGC", /* GSM07.05 3.5.5/4.5 - Send command */ - "+CMGD", /* GSM07.05 3.5.4 - Delete message */ - "+CMGF", /* GSM07.05 3.2.3 - Message Format */ - "+CMGL", /* GSM07.05 3.4.2/4.1 - List messages */ - "+CMGR", /* GSM07.05 3.4.3/4.2 - Read message */ - "+CMGS", /* GSM07.05 3.5.1/4.3 - Send message */ - "+CMGW", /* GSM07.05 3.5.3/4.4 - Write message to memory */ - "+CMIP", /* IS-99 5.6 - Mobile station IP address */ - "+CMM", /* IS-135 4.1.23 - Menu map */ - "+CMMS", /* GSM07.05 3.5.6 - More messages to send */ - "+CMOD", /* 3GPP TS 27.007 6.4 - Call mode */ - "+CMSS", /* GSM07.05 3.5.2/4.7 - Send message from storage */ - "+CMUT", /* 3GPP TS 27.007 8.24 - Mute control */ - "+CMUX", /* 3GPP TS 27.007 5.7 - Multiplexing mode */ - "+CNMA", /* GSM07.05 3.4.4/4.6 - New message acknowledgement to terminal adapter */ - "+CNMI", /* GSM07.05 3.4.1 - New message indications to terminal equipment */ - "+CNUM", /* 3GPP TS 27.007 7.1 - Subscriber number */ - "+COLP", /* 3GPP TS 27.007 7.8 - Connected line identification presentation */ - "+COPN", /* 3GPP TS 27.007 7.21 - Read operator names */ - "+COPS", /* 3GPP TS 27.007 7.3 - PLMN selection */ - "+COS", /* IS-135 4.1.24 - Originating service */ - "+COTDI", /* 3GPP TS 27.007 11.1.9 - Originator to Dispatcher Information */ - "+CPAS", /* 3GPP TS 27.007 8.1 - Phone activity status */ - "+CPBF", /* 3GPP TS 27.007 8.13 - Find phonebook entries */ - "+CPBR", /* 3GPP TS 27.007 8.12 - Read phonebook entries */ - "+CPBS", /* 3GPP TS 27.007 8.11 - Select phonebook memory storage */ - "+CPBW", /* 3GPP TS 27.007 8.14 - Write phonebook entry */ - "+CPIN", /* 3GPP TS 27.007 8.3 - Enter PIN */ - "+CPLS", /* 3GPP TS 27.007 7.20 - Selection of preferred PLMN list */ - "+CPMS", /* GSM07.05 3.2.2 - Preferred message storage */ - "+CPOL", /* 3GPP TS 27.007 7.19 - Preferred PLMN list */ - "+CPPS", /* 3GPP TS 27.007 7.23 - eMLPP subscriptions */ - "+CPROT", /* 3GPP TS 27.007 8.42 - Enter protocol mode */ - "+CPUC", /* 3GPP TS 27.007 8.27 - Price per unit and currency table */ - "+CPWC", /* 3GPP TS 27.007 8.29 - Power class */ - "+CPWD", /* 3GPP TS 27.007 7.5 - Change password */ - "+CQD", /* IS-135 4.1.25 - Query disconnect timer */ - "+CR", /* 3GPP TS 27.007 6.9 - Service reporting control */ - "+CRC", /* 3GPP TS 27.007 6.11 - Cellular result codes */ - "+CREG", /* 3GPP TS 27.007 7.2 - Network registration */ - "+CRES", /* GSM07.05 3.3.6 - Restore Settings */ - "+CRLP", /* 3GPP TS 27.007 6.8 - Radio link protocol */ - "+CRM", /* IS-99 5.6 - Set rm interface protocol */ - "+CRMC", /* 3GPP TS 27.007 8.34 - Ring Melody Control */ - "+CRMP", /* 3GPP TS 27.007 8.35 - Ring Melody Playback */ - "+CRSL", /* 3GPP TS 27.007 8.21 - Ringer sound level */ - "+CRSM", /* 3GPP TS 27.007 8.18 - Restricted SIM access */ - "+CSAS", /* GSM07.05 3.3.5 - Save settings */ - "+CSCA", /* GSM07.05 3.3.1 - Service centre address */ - "+CSCB", /* GSM07.05 3.3.4 - Select cell broadcast message types */ - "+CSCC", /* 3GPP TS 27.007 8.19 - Secure control command */ - "+CSCS", /* 3GPP TS 27.007 5.5 - Select TE character set */ - "+CSDF", /* 3GPP TS 27.007 6.22 - Settings date format */ - "+CSDH", /* GSM07.05 3.3.3 - Show text mode parameters */ - "+CSGT", /* 3GPP TS 27.007 8.32 - Set Greeting Text */ - "+CSIL", /* 3GPP TS 27.007 6.23 - Silence Command */ - "+CSIM", /* 3GPP TS 27.007 8.17 - Generic SIM access */ - "+CSMP", /* GSM07.05 3.3.2 - Set text mode parameters */ - "+CSMS", /* GSM07.05 3.2.1 - Select Message Service */ - "+CSNS", /* 3GPP TS 27.007 6.19 - Single numbering scheme */ - "+CSQ", /* 3GPP TS 27.007 8.5 - Signal quality */ - "+CSS", /* IS-135 4.1.28 - Serving system identification */ - "+CSSN", /* 3GPP TS 27.007 7.17 - Supplementary service notifications */ - "+CSTA", /* 3GPP TS 27.007 6.1 - Select type of address */ - "+CSTF", /* 3GPP TS 27.007 6.24 - Settings time format */ - "+CSVM", /* 3GPP TS 27.007 8.33 - Set Voice Mail Number */ - "+CTA", /* IS-135 4.1.29 - MT-Terminated async. Data calls */ - "+CTF", /* IS-135 4.1.30 - MT-Terminated FAX calls */ - "+CTFR", /* 3GPP TS 27.007 7.14 - Call deflection */ - "+CTZR", /* 3GPP TS 27.007 8.41 - Time Zone Reporting */ - "+CTZU", /* 3GPP TS 27.007 8.40 - Automatic Time Zone Update */ - "+CUSD", /* 3GPP TS 27.007 7.15 - Unstructured supplementary service data */ - "+CUUS1", /* 3GPP TS 27.007 7.26 - User to User Signalling Service 1 */ - "+CV120", /* 3GPP TS 27.007 6.21 - V.120 rate adaption protocol */ - "+CVHU", /* 3GPP TS 27.007 6.20 - Voice Hangup Control */ - "+CVIB", /* 3GPP TS 27.007 8.22 - Vibrator mode */ - "+CXT", /* IS-99 5.6 - Cellular extension */ - "+DR", /* V.250 6.6.2 - Data compression reporting */ - "+DS", /* V.250 6.6.1 - Data compression */ - "+DS44", /* V.250 6.6.2 - V.44 data compression */ - "+EB", /* V.250 6.5.2 - Break handling in error control operation */ - "+EFCS", /* V.250 6.5.4 - 32-bit frame check sequence */ - "+EFRAM", /* V.250 6.5.8 - Frame length */ - "+ER", /* V.250 6.5.5 - Error control reporting */ - "+ES", /* V.250 6.5.1 - Error control selection */ - "+ESA", /* V.80 8.2 - Synchronous access mode configuration */ - "+ESR", /* V.250 6.5.3 - Selective repeat */ - "+ETBM", /* V.250 6.5.6 - Call termination buffer management */ - "+EWIND", /* V.250 6.5.7 - Window size */ - "+F34", /* T.31 B.6.1 - Initial V.34 rate controls for FAX */ - "+FAA", /* T.32 8.5.2.5 - Adaptive Answer parameter */ - "+FAP", /* T.32 8.5.1.12 - Addressing and polling capabilities parameter */ - "+FAR", /* T.31 8.5.1 - Adaptive reception control */ - "+FBO", /* T.32 8.5.3.4 - Phase C data bit order */ - "+FBS", /* T.32 8.5.3.2 - Buffer Size, read only parameter */ - "+FBU", /* T.32 8.5.1.10 - HDLC Frame Reporting parameter */ - "+FCC", /* T.32 8.5.1.1 - DCE capabilities parameters */ - "+FCL", /* T.31 8.5.2 - Carrier loss timeout */ - "+FCLASS", /* T.31 8.2 - Capabilities identification and control */ - "+FCQ", /* T.32 8.5.2.3 - Copy quality checking parameter */ - "+FCR", /* T.32 8.5.1.9 - Capability to receive parameter */ - "+FCS", /* T.32 8.5.1.3 - Current Session Results parameters */ - "+FCT", /* T.32 8.5.2.6 - DTE phase C timeout parameter */ - "+FDD", /* T.31 8.5.3 - Double escape character replacement */ - "+FDR", /* T.32 8.3.4 - Data reception command */ - "+FDT", /* T.32 8.3.3 - Data transmission command */ - "+FEA", /* T.32 8.5.3.5 - Phase C received EOL alignment parameter */ - "+FFC", /* T.32 8.5.3.6 - Format conversion parameter */ - "+FFD", /* T.32 8.5.1.14 - File diagnostic message parameter */ - "+FHS", /* T.32 8.5.2.7 - Call termination status parameter */ - "+FIE", /* T.32 8.5.2.1 - Procedure interrupt enable parameter */ - "+FIP", /* T.32 8.3.6 - Initialize facsimile parameters */ - "+FIS", /* T.32 8.5.1.2 - Current session parameters */ - "+FIT", /* T.31 8.5.4 - DTE inactivity timeout */ - "+FKS", /* T.32 8.3.5 - Session termination command */ - "+FLI", /* T.32 8.5.1.5 - Local ID string parameter, TSI or CSI */ - "+FLO", /* T.31 says to implement something similar to +IFC */ - "+FLP", /* T.32 8.5.1.7 - Indicate document to poll parameter */ - "+FMI", /* T.31 says to duplicate +GMI */ - "+FMM", /* T.31 says to duplicate +GMM */ - "+FMR", /* T.31 says to duplicate +GMR */ - "+FMS", /* T.32 8.5.2.9 - Minimum phase C speed parameter */ - "+FND", /* T.32 8.5.2.10 - Non-Standard Message Data Indication parameter */ - "+FNR", /* T.32 8.5.1.11 - Negotiation message reporting control parameters */ - "+FNS", /* T.32 8.5.1.6 - Non-Standard Frame FIF parameter */ - "+FPA", /* T.32 8.5.1.13 - Selective polling address parameter */ - "+FPI", /* T.32 8.5.1.5 - Local Polling ID String parameter */ - "+FPP", /* T.32 8.5.3 - Facsimile packet protocol */ - "+FPR", /* T.31 says to implement something similar to +IPR */ - "+FPS", /* T.32 8.5.2.2 - Page Status parameter */ - "+FPW", /* T.32 8.5.1.13 - PassWord parameter (Sending or Polling) */ - "+FRH", /* T.31 8.3.6 - HDLC receive */ - "+FRM", /* T.31 8.3.4 - Facsimile receive */ - "+FRQ", /* T.32 8.5.2.4 - Receive Quality Thresholds parameters */ - "+FRS", /* T.31 8.3.2 - Receive silence */ - "+FRY", /* T.32 8.5.2.8 - ECM Retry Value parameter */ - "+FSA", /* T.32 8.5.1.13 - Subaddress parameter */ - "+FSP", /* T.32 8.5.1.8 - Request to poll parameter */ - "+FTH", /* T.31 8.3.5 - HDLC transmit */ - "+FTM", /* T.31 8.3.3 - Facsimile transmit */ - "+FTS", /* T.31 8.3.1 - Transmit silence */ - "+GCAP", /* V.250 6.1.9 - Request complete capabilities list */ - "+GCI", /* V.250 6.1.10 - Country of installation, */ - "+GMI", /* V.250 6.1.4 - Request manufacturer identification */ - "+GMM", /* V.250 6.1.5 - Request model identification */ - "+GMR", /* V.250 6.1.6 - Request revision identification */ - "+GOI", /* V.250 6.1.8 - Request global object identification */ - "+GSN", /* V.250 6.1.7 - Request product serial number identification */ - "+IBC", /* V.80 7.9 - Control of in-band control */ - "+IBM", /* V.80 7.10 - In-band MARK idle reporting control */ - "+ICF", /* V.250 6.2.11 - DTE-DCE character framing */ - "+ICLOK", /* V.250 6.2.14 - Select sync transmit clock source */ - "+IDSR", /* V.250 6.2.16 - Select data set ready option */ - "+IFC", /* V.250 6.2.12 - DTE-DCE local flow control */ - "+ILRR", /* V.250 6.2.13 - DTE-DCE local rate reporting */ - "+ILSD", /* V.250 6.2.15 - Select long space disconnect option */ - "+IPR", /* V.250 6.2.10 - Fixed DTE rate */ - "+IRTS", /* V.250 6.2.17 - Select synchronous mode RTS option */ - "+ITF", /* V.80 8.4 - Transmit flow control thresholds */ - "+MA", /* V.250 6.4.2 - Modulation automode control */ - "+MR", /* V.250 6.4.3 - Modulation reporting control */ - "+MS", /* V.250 6.4.1 - Modulation selection */ - "+MSC", /* V.250 6.4.8 - Seamless rate change enable */ - "+MV18AM", /* V.250 6.4.6 - V.18 answering message editing */ - "+MV18P", /* V.250 6.4.7 - Order of probes */ - "+MV18R", /* V.250 6.4.5 - V.18 reporting control */ - "+MV18S", /* V.250 6.4.4 - V.18 selection */ - "+PCW", /* V.250 6.8.1 - Call waiting enable (V.92 DCE) */ - "+PIG", /* V.250 6.8.5 - PCM upstream ignore */ - "+PMH", /* V.250 6.8.2 - Modem on hold enable */ - "+PMHF", /* V.250 6.8.6 - V.92 Modem on hold hook flash */ - "+PMHR", /* V.250 6.8.4 - Initiate modem on hold */ - "+PMHT", /* V.250 6.8.3 - Modem on hold timer */ - "+PQC", /* V.250 6.8.7 - V.92 Phase 1 and Phase 2 Control */ - "+PSS", /* V.250 6.8.8 - V.92 Use Short Sequence */ - "+SAC", /* V.252 3.4 - Audio transmit configuration */ - "+SAM", /* V.252 3.5 - Audio receive mode */ - "+SAR", /* V.252 5.3 - Audio receive channel indication */ - "+SARR", /* V.252 3.9 - Audio indication reporting */ - "+SAT", /* V.252 5.4 - Audio transmit channel indication */ - "+SCRR", /* V.252 3.11 - Capabilities indication reporting */ - "+SDC", /* V.252 3.3 - Data configuration */ - "+SDI", /* V.252 5.2 - Data channel identification */ - "+SDR", /* V.252 3.8 - Data indication reporting */ - "+SRSC", /* V.252 5.1.2 - Remote terminal simultaneous capability indication */ - "+STC", /* V.252 3.1 - Terminal configuration */ - "+STH", /* V.252 3.2 - Close logical channel */ - "+SVC", /* V.252 3.6 - Video transmit configuration */ - "+SVM", /* V.252 3.7 - Video receive mode */ - "+SVR", /* V.252 5.5 - Video receive channel indication */ - "+SVRR", /* V.252 3.10 - Video indication reporting */ - "+SVT", /* V.252 5.6 - Video transmit channel indication */ - "+TADR", /* V.250 6.7.2.9 - Local V.54 address */ - "+TAL", /* V.250 6.7.2.15 - Local analogue loop */ - "+TALS", /* V.250 6.7.2.6 - Analogue loop status */ - "+TDLS", /* V.250 6.7.2.7 - Local digital loop status */ - "+TE140", /* V.250 6.7.2.1 - Enable ckt 140 */ - "+TE141", /* V.250 6.7.2.2 - Enable ckt 141 */ - "+TEPAL", /* V.250 6.7.2.5 - Enable front panel analogue loop */ - "+TEPDL", /* V.250 6.7.2.4 - Enable front panel RDL */ - "+TERDL", /* V.250 6.7.2.3 - Enable RDL from remote */ - "+TLDL", /* V.250 6.7.2.13 - Local digital loop */ - "+TMO", /* V.250 6.9 - V.59 command */ - "+TMODE", /* V.250 6.7.2.10 - Set V.54 mode */ - "+TNUM", /* V.250 6.7.2.12 - Errored bit and block counts */ - "+TRDL", /* V.250 6.7.2.14 - Request remote digital loop */ - "+TRDLS", /* V.250 6.7.2.8 - Remote digital loop status */ - "+TRES", /* V.250 6.7.2.17 - Self test result */ - "+TSELF", /* V.250 6.7.2.16 - Self test */ - "+TTER", /* V.250 6.7.2.11 - Test error rate */ - "+VAC", /* V.252 4.1 - Set audio code */ - "+VACR", /* V.252 6.1 - Audio code report */ - "+VBT", /* 3GPP TS 27.007 C.2.2 - Buffer threshold setting */ - "+VCID", /* V.253 9.2.3 - Caller ID service */ - "+VCIDR", /* V.252 6.2 - Caller ID report */ - "+VDID", /* V.253 9.2.4 - DID service */ - "+VDIDR", /* V.252 6.2 - DID report */ - "+VDR", /* V.253 10.3.1 - Distinctive ring (ring cadence reporting) */ - "+VDT", /* V.253 10.3.2 - Control tone cadence reporting */ - "+VDX", /* V.253 10.5.6 - Speakerphone duplex mode */ - "+VEM", /* V.253 10.5.7 - Deliver event reports */ - "+VGM", /* V.253 10.5.2 - Microphone gain */ - "+VGR", /* V.253 10.2.1 - Receive gain selection */ - "+VGS", /* V.253 10.5.3 - Speaker gain */ - "+VGT", /* V.253 10.2.2 - Volume selection */ - "+VHC", /* V.252 4.12 - Telephony port hook control */ - "+VIP", /* V.253 10.1.1 - Initialize voice parameters */ - "+VIT", /* V.253 10.2.3 - DTE/DCE inactivity timer */ - "+VLS", /* V.253 10.2.4 - Analogue source/destination selection */ - "+VNH", /* V.253 9.2.5 - Automatic hangup control */ - "+VPH", /* V.252 4.11 - Phone hookswitch status */ - "+VPP", /* V.253 10.4.2 - Voice packet protocol */ - "+VPR", /* IS-101 10.4.3 - Select DTE/DCE interface rate */ - "+VRA", /* V.253 10.2.5 - Ringing tone goes away timer */ - "+VRID", /* Extension - Find the originating and destination numbers */ - "+VRL", /* V.253 10.1.2 - Ring local phone */ - "+VRN", /* V.253 10.2.6 - Ringing tone never appeared timer */ - "+VRX", /* V.253 10.1.3 - Voice receive state */ - "+VSD", /* V.253 10.2.7 - Silence detection (QUIET and SILENCE) */ - "+VSID", /* Extension - Set the originating number */ - "+VSM", /* V.253 10.2.8 - Compression method selection */ - "+VSP", /* V.253 10.5.1 - Voice speakerphone state */ - "+VTA", /* V.253 10.5.4 - Train acoustic echo-canceller */ - "+VTD", /* V.253 10.2.9 - Beep tone duration timer */ - "+VTER", /* V.252 6.4 - Simple telephony event report */ - "+VTH", /* V.253 10.5.5 - Train line echo-canceller */ - "+VTR", /* V.253 10.1.4 - Voice duplex state */ - "+VTS", /* V.253 10.1.5 - DTMF and tone generation in voice */ - "+VTX", /* V.253 10.1.6 - Transmit data state */ - "+VXT", /* IS-101 10.1.5 - Translate voice data */ - "+W", /* TIA-678 5.2.4.1 - Compliance indication */ - "+WBAG", /* TIA-678 C.5.6 Bias modem audio gain */ - "+WCDA", /* TIA-678 B.3.2.5 Display data link address */ - "+WCHG", /* TIA-678 B.3.2.4 Display battery charging status */ - "+WCID", /* TIA-678 B.3.2.1 Display system ID (operator) */ - "+WCLK", /* TIA-678 B.3.2.3 Lock/unlock DCE */ - "+WCPN", /* TIA-678 B.3.2.2 Set personal identification number */ - "+WCXF", /* TIA-678 B.3.2.6 Display supported annex B commands */ - "+WDAC", /* TIA-678 C.5.1 Data over analogue cellular command query */ - "+WDIR", /* TIA-678 C.5.8 Phone number directory selection */ - "+WECR", /* TIA-678 C.5.3 Enable cellular result codes */ - "+WFON", /* TIA-678 C.5.5 Phone specification */ - "+WKPD", /* TIA-678 C.5.7 Keypad emulation */ - "+WPBA", /* TIA-678 C.5.9 Phone battery query */ - "+WPTH", /* TIA-678 C.5.10 Call path */ - "+WRLK", /* TIA-678 C.5.4 Roam lockout */ - "+WS45", /* TIA-678 5.2.4.2 DTE-side stack selection */ - "+WS46", /* 3GPP TS 27.007 5.9 - PCCA STD-101 [17] select wireless network */ - "+WS50", /* TIA-678 B.3.1.1 Normalized signal strength */ - "+WS51", /* TIA-678 B.3.1.2 Carrier detect signal threshold */ - "+WS52", /* TIA-678 B.3.1.3 Normalized battery level */ - "+WS53", /* TIA-678 B.3.1.4 Normalized channel quality */ - "+WS54", /* TIA-678 B.3.1.5 Carrier detect channel quality threshold */ - "+WS57", /* TIA-678 B.3.1.7 Antenna preference */ - "+WS58", /* TIA-678 B.3.1.8 Idle time-out value */ - "+WSTL", /* TIA-678 C.5.2 Call session time limit */ - ";", /* Dummy to absorb semi-colon delimiters in commands */ - "A", /* V.250 6.3.5 - Answer */ - "D", /* V.250 6.3.1 - Dial */ - "E", /* V.250 6.2.4 - Command echo */ - "H", /* V.250 6.3.6 - Hook control */ - "I", /* V.250 6.1.3 - Request identification information */ - "L", /* V.250 6.3.13 - Monitor speaker loudness */ - "M", /* V.250 6.3.14 - Monitor speaker mode */ - "O", /* V.250 6.3.7 - Return to online data state */ - "P", /* V.250 6.3.3 - Select pulse dialling (command) */ - "Q", /* V.250 6.2.5 - Result code suppression */ - "S0", /* V.250 6.3.8 - Automatic answer */ - "S10", /* V.250 6.3.12 - Automatic disconnect delay */ - "S3", /* V.250 6.2.1 - Command line termination character */ - "S4", /* V.250 6.2.2 - Response formatting character */ - "S5", /* V.250 6.2.3 - Command line editing character */ - "S6", /* V.250 6.3.9 - Pause before blind dialling */ - "S7", /* V.250 6.3.10 - Connection completion timeout */ - "S8", /* V.250 6.3.11 - Comma dial modifier time */ - "T", /* V.250 6.3.2 - Select tone dialling (command) */ - "V", /* V.250 6.2.6 - DCE response format */ - "X", /* V.250 6.2.7 - Result code selection and call progress monitoring control */ - "Z", /* V.250 6.1.1 - Reset to default configuration */ - NULL -}; - -int packed_ptr = 0; - -short int packed_trie[30000]; - -#define ALPHABET_SIZE 128 - -typedef struct trie_node_s -{ - int first; - int last; - int node_no; - int entry; - /* Array of pointers to children */ - struct trie_node_s *child_list[ALPHABET_SIZE]; -} trie_node_t; - -typedef struct -{ - int entries; - /* The root of the trie */ - trie_node_t *root; -} trie_t; - -static trie_node_t *trie_node_create(void) -{ - trie_node_t *s; - - if ((s = (trie_node_t *) malloc(sizeof(*s)))) - { - memset(s, 0, sizeof(*s)); - s->first = ALPHABET_SIZE - 1; - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -static trie_t *trie_create(void) -{ - trie_t *s; - - if ((s = (trie_t *) malloc(sizeof(*s)))) - { - memset(s, 0, sizeof(*s)); - s->root = trie_node_create(); - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -static void trie_recursive_add_node_numbers(trie_node_t *t) -{ - int index; - - if (t) - { - if (t->first <= t->last) - { - t->node_no = packed_ptr + 1; - packed_ptr += (t->last - t->first + 1 + 3); - for (index = 0; index < ALPHABET_SIZE; index++) - trie_recursive_add_node_numbers(t->child_list[index]); - } - else - { - t->node_no = packed_ptr + 1; - packed_ptr += 3; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static void trie_recursive_build_packed_trie(trie_node_t *t) -{ - int i; - - if (t) - { - if (t->first <= t->last) - { - packed_trie[packed_ptr++] = t->first; - packed_trie[packed_ptr++] = t->last; - packed_trie[packed_ptr++] = t->entry; - for (i = t->first; i <= t->last; i++) - packed_trie[packed_ptr++] = (t->child_list[i]) ? t->child_list[i]->node_no : 0; - for (i = t->first; i <= t->last; i++) - trie_recursive_build_packed_trie(t->child_list[i]); - } - else - { - packed_trie[packed_ptr++] = 1; - packed_trie[packed_ptr++] = 0; - packed_trie[packed_ptr++] = t->entry; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static void trie_add(trie_t *s, const char *u, size_t len) -{ - size_t i; - int index; - trie_node_t *t; - - s->entries++; - /* Loop over the length of the string to add and traverse the trie... */ - for (t = s->root, i = 0; i < len; i++) - { - /* The character in u we are processing... */ - index = (unsigned char) u[i]; - - /* Is there a child node for this character? */ - if (t->child_list[index] == NULL) - { - if ((t->child_list[index] = trie_node_create()) == NULL) - exit(2); - if (index < t->first) - t->first = index; - if (index > t->last) - t->last = index; - } - - /* Move to the new node... and loop */ - t = t->child_list[index]; - } - t->entry = s->entries; -} -/*- End of function --------------------------------------------------------*/ - -static void dump_trie(void) -{ - int i; - - printf("\nstatic const at_cmd_service_t at_commands[] =\n{\n"); - for (i = 0; wordlist[i]; i++) - { - switch (wordlist[i][0]) - { - case ' ': - case ';': - printf(" at_cmd_dummy,\n"); - break; - case '+': - printf(" at_cmd_plus_%s,\n", wordlist[i] + 1); - break; - case '&': - printf(" at_cmd_amp_%s,\n", wordlist[i] + 1); - break; - default: - printf(" at_cmd_%s,\n", wordlist[i]); - break; - } - } - printf("};\n"); - - printf("\nstatic const uint16_t command_trie[] =\n{"); - for (i = 0; i < packed_ptr; i++) - { - if ((i & 7) == 0) - printf("\n "); - printf("0x%04X, ", packed_trie[i]); - } - printf("\n};\n"); - printf("\n#define COMMAND_TRIE_LEN %d\n", packed_ptr); - -} -/*- End of function --------------------------------------------------------*/ - -static void trie_recursive_free(trie_node_t *t) -{ - int i; - - if (t) - { - if (t->first <= t->last) - { - for (i = t->first; i <= t->last; i++) - trie_recursive_free(t->child_list[i]); - /*endfor*/ - } - /*endif*/ - free(t); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void trie_free(trie_t *s) -{ - if (s) - { - if (s->root) - trie_recursive_free(s->root); - /*endif*/ - free(s); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - trie_t *s; - int i; - - if ((s = trie_create()) == NULL) - exit(2); - /*endif*/ - - printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n"); - printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n"); - printf("\n"); - - for (i = 0; wordlist[i]; i++) - trie_add(s, wordlist[i], strlen(wordlist[i])); - /*endfor*/ - printf("// The trie contains %d entries\n", i); - - packed_ptr = 0; - trie_recursive_add_node_numbers(s->root); - packed_ptr = 0; - trie_recursive_build_packed_trie(s->root); - - dump_trie(); - - trie_free(s); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/make_cielab_luts.c b/libs/spandsp/src/make_cielab_luts.c deleted file mode 100644 index 151c94cfbc..0000000000 --- a/libs/spandsp/src/make_cielab_luts.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * make_cielab_luts.c - Create the look up tables for CIELab colour management - * - * 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 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 */ - -#include -#include -#include -#include -#include -#include -#include - -typedef struct -{ - float L; - float a; - float b; -} cielab_t; - -int main(int argc, char *argv[]) -{ - float r; - uint8_t srgb; - int i; - - printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n"); - printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n"); - printf("\n"); - - printf("static const float srgb_to_linear[256] =\n"); - printf("{\n"); - for (i = 0; i < 256; i++) - { - /* Start with "i" as the sRGB value */ - r = i/256.0f; - - /* sRGB to Linear RGB */ - r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f; - - printf((i < 255) ? " %f,\n" : " %f\n", r); - } - printf("};\n"); - - printf("static const uint8_t linear_to_srgb[4096] =\n"); - printf("{\n"); - for (i = 0; i < 4096; i++) - { - /* Start with "i" as the linear RGB value */ - /* Linear RGB to sRGB */ - r = i/4096.0f; - - r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f; - - r = floorf(r*256.0f); - - srgb = (uint8_t) ((r < 0) ? 0 : (r <= 255) ? r : 255); - - printf((i < 4095) ? " %d,\n" : " %d\n", srgb); - } - printf("};\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/make_math_fixed_tables.c b/libs/spandsp/src/make_math_fixed_tables.c deleted file mode 100644 index 642deff743..0000000000 --- a/libs/spandsp/src/make_math_fixed_tables.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * make_fixed_point_math_tables.c - Generate lookup tables for some of the - * fixed point maths functions. - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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; - double val; - int ival; - - printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n"); - printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n"); - printf("\n"); - - printf("static const uint16_t fixed_reciprocal_table[129] =\n"); - printf("{\n"); - for (i = 0; i < 129; i++) - { - val = 32768.0*128.0/(128 + i) + 0.5; - ival = (int) val; - if (i < 128) - printf(" %6d,\n", ival); - else - printf(" %6d\n", ival); - } - printf("};\n\n"); - - printf("static const uint16_t fixed_sqrt_table[193] =\n"); - printf("{\n"); - for (i = 64; i <= 256; i++) - { - ival = (int) (sqrt(i/256.0)*65536.0 + 0.5); - if (ival > 65535) - ival = 65535; - if (i < 256) - printf(" %6d,\n", ival); - else - printf(" %6d\n", ival); - } - printf("};\n\n"); - - printf("static const int16_t fixed_log10_table[129] =\n"); - printf("{\n"); - for (i = 128; i <= 256; i++) - { - ival = (int) (log10(i/256.0)*32768.0 - 0.5); - if (i <= 255) - printf(" %6d,\n", ival); - else - printf(" %6d\n", ival); - } - printf("};\n\n"); - - printf("static const int16_t fixed_sine_table[257] =\n"); - printf("{\n"); - for (i = 0; i <= 256; i++) - { - val = sin(i*3.1415926535/512.0)*32768.0; - ival = (int) (val + 0.5); - if (ival > 32767) - ival = 32767; - if (i <= 255) - printf(" %6d,\n", ival); - else - printf(" %6d\n", ival); - } - printf("};\n\n"); - - printf("static const uint16_t fixed_arctan_table[257] =\n"); - printf("{\n"); - for (i = 0; i <= 256; i++) - { - val = atan(i/256.0)*65536.0/(2.0*3.1415926535); - 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) - ival = 1; - if (i <= 255) - printf(" %6d,\n", ival); - else - printf(" %6d\n", ival); - } - printf("};\n\n"); - - 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 deleted file mode 100644 index 87e71b50ac..0000000000 --- a/libs/spandsp/src/make_modem_filter.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * make_modem_filter.c - Create coefficient sets for pulse shaping - * various modem rx and tx signals. - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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 -#include -#include -#include -#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" - -//#define SAMPLE_RATE 8000.0 -#define MAX_COEFFS_PER_FILTER 128 -#define MAX_COEFF_SETS 384 - -static void make_tx_filter(int coeff_sets, - int coeffs_per_filter, - double carrier, - double baud_rate, - double excess_bandwidth, - const char *tag) -{ - int i; - int j; - int x; - int total_coeffs; - double alpha; - double beta; - double floating_gain; - double fixed_gain; - double fixed_scaling; - double peak; - double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1]; - - total_coeffs = coeff_sets*coeffs_per_filter + 1; - alpha = baud_rate/(2.0*(double) (coeff_sets*baud_rate)); - beta = excess_bandwidth; - - 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; - for (i = coeff_sets/2; i < total_coeffs; i += coeff_sets) - floating_gain += coeffs[i]; - /* Normalise the gain to 1.0 */ - for (i = 0; i < total_coeffs; i++) - coeffs[i] /= floating_gain; - floating_gain = 1.0; - fixed_gain = 1.0; - - peak = -1.0; - for (i = 0; i < total_coeffs; i++) - { - if (fabs(coeffs[i]) > peak) - peak = fabs(coeffs[i]); - } - fixed_scaling = 32767.0f; - if (peak >= 1.0) - { - fixed_scaling /= peak; - fixed_gain = 1.0/peak; - } - - /* Churn out the data as a C source code header file, which can be directly included by the - modem code. */ - printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n"); - printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n"); - printf("\n"); - printf("#if defined(SPANDSP_USE_FIXED_POINT)\n"); - printf("#define TX_PULSESHAPER%s_SCALE(x) ((int16_t) (%f*x + ((x >= 0.0) ? 0.5 : -0.5)))\n", tag, fixed_scaling); - printf("#define TX_PULSESHAPER%s_GAIN %ff\n", tag, fixed_gain); - printf("#else\n"); - printf("#define TX_PULSESHAPER%s_SCALE(x) (x)\n", tag); - printf("#define TX_PULSESHAPER%s_GAIN %ff\n", tag, floating_gain); - printf("#endif\n"); - printf("#define TX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets); - printf("\n"); - printf("#if defined(SPANDSP_USE_FIXED_POINT)\n"); - printf("static const int16_t tx_pulseshaper%s[TX_PULSESHAPER%s_COEFF_SETS][%d] =\n", - tag, - tag, - coeffs_per_filter); - printf("#else\n"); - printf("static const float tx_pulseshaper%s[TX_PULSESHAPER%s_COEFF_SETS][%d] =\n", - tag, - tag, - coeffs_per_filter); - printf("#endif\n"); - printf("{\n"); - for (j = 0; j < coeff_sets; j++) - { - x = j; - printf(" {\n"); - printf(" TX_PULSESHAPER%s_SCALE(%15.10ff), /* Filter %d */\n", tag, coeffs[x], j); - for (i = 1; i < coeffs_per_filter - 1; i++) - { - x = i*coeff_sets + j; - printf(" TX_PULSESHAPER%s_SCALE(%15.10ff),\n", tag, coeffs[x]); - } - x = i*coeff_sets + j; - printf(" TX_PULSESHAPER%s_SCALE(%15.10ff)\n", tag, coeffs[x]); - if (j < coeff_sets - 1) - printf(" },\n"); - else - printf(" }\n"); - } - printf("};\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void make_rx_filter(int coeff_sets, - int coeffs_per_filter, - double carrier, - double baud_rate, - double excess_bandwidth, - const char *tag) -{ - int i; - int j; - int k; - int m; - int x; - int total_coeffs; - double alpha; - double beta; - double floating_gain; - double fixed_gain; - double fixed_scaling; - double peak; - double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1]; - double cox[MAX_COEFFS_PER_FILTER]; - - total_coeffs = coeff_sets*coeffs_per_filter + 1; - alpha = baud_rate/(2.0*(double) (coeff_sets*SAMPLE_RATE)); - beta = excess_bandwidth; - carrier *= 2.0*3.1415926535/SAMPLE_RATE; - - 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; - for (i = coeff_sets/2; i < total_coeffs; i += coeff_sets) - floating_gain += coeffs[i]; - /* Normalise the gain to 1.0 */ - for (i = 0; i < total_coeffs; i++) - coeffs[i] /= floating_gain; - floating_gain = 1.0; - fixed_gain = 1.0; - - peak = -1.0; - for (i = 0; i < total_coeffs; i++) - { - if (fabs(coeffs[i]) > peak) - peak = fabs(coeffs[i]); - } - fixed_scaling = 32767.0f; - if (peak >= 1.0) - { - fixed_scaling /= peak; - fixed_gain = 1.0/peak; - } - - /* Churn out the data as a C source code header file, which can be directly included by the - modem code. */ - printf("#if defined(SPANDSP_USE_FIXED_POINT)\n"); - printf("#define RX_PULSESHAPER%s_SCALE(x) ((int16_t) (%f*x + ((x >= 0.0) ? 0.5 : -0.5)))\n", tag, fixed_scaling); - printf("#define RX_PULSESHAPER%s_GAIN %ff\n", tag, fixed_gain); - printf("#else\n"); - printf("#define RX_PULSESHAPER%s_SCALE(x) (x)\n", tag); - printf("#define RX_PULSESHAPER%s_GAIN %ff\n", tag, floating_gain); - printf("#endif\n"); - printf("#define RX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets); - for (k = 0; k < 2; k++) - { - printf("\n"); - printf("#if defined(SPANDSP_USE_FIXED_POINT)\n"); - printf("static const int16_t rx_pulseshaper%s_%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n", - tag, - (k == 0) ? "re" : "im", - tag, - coeffs_per_filter); - printf("#else\n"); - printf("static const float rx_pulseshaper%s_%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n", - tag, - (k == 0) ? "re" : "im", - tag, - coeffs_per_filter); - printf("#endif\n"); - printf("{\n"); - for (j = 0; j < coeff_sets; j++) - { - /* Complex modulate the filter, to make it a complex pulse shaping bandpass filter - centred at the nominal carrier frequency. Use the same phase for all the coefficient - sets. This means the modem can step the carrier in whole samples, and not worry about - the fractional sample shift caused by selecting amongst the various coefficient sets. */ - for (i = 0; i < coeffs_per_filter; i++) - { - m = i - (coeffs_per_filter >> 1); - x = i*coeff_sets + j; - if (k == 0) - cox[i] = coeffs[x]*cos(carrier*m); - else - cox[i] = coeffs[x]*sin(carrier*m); - } - printf(" {\n"); - printf(" RX_PULSESHAPER%s_SCALE(%15.10ff), /* Filter %d */\n", tag, cox[0], j); - for (i = 1; i < coeffs_per_filter - 1; i++) - printf(" RX_PULSESHAPER%s_SCALE(%15.10ff),\n", tag, cox[i]); - printf(" RX_PULSESHAPER%s_SCALE(%15.10ff)\n", tag, cox[i]); - if (j < coeff_sets - 1) - printf(" },\n"); - else - printf(" }\n"); - } - printf("};\n"); - } -} -/*- End of function --------------------------------------------------------*/ - -static void usage(void) -{ - fprintf(stderr, "Usage: make_modem_rx_filter -m [-r] [-t]\n"); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char **argv) -{ - int rx_coeff_sets; - int rx_coeffs_per_filter; - int tx_coeff_sets; - int tx_coeffs_per_filter; - int opt; - int transmit_modem; - double carrier; - double baud_rate; - double rx_excess_bandwidth; - double tx_excess_bandwidth; - const char *rx_tag; - const char *tx_tag; - const char *modem; - - transmit_modem = false; - modem = ""; - while ((opt = getopt(argc, argv, "m:rt")) != -1) - { - switch (opt) - { - case 'm': - modem = optarg; - break; - case 'r': - transmit_modem = false; - break; - case 't': - transmit_modem = true; - break; - default: - usage(); - exit(2); - break; - } - } - if (strcmp(modem, "V.17") == 0 || strcmp(modem, "V.32bis") == 0) - { - /* This applies to V.32bis as well as V.17 */ - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.5; - tx_coeff_sets = 10; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.25; - carrier = 1800.0; - baud_rate = 2400.0; - rx_tag = ""; - tx_tag = ""; - } - else if (strcmp(modem, "V.22bis") == 0) - { - /* This is only intended to apply to transmit. */ - rx_coeff_sets = 12; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.75; - tx_coeff_sets = 40; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.75; - carrier = 1200.0; - baud_rate = 600.0; - rx_tag = ""; - tx_tag = ""; - } - else if (strcmp(modem, "V.22bis1200") == 0) - { - /* This is only intended to apply to receive. */ - rx_coeff_sets = 12; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.75; - tx_coeff_sets = 40; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.75; - carrier = 1200.0; - baud_rate = 600.0; - rx_tag = "_1200"; - tx_tag = "_1200"; - } - else if (strcmp(modem, "V.22bis2400") == 0) - { - /* This is only intended to apply to receive. */ - rx_coeff_sets = 12; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.75; - tx_coeff_sets = 40; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.75; - carrier = 2400.0; - baud_rate = 600.0; - rx_tag = "_2400"; - tx_tag = "_2400"; - } - else if (strcmp(modem, "V.27ter2400") == 0) - { - rx_coeff_sets = 12; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.5; - tx_coeff_sets = 20; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.5; - carrier = 1800.0; - baud_rate = 1200.0; - rx_tag = "_2400"; - tx_tag = "_2400"; - } - else if (strcmp(modem, "V.27ter4800") == 0) - { - rx_coeff_sets = 8; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.5; - tx_coeff_sets = 5; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.5; - carrier = 1800.0; - baud_rate = 1600.0; - rx_tag = "_4800"; - tx_tag = "_4800"; - } - else if (strcmp(modem, "V.29") == 0) - { - rx_coeff_sets = 48; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.5; - tx_coeff_sets = 10; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.25; - carrier = 1700.0; - baud_rate = 2400.0; - rx_tag = ""; - tx_tag = ""; - } - else if (strcmp(modem, "V.34_2400") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 10; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1600.0; - baud_rate = 2400.0; - rx_tag = "_2400_low_carrier"; - tx_tag = "_2400"; - } - else if (strcmp(modem, "V.34_2400_high") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 10; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1800.0; - baud_rate = 2400.0; - rx_tag = "_2400_high_carrier"; - tx_tag = "_2400"; - } - else if (strcmp(modem, "V.34_2743") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 35; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1646.0; - baud_rate = 2400.0*8.0/7.0; - rx_tag = "_2743_low_carrier"; - tx_tag = "_2743"; - } - else if (strcmp(modem, "V.34_2743_high") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 35; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1829.0; - baud_rate = 2400.0*8.0/7.0; - rx_tag = "_2743_high_carrier"; - tx_tag = "_2743"; - } - else if (strcmp(modem, "V.34_2800") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 20; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1680.0; - baud_rate = 2400.0*7.0/6.0; - rx_tag = "_2800_low_carrier"; - tx_tag = "_2800"; - } - else if (strcmp(modem, "V.34_2800_high") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 20; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1867.0; - baud_rate = 2400.0*7.0/6.0; - rx_tag = "_2800_high_carrier"; - tx_tag = "_2800"; - } - else if (strcmp(modem, "V.34_3000") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 8; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1800.0; - baud_rate = 2400.0*5.0/4.0; - rx_tag = "_3000_low_carrier"; - tx_tag = "_3000"; - } - else if (strcmp(modem, "V.34_3000_high") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 8; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 2000.0; - baud_rate = 2400.0*5.0/4.0; - rx_tag = "_3000_high_carrier"; - tx_tag = "_3000"; - } - else if (strcmp(modem, "V.34_3200") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 5; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1829.0; - baud_rate = 2400.0*4.0/3.0; - rx_tag = "_3200_low_carrier"; - tx_tag = "_3200"; - } - else if (strcmp(modem, "V.34_3200_high") == 0) - { - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 5; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - carrier = 1920.0; - baud_rate = 2400.0*4.0/3.0; - rx_tag = "_3200_high_carrier"; - tx_tag = "_3200"; - } - else if (strcmp(modem, "V.34_3429") == 0) - { - /* There is only one carrier frequency defined for this baud rate */ - rx_coeff_sets = 192; - rx_coeffs_per_filter = 27; - rx_excess_bandwidth = 0.25; - tx_coeff_sets = 7; - tx_coeffs_per_filter = 9; - tx_excess_bandwidth = 0.12; - //carrier = 1959.0; - carrier = 1959.0; - baud_rate = 2400.0*10.0/7.0; - rx_tag = "_3429"; - tx_tag = "_3429"; - } - else - { - usage(); - exit(2); - } - if (transmit_modem) - { - make_tx_filter(tx_coeff_sets, - tx_coeffs_per_filter, - carrier, - baud_rate, - tx_excess_bandwidth, - tx_tag); - } - else - { - make_rx_filter(rx_coeff_sets, - rx_coeffs_per_filter, - carrier, - baud_rate, - rx_excess_bandwidth, - rx_tag); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/make_t43_gray_code_tables.c b/libs/spandsp/src/make_t43_gray_code_tables.c deleted file mode 100644 index 9fd1befd5c..0000000000 --- a/libs/spandsp/src/make_t43_gray_code_tables.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n"); - printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n"); - printf("\n"); - - 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/math_fixed.c b/libs/spandsp/src/math_fixed.c deleted file mode 100644 index f538f106f4..0000000000 --- a/libs/spandsp/src/math_fixed.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * math_fixed.c - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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 -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" -#include - -#include "math_fixed_tables.h" - -#include "spandsp/telephony.h" -#include "spandsp/bit_operations.h" -#include "spandsp/math_fixed.h" - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(uint16_t) sqrtu32_u16(uint32_t x) -{ - uint16_t zz; - uint16_t z; - uint16_t i; - - z = 0; - for (i = 0x8000; i; i >>= 1) - { - zz = z | i; - if (((int32_t) zz*zz) <= x) - z = zz; - } - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(uint16_t) fixed_reciprocal16(uint16_t x, int *shift) -{ - if (x == 0) - { - *shift = 0; - return 0xFFFF; - } - *shift = 15 - top_bit(x); - x <<= *shift; - return fixed_reciprocal_table[((x + 0x80) >> 8) - 128]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) fixed_divide16(uint16_t y, uint16_t x) -{ - int shift; - uint32_t z; - uint16_t recip; - - if (x == 0) - return 0xFFFF; - recip = fixed_reciprocal16(x, &shift); - z = (((uint32_t) y*recip) >> 15) << shift; - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) fixed_divide32(uint32_t y, uint16_t x) -{ - int shift; - uint32_t z; - uint16_t recip; - - if (x == 0) - return 0xFFFF; - recip = fixed_reciprocal16(x, &shift); - z = (((uint32_t) y*recip) >> 15) << shift; - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) fixed_log10_16(uint16_t x) -{ - int shift; - - if (x == 0) - return 0; - shift = 14 - top_bit(x); - x <<= shift; - return (fixed_log10_table[((x + 0x40) >> 7) - 128] >> 3) - shift*1233; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) fixed_log10_32(uint32_t x) -{ - int shift; - - if (x == 0) - return 0; - shift = 30 - top_bit(x); - x <<= shift; - return (fixed_log10_table[((x + 0x400000) >> 23) - 128] >> 3) - shift*1233; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) fixed_sqrt16(uint16_t x) -{ - int shift; - - if (x == 0) - return 0; - shift = 14 - (top_bit(x) & ~1); - x <<= shift; - //return fixed_sqrt_table[(((x + 0x80) >> 8) & 0xFF) - 64] >> (shift >> 1); - return fixed_sqrt_table[((x >> 8) & 0xFF) - 64] >> (shift >> 1); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) fixed_sqrt32(uint32_t x) -{ - int shift; - - if (x == 0) - return 0; - shift = 30 - (top_bit(x) & ~1); - x <<= shift; - //return fixed_sqrt_table[(((x + 0x800000) >> 24) & 0xFF) - 64] >> (shift >> 1); - return fixed_sqrt_table[((x >> 24) & 0xFF) - 64] >> (shift >> 1); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) fixed_sin(uint16_t x) -{ - int step; - int step_after; - int16_t frac; - int16_t z; - - step = (x & 0x3FFF) >> 6; - frac = x & 0x3F; - if ((x & 0x4000)) - { - step = 256 - step; - step_after = step - 1; - } - else - { - step_after = step + 1; - } - z = fixed_sine_table[step] + ((frac*(fixed_sine_table[step_after] - fixed_sine_table[step])) >> 6); - if ((x & 0x8000)) - z = -z; - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) fixed_cos(uint16_t x) -{ - int step; - int step_after; - int16_t frac; - int16_t z; - - x += 0x4000; - step = (x & 0x3FFF) >> 6; - frac = x & 0x3F; - if ((x & 0x4000)) - { - step = 256 - step; - step_after = step - 1; - } - else - { - step_after = step + 1; - } - z = fixed_sine_table[step] + ((frac*(fixed_sine_table[step_after] - fixed_sine_table[step])) >> 6); - if ((x & 0x8000)) - z = -z; - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint16_t) fixed_atan2(int16_t y, int16_t x) -{ - int16_t abs_x; - int16_t abs_y; - uint16_t angle; - uint16_t recip; - uint32_t z; - int step; - int shift; - - if (y == 0) - return (x & 0x8000); - if (x == 0) - return ((y & 0x8000) | 0x4000); - abs_x = abs(x); - abs_y = abs(y); - - if (abs_y < abs_x) - { - recip = fixed_reciprocal16(abs_x, &shift); - z = (((uint32_t) recip*abs_y) >> 15) << shift; - step = z >> 7; - angle = fixed_arctan_table[step]; - } - else - { - recip = fixed_reciprocal16(abs_y, &shift); - z = (((uint32_t) recip*abs_x) >> 15) << shift; - step = z >> 7; - angle = 0x4000 - fixed_arctan_table[step]; - } - /* If we are in quadrant II or III, flip things around */ - if (x < 0) - angle = 0x8000 - angle; - /* If we are in quadrant III or IV, negate to return an - answer in the full circle range. */ - if (y < 0) - angle = -angle; - return (uint16_t) angle; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/mmx_sse_decs.h b/libs/spandsp/src/mmx_sse_decs.h deleted file mode 100644 index 5ebd5f95c9..0000000000 --- a/libs/spandsp/src/mmx_sse_decs.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * mmx_sse_decs.h - Pull in the appropriate systems headers for the MMX/SSE settings. - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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(_MMX_SSE_DECS_H_) -#define _MMX_SSE_DECS_H_ - -#if defined(SPANDSP_USE_MMX) -#include -#endif -#if defined(SPANDSP_USE_SSE) -#include -#endif -#if defined(SPANDSP_USE_SSE2) -#include -#endif -#if defined(SPANDSP_USE_SSE3) -#include -#endif -#if defined(SPANDSP_USE_SSSE3) -#include -#endif -#if defined(SPANDSP_USE_SSE4_1) -#include -#endif -#if defined(SPANDSP_USE_SSE4_2) -#include -#endif -#if defined(SPANDSP_USE_SSE4A) -#include -#endif -#if defined(SPANDSP_USE_SSE5) -#include -#endif -#if defined(SPANDSP_USE_AVX) -#include -#endif -#if defined(SPANDSP_USE_AVX2) -#include -#endif - -#endif - -/*- End of include ---------------------------------------------------------*/ diff --git a/libs/spandsp/src/modem_connect_tones.c b/libs/spandsp/src/modem_connect_tones.c deleted file mode 100644 index cb43f219e0..0000000000 --- a/libs/spandsp/src/modem_connect_tones.c +++ /dev/null @@ -1,779 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_connect_tones.c - Generation and detection of tones - * associated with modems calling and answering calls. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 */ - -/* CNG is 0.5s+-15% of 1100+-38Hz, 3s+-15% off, repeating. - - CED is 0.2s silence, 3.3+-0.7s of 2100+-15Hz, and 75+-20ms of silence. - - Calling tone is 0.5s-0.7s of 1300Hz+-15Hz, 1.5s-2.0s off, repeating. - - ANS is 3.3+-0.7s of 2100+-15Hz. - - ANS/ is 3.3+-0.7s of 2100+-15Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms. - - ANSam/ is 2100+-1Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms, and AM with a sinewave of 15+-0.1Hz. - The modulated envelope ranges in amplitude between (0.8+-0.01) and (1.2+-0.01) times its average - amplitude. It lasts up to 5s, but will be stopped early if the V.8 protocol proceeds. */ - -#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 -#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" -#include "spandsp/dds.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/power_meter.h" -#include "spandsp/async.h" -#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" - -#define HDLC_FRAMING_OK_THRESHOLD 5 - -SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone) -{ - switch (tone) - { - case MODEM_CONNECT_TONES_NONE: - return "No tone"; - case MODEM_CONNECT_TONES_FAX_CNG: - return "FAX CNG"; - case MODEM_CONNECT_TONES_ANS: - return "ANS or FAX CED"; - case MODEM_CONNECT_TONES_ANS_PR: - return "ANS/"; - case MODEM_CONNECT_TONES_ANSAM: - return "ANSam"; - case MODEM_CONNECT_TONES_ANSAM_PR: - return "ANSam/"; - case MODEM_CONNECT_TONES_FAX_PREAMBLE: - return "FAX preamble"; - case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: - return "FAX CED or preamble"; - case MODEM_CONNECT_TONES_BELL_ANS: - return "Bell ANS"; - case MODEM_CONNECT_TONES_CALLING_TONE: - return "Calling tone"; - } - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s, - int16_t amp[], - int len) -{ - int16_t mod; - int i; - int xlen; - - i = 0; - switch (s->tone_type) - { - case MODEM_CONNECT_TONES_FAX_CNG: - for ( ; i < len; i++) - { - if (s->duration_timer > ms_to_samples(3000)) - { - if ((xlen = i + s->duration_timer - ms_to_samples(3000)) > len) - xlen = len; - s->duration_timer -= (xlen - i); - for ( ; i < xlen; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); - } - if (s->duration_timer > 0) - { - if ((xlen = i + s->duration_timer) > len) - xlen = len; - s->duration_timer -= (xlen - i); - memset(amp + i, 0, sizeof(int16_t)*(xlen - i)); - i = xlen; - } - if (s->duration_timer == 0) - s->duration_timer = ms_to_samples(500 + 3000); - } - break; - case MODEM_CONNECT_TONES_ANS: - if (s->duration_timer < len) - len = s->duration_timer; - if (s->duration_timer > ms_to_samples(2600)) - { - /* There is some initial silence to be generated. */ - if ((i = s->duration_timer - ms_to_samples(2600)) > len) - i = len; - memset(amp, 0, sizeof(int16_t)*i); - } - for ( ; i < len; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); - s->duration_timer -= len; - break; - case MODEM_CONNECT_TONES_ANS_PR: - if (s->duration_timer < len) - len = s->duration_timer; - if (s->duration_timer > ms_to_samples(3300)) - { - if ((i = s->duration_timer - ms_to_samples(3300)) > len) - i = len; - memset(amp, 0, sizeof(int16_t)*i); - } - for ( ; i < len; i++) - { - if (--s->hop_timer <= 0) - { - s->hop_timer = ms_to_samples(450); - s->tone_phase += 0x80000000; - } - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); - } - s->duration_timer -= len; - break; - case MODEM_CONNECT_TONES_ANSAM: - if (s->duration_timer < len) - len = s->duration_timer; - if (s->duration_timer > ms_to_samples(5000)) - { - if ((i = s->duration_timer - ms_to_samples(5000)) > len) - i = len; - memset(amp, 0, sizeof(int16_t)*i); - } - for ( ; i < len; i++) - { - mod = (int16_t) (s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0)); - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); - } - s->duration_timer -= len; - break; - case MODEM_CONNECT_TONES_ANSAM_PR: - if (s->duration_timer < len) - len = s->duration_timer; - if (s->duration_timer > ms_to_samples(5000)) - { - if ((i = s->duration_timer - ms_to_samples(5000)) > len) - i = len; - memset(amp, 0, sizeof(int16_t)*i); - } - for ( ; i < len; i++) - { - if (--s->hop_timer <= 0) - { - s->hop_timer = ms_to_samples(450); - s->tone_phase += 0x80000000; - } - mod = (int16_t) (s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0)); - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); - } - s->duration_timer -= len; - break; - case MODEM_CONNECT_TONES_BELL_ANS: - if (s->duration_timer < len) - len = s->duration_timer; - if (s->duration_timer > ms_to_samples(2600)) - { - /* There is some initial silence to be generated. */ - if ((i = s->duration_timer - ms_to_samples(2600)) > len) - i = len; - memset(amp, 0, sizeof(int16_t)*i); - } - for ( ; i < len; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); - s->duration_timer -= len; - break; - case MODEM_CONNECT_TONES_CALLING_TONE: - for ( ; i < len; i++) - { - if (s->duration_timer > ms_to_samples(2000)) - { - if ((xlen = i + s->duration_timer - ms_to_samples(2000)) > len) - xlen = len; - s->duration_timer -= (xlen - i); - for ( ; i < xlen; i++) - amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); - } - if (s->duration_timer > 0) - { - if ((xlen = i + s->duration_timer) > len) - xlen = len; - s->duration_timer -= (xlen - i); - memset(amp + i, 0, sizeof(int16_t)*(xlen - i)); - i = xlen; - } - if (s->duration_timer == 0) - s->duration_timer = ms_to_samples(600 + 2000); - } - break; - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem_connect_tones_tx_state_t *s, - int tone_type) -{ - int alloced; - - alloced = false; - if (s == NULL) - { - if ((s = (modem_connect_tones_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - alloced = true; - } - s->tone_type = tone_type; - switch (s->tone_type) - { - case MODEM_CONNECT_TONES_FAX_CNG: - /* 0.5s of 1100Hz+-38Hz + 3.0s of silence repeating. Timing +-15% */ - s->tone_phase_rate = dds_phase_rate(1100.0); - s->level = dds_scaling_dbm0(-11); - s->duration_timer = ms_to_samples(500 + 3000); - s->mod_phase_rate = 0; - s->tone_phase = 0; - s->mod_phase = 0; - s->mod_level = 0; - s->hop_timer = 0; - break; - case MODEM_CONNECT_TONES_ANS: - case MODEM_CONNECT_TONES_ANSAM: - /* 0.2s of silence, then 2.6s to 4s of 2100Hz+-15Hz tone, then 75ms of silence. */ - s->tone_phase_rate = dds_phase_rate(2100.0); - s->level = dds_scaling_dbm0(-11); - if (s->tone_type == MODEM_CONNECT_TONES_ANSAM) - { - s->mod_phase_rate = dds_phase_rate(15.0); - s->mod_level = s->level/5; - s->duration_timer = ms_to_samples(200 + 5000); - } - else - { - s->mod_phase_rate = 0; - s->mod_level = 0; - s->duration_timer = ms_to_samples(200 + 2600); - } - s->tone_phase = 0; - s->mod_phase = 0; - s->hop_timer = 0; - break; - case MODEM_CONNECT_TONES_ANS_PR: - case MODEM_CONNECT_TONES_ANSAM_PR: - s->tone_phase_rate = dds_phase_rate(2100.0); - s->level = dds_scaling_dbm0(-12); - if (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR) - { - s->mod_phase_rate = dds_phase_rate(15.0); - s->mod_level = s->level/5; - s->duration_timer = ms_to_samples(200 + 5000); - } - else - { - s->mod_phase_rate = 0; - s->mod_level = 0; - s->duration_timer = ms_to_samples(200 + 3300); - } - s->tone_phase = 0; - s->mod_phase = 0; - s->hop_timer = ms_to_samples(450); - break; - case MODEM_CONNECT_TONES_BELL_ANS: - /* 0.2s of silence, then 2.6s to 4s of 2225Hz+-15Hz tone, then 75ms of silence. */ - s->tone_phase_rate = dds_phase_rate(2225.0); - s->level = dds_scaling_dbm0(-11); - s->mod_phase_rate = 0; - s->mod_level = 0; - s->duration_timer = ms_to_samples(200 + 2600); - s->tone_phase = 0; - s->mod_phase = 0; - s->hop_timer = 0; - break; - case MODEM_CONNECT_TONES_CALLING_TONE: - /* 0.6s of 1300Hz+-15Hz + 2.0s of silence repeating. */ - s->tone_phase_rate = dds_phase_rate(1300.0); - s->level = dds_scaling_dbm0(-11); - s->duration_timer = ms_to_samples(600 + 2000); - s->mod_phase_rate = 0; - s->tone_phase = 0; - s->mod_phase = 0; - s->mod_level = 0; - s->hop_timer = 0; - break; - default: - if (alloced) - span_free(s); - return NULL; - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_tx_release(modem_connect_tones_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void report_tone_state(modem_connect_tones_rx_state_t *s, int tone, int level) -{ - if (tone != s->tone_present) - { - if (s->tone_callback) - { - s->tone_callback(s->callback_data, tone, level, 0); - } - else - { - if (tone != MODEM_CONNECT_TONES_NONE) - s->hit = tone; - } - s->tone_present = tone; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v21_put_bit(void *user_data, int bit) -{ - modem_connect_tones_rx_state_t *s; - - s = (modem_connect_tones_rx_state_t *) user_data; - if (bit < 0) - { - /* Special conditions. */ - switch (bit) - { - case SIG_STATUS_CARRIER_DOWN: - /* Only declare tone off, if we were the one to declare tone on. */ - if (s->tone_present == MODEM_CONNECT_TONES_FAX_PREAMBLE) - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - /* Fall through */ - case SIG_STATUS_CARRIER_UP: - s->raw_bit_stream = 0; - s->num_bits = 0; - s->flags_seen = 0; - s->framing_ok_announced = false; - break; - } - return; - } - /* Look for enough FAX V.21 message preamble (back to back HDLC flag octets) to be sure - we are really seeing preamble, and declare the signal to be present. Any change from - preamble declares the signal to not be present, though it will probably be the body - of the messages following the preamble. */ - s->raw_bit_stream = (s->raw_bit_stream << 1) | ((bit << 8) & 0x100); - s->num_bits++; - if ((s->raw_bit_stream & 0x7F00) == 0x7E00) - { - if ((s->raw_bit_stream & 0x8000)) - { - /* Hit HDLC abort */ - s->flags_seen = 0; - } - else - { - /* Hit HDLC flag */ - if (s->flags_seen < HDLC_FRAMING_OK_THRESHOLD) - { - /* Check the flags are back-to-back when testing for valid preamble. This - greatly reduces the chances of false preamble detection, and anything - which doesn't send them back-to-back is badly broken. */ - if (s->num_bits != 8) - s->flags_seen = 0; - 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->num_bits = 0; - } - else - { - if (s->flags_seen >= HDLC_FRAMING_OK_THRESHOLD) - { - if (s->num_bits == 8) - { - s->framing_ok_announced = false; - s->flags_seen = 0; - } - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s, - const int16_t amp[], - int len) -{ - int i; - int16_t notched; - float v1; - float famp; - float filtered; - - switch (s->tone_type) - { - case MODEM_CONNECT_TONES_FAX_CNG: - for (i = 0; i < len; i++) - { - famp = amp[i]; - /* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth - criteria. */ - /* Poles 0.736618498*exp(+-1047/4000 * PI * j) - Zeroes exp(+-1099.5/4000 * PI * j) */ - v1 = 0.792928f*famp + 1.0018744927985f*s->znotch_1 - 0.54196833412465f*s->znotch_2; - famp = v1 - 1.2994747954630f*s->znotch_1 + s->znotch_2; - s->znotch_2 = s->znotch_1; - s->znotch_1 = v1; - notched = (int16_t) lfastrintf(famp); - - /* Estimate the overall energy in the channel, and the energy in - the notch (i.e. overall channel energy - tone energy => noise). - Use abs instead of multiply for speed (is it really faster?). */ - s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); - s->notch_level += ((abs(notched) - s->notch_level) >> 5); - if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) - { - /* There is adequate energy in the channel, and it is mostly at 1100Hz. */ - if (s->tone_present != MODEM_CONNECT_TONES_FAX_CNG) - { - if (++s->tone_cycle_duration >= ms_to_samples(415)) - report_tone_state(s, MODEM_CONNECT_TONES_FAX_CNG, lfastrintf(((s->channel_level == 0) ? (-96.329f + DBM0_MAX_POWER) : log10f(s->channel_level/32768.0f)*20.0f) + DBM0_MAX_POWER + 0.8f)); - } - } - else - { - /* If the signal looks wrong, even for a moment, we consider this the - end of the tone. */ - if (s->tone_present == MODEM_CONNECT_TONES_FAX_CNG) - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - s->tone_cycle_duration = 0; - } - } - break; - case MODEM_CONNECT_TONES_FAX_PREAMBLE: - /* Ignore any CED tone, and just look for V.21 preamble. */ - fsk_rx(&(s->v21rx), amp, len); - break; - case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: - /* Also look for V.21 preamble. A lot of machines don't send the 2100Hz burst. It - might also not be seen all the way through the channel, due to switching delays. */ - fsk_rx(&(s->v21rx), amp, len); - /* Now fall through and look for a 2100Hz tone */ - case MODEM_CONNECT_TONES_ANS: - for (i = 0; i < len; i++) - { - famp = amp[i]; - /* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */ - /* Poles 0.9983989*exp(+-15/4000 * PI * j) - Zeroes exp(0/4000 * PI * j) */ - v1 = fabs(famp) + 1.996667f*s->z15hz_1 - 0.9968004f*s->z15hz_2; - filtered = 0.001599787f*(v1 - s->z15hz_2); - s->z15hz_2 = s->z15hz_1; - s->z15hz_1 = v1; - s->am_level += abs((int) lfastrintf(filtered)) - (s->am_level >> 8); - //printf("%9.1f %10.4f %9d %9d\n", famp, filtered, s->am_level, s->channel_level); - /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth - criteria. */ - /* Poles 0.7144255*exp(+-2105.612/4000 * PI * j) - Zeroes exp(+-2099.9/4000 * PI * j) */ - v1 = 0.7552f*famp - 0.1183852f*s->znotch_1 - 0.5104039f*s->znotch_2; - famp = v1 + 0.1567596f*s->znotch_1 + s->znotch_2; - s->znotch_2 = s->znotch_1; - s->znotch_1 = v1; - notched = (int16_t) lfastrintf(famp); - /* Estimate the overall energy in the channel, and the energy in - the notch (i.e. overall channel energy - tone energy => noise). - Use abs instead of multiply for speed (is it really faster?). - Damp the overall energy a little more for a stable result. - Damp the notch energy a little less, so we don't damp out the - blip every time the phase reverses. */ - s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); - s->notch_level += ((abs(notched) - s->notch_level) >> 4); - /* This should cut off at about -43dBm0 */ - if (s->channel_level <= 70) - { - /* If the energy level is low, even for a moment, we consider this the - end of the tone. */ - if (s->tone_present != MODEM_CONNECT_TONES_NONE) - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - s->tone_cycle_duration = 0; - s->good_cycles = 0; - s->tone_on = false; - continue; - } - /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ - s->tone_cycle_duration++; - if (s->notch_level*6 < s->channel_level) - { - /* The notch test says yes, so we have the tone. */ - /* We should get a kick from the notch filter every 450+-25ms, as the phase reverses, for an - EC disable tone. For a simple answer tone, the tone should persist unbroken for longer. */ - if (!s->tone_on) - { - if (s->tone_cycle_duration >= ms_to_samples(450 - 25)) - { - if (++s->good_cycles == 3) - { - report_tone_state(s, - (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANS_PR, - lfastrintf(((s->channel_level == 0) ? (-96.329f + DBM0_MAX_POWER) : log10f(s->channel_level/32768.0f)*20.0f) + DBM0_MAX_POWER + 0.8f)); - } - } - else - { - s->good_cycles = 0; - } - /* Cycles are timed from rising edge to rising edge */ - s->tone_cycle_duration = 0; - } - else - { - if (s->tone_cycle_duration >= ms_to_samples(450 + 100)) - { - if (s->tone_present == MODEM_CONNECT_TONES_NONE) - { - report_tone_state(s, - (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM : MODEM_CONNECT_TONES_ANS, - lfastrintf(((s->channel_level == 0) ? (-96.329f + DBM0_MAX_POWER) : log10f(s->channel_level/32768.0f)*20.0f) + DBM0_MAX_POWER + 0.8f)); - } - s->good_cycles = 0; - s->tone_cycle_duration = ms_to_samples(450 + 100); - } - } - s->tone_on = true; - } - else if (s->notch_level*5 > s->channel_level) - { - if (s->tone_present == MODEM_CONNECT_TONES_ANS) - { - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - s->good_cycles = 0; - } - else - { - if (s->tone_cycle_duration >= ms_to_samples(450 + 25)) - { - /* The change came too late for a cycle of ANS_PR tone */ - if (s->tone_present == MODEM_CONNECT_TONES_ANS_PR || s->tone_present == MODEM_CONNECT_TONES_ANSAM_PR) - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - s->good_cycles = 0; - } - } - s->tone_on = false; - } - } - break; - case MODEM_CONNECT_TONES_BELL_ANS: - for (i = 0; i < len; i++) - { - famp = amp[i]; - /* A Cauer notch at 2225Hz, spread just wide enough to meet our detection bandwidth - criteria. */ - /* Poles 0.7144255*exp(+-2230.612/4000 * PI * j) - Zeroes exp(+-2224.9/4000 * PI * j) */ - v1 = 0.739651f*famp - 0.257384f*s->znotch_1 - 0.510404f*s->znotch_2; - famp = v1 + 0.351437f*s->znotch_1 + s->znotch_2; - s->znotch_2 = s->znotch_1; - s->znotch_1 = v1; - notched = (int16_t) lfastrintf(famp); - - /* Estimate the overall energy in the channel, and the energy in - the notch (i.e. overall channel energy - tone energy => noise). - Use abs instead of multiply for speed (is it really faster?). */ - s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); - s->notch_level += ((abs(notched) - s->notch_level) >> 5); - if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) - { - /* There is adequate energy in the channel, and it is mostly at 2225Hz. */ - if (s->tone_present != MODEM_CONNECT_TONES_BELL_ANS) - { - if (++s->tone_cycle_duration >= ms_to_samples(415)) - report_tone_state(s, MODEM_CONNECT_TONES_BELL_ANS, lfastrintf(((s->channel_level == 0) ? (-96.329f + DBM0_MAX_POWER) : log10f(s->channel_level/32768.0f)*20.0f) + DBM0_MAX_POWER + 0.8f)); - } - } - else - { - /* If the signal looks wrong, even for a moment, we consider this the - end of the tone. */ - if (s->tone_present == MODEM_CONNECT_TONES_BELL_ANS) - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - s->tone_cycle_duration = 0; - } - } - break; - case MODEM_CONNECT_TONES_CALLING_TONE: - for (i = 0; i < len; i++) - { - famp = amp[i]; - /* A Cauer notch at 1300Hz, spread just wide enough to meet our detection bandwidth - criteria. */ - /* Poles 0.736618498*exp(+-1247/4000 * PI * j) - Zeroes exp(+-1299.5/4000 * PI * j) */ - v1 = 0.755582f*famp + 0.820887174515f*s->znotch_1 - 0.541968324778f*s->znotch_2; - famp = v1 - 1.0456667108f*s->znotch_1 + s->znotch_2; - s->znotch_2 = s->znotch_1; - s->znotch_1 = v1; - notched = (int16_t) lfastrintf(famp); - - /* Estimate the overall energy in the channel, and the energy in - the notch (i.e. overall channel energy - tone energy => noise). - Use abs instead of multiply for speed (is it really faster?). */ - s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); - s->notch_level += ((abs(notched) - s->notch_level) >> 5); - if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) - { - /* There is adequate energy in the channel, and it is mostly at 1300Hz. */ - if (s->tone_present != MODEM_CONNECT_TONES_CALLING_TONE) - { - if (++s->tone_cycle_duration >= ms_to_samples(415)) - report_tone_state(s, MODEM_CONNECT_TONES_CALLING_TONE, lfastrintf(((s->channel_level == 0) ? (-96.329f + DBM0_MAX_POWER) : log10f(s->channel_level/32768.0f)*20.0f) + DBM0_MAX_POWER + 0.8f)); - } - } - else - { - /* If the signal looks wrong, even for a moment, we consider this the - end of the tone. */ - if (s->tone_present == MODEM_CONNECT_TONES_CALLING_TONE) - report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); - s->tone_cycle_duration = 0; - } - } - break; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s) -{ - int x; - - x = s->hit; - s->hit = MODEM_CONNECT_TONES_NONE; - return x; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem_connect_tones_rx_state_t *s, - int tone_type, - tone_report_func_t tone_callback, - void *user_data) -{ - if (s == NULL) - { - if ((s = (modem_connect_tones_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - - s->tone_type = tone_type; - switch (s->tone_type) - { - case MODEM_CONNECT_TONES_FAX_PREAMBLE: - case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: - fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, s); - fsk_rx_signal_cutoff(&(s->v21rx), -45.5f); - break; - case MODEM_CONNECT_TONES_ANS_PR: - case MODEM_CONNECT_TONES_ANSAM: - case MODEM_CONNECT_TONES_ANSAM_PR: - /* Treat these all the same for receive purposes */ - s->tone_type = MODEM_CONNECT_TONES_ANS; - break; - } - s->channel_level = 0; - s->notch_level = 0; - s->am_level = 0; - s->tone_present = MODEM_CONNECT_TONES_NONE; - s->tone_cycle_duration = 0; - s->good_cycles = 0; - s->hit = MODEM_CONNECT_TONES_NONE; - s->tone_on = false; - s->tone_callback = tone_callback; - s->callback_data = user_data; - s->znotch_1 = 0.0f; - s->znotch_2 = 0.0f; - s->z15hz_1 = 0.0f; - s->z15hz_2 = 0.0f; - s->num_bits = 0; - s->flags_seen = 0; - s->framing_ok_announced = false; - s->raw_bit_stream = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_rx_release(modem_connect_tones_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) modem_connect_tones_rx_free(modem_connect_tones_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/modem_echo.c b/libs/spandsp/src/modem_echo.c deleted file mode 100644 index 622c201279..0000000000 --- a/libs/spandsp/src/modem_echo.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_echo.c - An echo cancellor, suitable for electrical echos in GSTN modems - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 2003, 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 */ - -/* The FIR taps must be adapted as 32 bit values, to get the necessary finesse - in the adaption process. However, they are applied as 16 bit values (bits 30-15 - of the 32 bit values) in the FIR. For the working 16 bit values, we need 4 sets. - */ - -#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 -#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" - -#include "spandsp/private/modem_echo.h" - -SPAN_DECLARE(void) modem_echo_can_free(modem_echo_can_state_t *ec) -{ - fir16_free(&ec->fir_state); - span_free(ec->fir_taps32); - span_free(ec->fir_taps16); - span_free(ec); -} -/*- End of function --------------------------------------------------------*/ - -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 *) 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 *) span_alloc(ec->taps*sizeof(int32_t))) == NULL) - { - span_free(ec); - return NULL; - } - memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t)); - if ((ec->fir_taps16 = (int16_t *) span_alloc(ec->taps*sizeof(int16_t))) == NULL) - { - 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) - { - span_free(ec->fir_taps16); - span_free(ec->fir_taps32); - span_free(ec); - return NULL; - } - return ec; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) modem_echo_can_flush(modem_echo_can_state_t *ec) -{ - ec->tx_power = 0; - - fir16_flush(&ec->fir_state); - ec->fir_state.curr_pos = ec->taps - 1; - memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t)); - memset(ec->fir_taps16, 0, ec->taps*sizeof(int16_t)); - ec->curr_pos = ec->taps - 1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) modem_echo_can_adaption_mode(modem_echo_can_state_t *ec, int adapt) -{ - ec->adapt = adapt; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int16_t) modem_echo_can_update(modem_echo_can_state_t *ec, int16_t tx, int16_t rx) -{ - int32_t echo_value; - int clean_rx; - int shift; - int i; - int offset1; - int offset2; - - /* Evaluate the echo - i.e. apply the FIR filter */ - /* Assume the gain of the FIR does not exceed unity. Exceeding unity - would seem like a rather poor thing for an echo cancellor to do :) - This means we can compute the result with a total disregard for - overflows. 16bits x 16bits -> 31bits, so no overflow can occur in - any multiply. While accumulating we may overflow and underflow the - 32 bit scale often. However, if the gain does not exceed unity, - everything should work itself out, and the final result will be - OK, without any saturation logic. */ - /* Overflow is very much possible here, and we do nothing about it because - of the compute costs */ - echo_value = fir16(&ec->fir_state, tx); - - /* And the answer is..... */ - clean_rx = rx - echo_value; - //printf("%8d %8d %8d %8d\n", tx, rx, echo_value, clean_rx); - if (ec->adapt) - { - /* Calculate short term power levels using very simple single pole IIRs */ - /* TODO: Is the nasty modulus approach the fastest, or would a real - tx*tx power calculation actually be faster? Using the squares - makes the numbers grow a lot! */ - ec->tx_power += ((tx*tx - ec->tx_power) >> 5); - - shift = 1; - /* Update the FIR taps */ - offset2 = ec->curr_pos; - offset1 = ec->taps - offset2; - for (i = ec->taps - 1; i >= offset1; i--) - { - /* Leak to avoid the coefficients drifting beyond the ability of the - adaption process to bring them back under control. */ - ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23); - ec->fir_taps32[i] += (ec->fir_state.history[i - offset1]*clean_rx) >> shift; - ec->fir_taps16[i] = (int16_t) (ec->fir_taps32[i] >> 15); - } - for ( ; i >= 0; i--) - { - ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23); - ec->fir_taps32[i] += (ec->fir_state.history[i + offset2]*clean_rx) >> shift; - ec->fir_taps16[i] = (int16_t) (ec->fir_taps32[i] >> 15); - } - } - - /* Roll around the rolling buffer */ - if (ec->curr_pos <= 0) - ec->curr_pos = ec->taps; - ec->curr_pos--; - return (int16_t) clean_rx; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/msvc/Download_TIFF.2005.vcproj b/libs/spandsp/src/msvc/Download_TIFF.2005.vcproj deleted file mode 100644 index ce78ce0d6c..0000000000 --- a/libs/spandsp/src/msvc/Download_TIFF.2005.vcproj +++ /dev/null @@ -1,49 +0,0 @@ -tiff-4.0.2 - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/Download_TIFF.2008.vcproj b/libs/spandsp/src/msvc/Download_TIFF.2008.vcproj deleted file mode 100644 index 2b59b47d76..0000000000 --- a/libs/spandsp/src/msvc/Download_TIFF.2008.vcproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/config.h b/libs/spandsp/src/msvc/config.h deleted file mode 100644 index 78b76c0149..0000000000 --- a/libs/spandsp/src/msvc/config.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * config.h - a fudge for MSVC, which lacks this header - * - * Written by Steve Underwood - * - * Copyright (C) 2006 Michael Jerris - * - * - * This file is released in the public domain. - */ - -#if !defined(_MSVC_CONFIG_H_) -#define _MSVC_CONFIG_H_ - -#define HAVE_SINF -#define HAVE_COSF -#define HAVE_TANF -#define HAVE_ASINF -#define HAVE_ACOSF -#define HAVE_ATANF -#define HAVE_ATAN2F -#define HAVE_CEILF -#define HAVE_FLOORF -#define HAVE_POWF -#define HAVE_EXPF -#define HAVE_LOGF -#define HAVE_LOG10F -#define HAVE_MATH_H -#define HAVE_TGMATH_H - -#define HAVE_LONG_DOUBLE -#define HAVE_LIBTIFF - -#define SPANDSP_USE_EXPORT_CAPABILITY 1 - -#define PACKAGE "spandsp" -#define VERSION "0.0.6" - -/* Win32/DevStudio compatibility stuff */ - -#ifdef _MSC_VER - - #if (_MSC_VER >= 1400) // VC8+ - #ifndef _CRT_SECURE_NO_DEPRECATE - #define _CRT_SECURE_NO_DEPRECATE - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #endif // VC8+ - - // disable the following warnings - #pragma warning(disable:4100) // The formal parameter is not referenced in the body of the function. The unreferenced parameter is ignored. - #pragma warning(disable:4200) // Non standard extension C zero sized array - #pragma warning(disable:4706) // assignment within conditional expression - #pragma warning(disable:4244) // conversion from 'type1' to 'type2', possible loss of data - #pragma warning(disable:4295) // array is too small to include a terminating null character - #pragma warning(disable:4125) // decimal digit terminates octal escape sequence - #pragma warning(disable:4305) // 'function' : truncation from 'double' to 'float' - #pragma warning(disable:4018) // '<' : signed/unsigned mismatch - #pragma warning(disable:4389) // '==' : signed/unsigned mismatch - #pragma warning(disable:4245) // 'return' : conversion from 'int' to 'size_t', signed/unsigned mismatch - - #define strncasecmp _strnicmp - #define strcasecmp _stricmp - #if _MSC_VER < 1900 - #define snprintf _snprintf - #endif - #define inline __inline - #define __inline__ __inline - - #define _MMX_H_ - - #if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800)) - #define cbrtf(value) pow((float)value, (float).333) - #endif - - #include // To get alloca - -#endif - -#endif diff --git a/libs/spandsp/src/msvc/getopt.c b/libs/spandsp/src/msvc/getopt.c deleted file mode 100644 index a19bd4b78b..0000000000 --- a/libs/spandsp/src/msvc/getopt.c +++ /dev/null @@ -1,177 +0,0 @@ -/***************************************************************************** - * - * 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 deleted file mode 100644 index 83704180a9..0000000000 --- a/libs/spandsp/src/msvc/gettimeofday.c +++ /dev/null @@ -1,36 +0,0 @@ -#ifdef _MSC_VER -#pragma warning(disable:4100) -#endif - -#include "windows.h" - -const unsigned long long int DELTA_EPOCH_IN_MICROSECS = 11644473600000000; - -void gettimeofday(struct timeval *tv, void *tz) -{ - 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/inttypes.h b/libs/spandsp/src/msvc/inttypes.h deleted file mode 100644 index 9612d3e1e5..0000000000 --- a/libs/spandsp/src/msvc/inttypes.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * inttypes.h - a fudge for MSVC, which lacks this header - * - * Written by Steve Underwood - * - * Copyright (C) 2006 Michael Jerris - * - * - * This file is released in the public domain. - * - */ - -#if !defined(_INTTYPES_H_) -#define _INTTYPES_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1900 -#include -#else - -typedef __int8 __int8_t; -typedef __int16 __int16_t; -typedef __int32 __int32_t; -typedef __int64 __int64_t; - -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; - -#endif -#if !defined(INFINITY) && _MSC_VER < 1800 -#define INFINITY 0x7FFFFFFF -#endif - -#if !defined(UINT8_MAX) -#define UINT8_MAX 0xFF -#endif -#if !defined(UINT16_MAX) -#define UINT16_MAX 0xFFFF -#endif -#if !defined(UINT32_MAX) -#define UINT32_MAX 0xFFFFFFFF -#endif - -#if !defined(INT16_MAX) -#define INT16_MAX 0x7FFF -#endif -#if !defined(INT16_MIN) -#define INT16_MIN (-INT16_MAX - 1) -#endif - -#if !defined(INT32_MAX) -#define INT32_MAX (2147483647) -#endif -#if !defined(INT32_MIN) -#define INT32_MIN (-2147483647 - 1) -#endif - -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "ld" -#define PRId64 "lld" - -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "lu" -#define PRIu64 "llu" - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/spandsp/src/msvc/make_at_dictionary.2005.vcproj b/libs/spandsp/src/msvc/make_at_dictionary.2005.vcproj deleted file mode 100644 index 61c5c14c34..0000000000 --- a/libs/spandsp/src/msvc/make_at_dictionary.2005.vcproj +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/make_at_dictionary.2008.vcproj b/libs/spandsp/src/msvc/make_at_dictionary.2008.vcproj deleted file mode 100644 index a4f58d7771..0000000000 --- a/libs/spandsp/src/msvc/make_at_dictionary.2008.vcproj +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/make_at_dictionary.2010.vcxproj.filters b/libs/spandsp/src/msvc/make_at_dictionary.2010.vcxproj.filters deleted file mode 100644 index 708d52292d..0000000000 --- a/libs/spandsp/src/msvc/make_at_dictionary.2010.vcxproj.filters +++ /dev/null @@ -1,14 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - - \ No newline at end of file diff --git a/libs/spandsp/src/msvc/make_math_fixed_tables.2010.vcxproj.filters b/libs/spandsp/src/msvc/make_math_fixed_tables.2010.vcxproj.filters deleted file mode 100644 index a9807aac86..0000000000 --- a/libs/spandsp/src/msvc/make_math_fixed_tables.2010.vcxproj.filters +++ /dev/null @@ -1,14 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - - \ No newline at end of file diff --git a/libs/spandsp/src/msvc/make_modem_filter.2005.vcproj b/libs/spandsp/src/msvc/make_modem_filter.2005.vcproj deleted file mode 100644 index 43efd4bdfb..0000000000 --- a/libs/spandsp/src/msvc/make_modem_filter.2005.vcproj +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/make_modem_filter.2008.vcproj b/libs/spandsp/src/msvc/make_modem_filter.2008.vcproj deleted file mode 100644 index 7cd88db2b3..0000000000 --- a/libs/spandsp/src/msvc/make_modem_filter.2008.vcproj +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/make_modem_filter.2010.vcxproj.filters b/libs/spandsp/src/msvc/make_modem_filter.2010.vcxproj.filters deleted file mode 100644 index 122497994c..0000000000 --- a/libs/spandsp/src/msvc/make_modem_filter.2010.vcxproj.filters +++ /dev/null @@ -1,29 +0,0 @@ - - - - - {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 - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - \ No newline at end of file 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 deleted file mode 100644 index 8ab1316fdc..0000000000 --- a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj.filters +++ /dev/null @@ -1,14 +0,0 @@ - - - - - {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/msvcproj.foot b/libs/spandsp/src/msvc/msvcproj.foot deleted file mode 100644 index f5ed822476..0000000000 --- a/libs/spandsp/src/msvc/msvcproj.foot +++ /dev/null @@ -1,7 +0,0 @@ - -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/libs/spandsp/src/msvc/msvcproj.head b/libs/spandsp/src/msvc/msvcproj.head deleted file mode 100644 index b91c780b04..0000000000 --- a/libs/spandsp/src/msvc/msvcproj.head +++ /dev/null @@ -1,92 +0,0 @@ -# Microsoft Developer Studio Project File - Name="spandsp" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=spandsp - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "spandsp.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "spandsp.mak" CFG="spandsp - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "spandsp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "spandsp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "spandsp - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /D "_WINDLL" /FR /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /map /debug /machine:I386 /out:"Release/libspandsp.dll" - -!ELSEIF "$(CFG)" == "spandsp - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D HAVE_TGMATH_H /FR /FD /GZ /c -# SUBTRACT CPP /WX /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib winmm.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"Debug/libspandsp.dll" /pdbtype:sept -# SUBTRACT LINK32 /nodefaultlib - -!ENDIF - -# Begin Target - -# Name "spandsp - Win32 Release" -# Name "spandsp - Win32 Debug" diff --git a/libs/spandsp/src/msvc/spandsp.h b/libs/spandsp/src/msvc/spandsp.h deleted file mode 100644 index 25d19698de..0000000000 --- a/libs/spandsp/src/msvc/spandsp.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * spandsp.h - The head guy amongst the headers - * - * 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 */ - -#if !defined(_SPANDSP_H_) -#define _SPANDSP_H_ - -#define __inline__ __inline -#pragma warning(disable:4200) - -#undef SPANDSP_USE_FIXED_POINT -#undef SPANDSP_MISALIGNED_ACCESS_FAILS - -#define SPANDSP_USE_EXPORT_CAPABILITY 1 - -#undef SPANDSP_SUPPORT_T43 -#undef SPANDSP_SUPPORT_V32BIS -#undef SPANDSP_SUPPORT_V34 -#undef SPANDSP_SUPPORT_TIFF_FX - -#include -#include -#include -#include -#include -#include -#include - -#if !defined(__cplusplus) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) -#include -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/msvc/sys/time.h b/libs/spandsp/src/msvc/sys/time.h deleted file mode 100644 index 864891bc28..0000000000 --- a/libs/spandsp/src/msvc/sys/time.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * sys/time.h - a fudge for MSVC, which lacks this header - * - * Written by Steve Underwood - * - * Copyright (C) 2006 Michael Jerris - * - * - * This file is released in the public domain. - * - */ - -struct timeval -{ - long int tv_sec; - long int tv_usec; -}; - -extern void gettimeofday(struct timeval *tv, void *tz); diff --git a/libs/spandsp/src/msvc/tgmath.h b/libs/spandsp/src/msvc/tgmath.h deleted file mode 100644 index 32462681df..0000000000 --- a/libs/spandsp/src/msvc/tgmath.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tgmath.h - a fudge for MSVC, which lacks this header - * - * Written by Steve Underwood - * - * Copyright (C) 2006 Michael Jerris - * - * - * This file is released in the public domain. - * - */ - -#if !defined(_TGMATH_H_) -#define _TGMATH_H_ - -#include - -#if !defined(M_PI) -/* C99 systems may not define M_PI */ -#define M_PI 3.14159265358979323846264338327 -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/spandsp/src/msvc/tiff/cleancount b/libs/spandsp/src/msvc/tiff/cleancount deleted file mode 100644 index 56a6051ca2..0000000000 --- a/libs/spandsp/src/msvc/tiff/cleancount +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/libs/spandsp/src/msvc/unistd.h b/libs/spandsp/src/msvc/unistd.h deleted file mode 100644 index 28ab355c09..0000000000 --- a/libs/spandsp/src/msvc/unistd.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * unistd.h - a fudge for MSVC, which lacks this header - * - * Written by Steve Underwood - * - * Copyright (C) 2006 Michael Jerris - * - * - * This file is released in the public domain. - * - */ - -#if !defined(_UNISTD_H_) -#define _UNISTD_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// Declare this so we don't have to include winsock.h, it causes numerous conflicts. -extern int __stdcall gethostname(char * name, int namelen); -#pragma comment(lib, "ws2_32.lib") - -extern int getopt(int argc, char *argv[], char *opstring); - -extern char *optarg; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/spandsp/src/msvc/util.vbs b/libs/spandsp/src/msvc/util.vbs deleted file mode 100644 index ce60e53b2b..0000000000 --- a/libs/spandsp/src/msvc/util.vbs +++ /dev/null @@ -1,199 +0,0 @@ -' -' Contributor(s): -' Michael Jerris -' David A. Horner http://dave.thehorners.com -'---------------------------------------------- - -'On Error Resume Next -' ************** -' Initialization -' ************** - -Set WshShell = CreateObject("WScript.Shell") -Set FSO = CreateObject("Scripting.FileSystemObject") -Set WshSysEnv = WshShell.Environment("SYSTEM") -Set xml = CreateObject("Microsoft.XMLHTTP") -Dim UseWgetEXE - -On Error Resume Next -Set oStream = CreateObject("Adodb.Stream") -On Error Goto 0 - -If Not IsObject(oStream) Then - wscript.echo("Failed to create Adodb.Stream, using alternative download method.") - UseWgetEXE=true -Else - UseWgetEXE=false -End If -Randomize -Set objArgs = WScript.Arguments -quote=Chr(34) -ScriptDir=Left(WScript.ScriptFullName,Len(WScript.ScriptFullName)-Len(WScript.ScriptName)) -UtilsDir=Showpath(ScriptDir) -ToolsBase="http://files.freeswitch.org/downloads/win32/" - -If UseWgetEXE Then - GetWgetEXE UtilsDir -End If - -GetCompressionTools UtilsDir - - -If objArgs.Count >=3 Then - Select Case objArgs(0) - Case "Get" - Wget objArgs(1), Showpath(objArgs(2)) - Case "GetUnzip" - WgetUnCompress objArgs(1), Showpath(objArgs(2)) - End Select -End If - - -' ******************* -' Utility Subroutines -' ******************* - - -Sub WgetUnCompress(URL, DestFolder) - If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If - StartPos = InstrRev(URL, "/", -1, 1) - strlength = Len(URL) - filename=Right(URL,strlength-StartPos) - NameEnd = InstrRev(filename, ".",-1, 1) - filestrlength = Len(filename) - filebase = Left(filename,NameEnd) - fileext = Right(filename, Len(filename) - NameEnd) - Wget URL, DestFolder - If fileext = "zip" Then - UnCompress Destfolder & filename, DestFolder & filebase - Else - UnCompress Destfolder & filename, DestFolder - End If -End Sub - -Sub GetCompressionTools(DestFolder) - Dim oExec - If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If - If Not FSO.FileExists(DestFolder & "7za.exe") Then - If Not FSO.FileExists(DestFolder & "7za.tag") Then - Set MyFile = fso.CreateTextFile(DestFolder & "7za.tag", True) - MyFile.WriteLine("This file marks a pending download for 7za.exe so we don't download it twice at the same time") - MyFile.Close - - Wget ToolsBase & "7za.exe", DestFolder - - FSO.DeleteFile DestFolder & "7za.tag" ,true - Else - WScript.Sleep(5000) - End If - End If -End Sub - -Sub GetWgetEXE(DestFolder) - Dim oExec - If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If - If Not FSO.FileExists(DestFolder & "wget.exe") Then - Slow_Wget ToolsBase & "wget.exe", DestFolder - End If -End Sub - -Sub UnCompress(Archive, DestFolder) - batname = "tmp" & CStr(Int(10000*Rnd)) & ".bat" - wscript.echo("Extracting: " & Archive) - Set MyFile = fso.CreateTextFile(UtilsDir & batname, True) - MyFile.WriteLine("@" & quote & UtilsDir & "7za.exe" & quote & " x " & quote & Archive & quote & " -y -o" & quote & DestFolder & quote ) - MyFile.Close - Set oExec = WshShell.Exec(UtilsDir & batname) - Do - WScript.Echo OExec.StdOut.ReadLine() - Loop While Not OExec.StdOut.atEndOfStream - If FSO.FileExists(Left(Archive, Len(Archive)-3))Then - Set MyFile = fso.CreateTextFile(UtilsDir & batname, True) - MyFile.WriteLine("@" & quote & UtilsDir & "7za.exe" & quote & " x " & quote & Left(Archive, Len(Archive)-3) & quote & " -y -o" & quote & DestFolder & quote ) - MyFile.Close - Set oExec = WshShell.Exec(UtilsDir & batname) - Do - WScript.Echo OExec.StdOut.ReadLine() - Loop While Not OExec.StdOut.atEndOfStream - WScript.Sleep(500) - FSO.DeleteFile Left(Archive, Len(Archive)-3) ,true - End If - If FSO.FileExists(Left(Archive, Len(Archive)-3) & "tar")Then - Set MyFile = fso.CreateTextFile(UtilsDir & batname, True) - MyFile.WriteLine("@" & quote & UtilsDir & "7za.exe" & quote & " x " & quote & Left(Archive, Len(Archive)-3) & "tar" & quote & " -y -o" & quote & DestFolder & quote ) - MyFile.Close - Set oExec = WshShell.Exec(UtilsDir & batname) - Do - WScript.Echo OExec.StdOut.ReadLine() - Loop While Not OExec.StdOut.atEndOfStream - WScript.Sleep(500) - FSO.DeleteFile Left(Archive, Len(Archive)-3) & "tar",true - End If - - WScript.Sleep(500) - If FSO.FileExists(UtilsDir & batname)Then - FSO.DeleteFile UtilsDir & batname, True - End If -End Sub - -Sub Wget(URL, DestFolder) - StartPos = InstrRev(URL, "/", -1, 1) - strlength = Len(URL) - filename=Right(URL,strlength-StartPos) - If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If - - Wscript.echo("Downloading: " & URL) - -If UseWgetEXE Then - batname = "tmp" & CStr(Int(10000*Rnd)) & ".bat" - Set MyFile = fso.CreateTextFile(UtilsDir & batname, True) - MyFile.WriteLine("@cd " & quote & DestFolder & quote) - MyFile.WriteLine("@" & quote & UtilsDir & "wget.exe" & quote & " " & URL) - MyFile.Close - Set oExec = WshShell.Exec(UtilsDir & batname) - Do - WScript.Echo OExec.StdOut.ReadLine() - Loop While Not OExec.StdOut.atEndOfStream - -Else - xml.Open "GET", URL, False - xml.Send - - Const adTypeBinary = 1 - Const adSaveCreateOverWrite = 2 - Const adSaveCreateNotExist = 1 - - oStream.type = adTypeBinary - oStream.open - oStream.write xml.responseBody - oStream.savetofile DestFolder & filename, adSaveCreateOverWrite - oStream.close -End If - -End Sub - -Sub Slow_Wget(URL, DestFolder) - StartPos = InstrRev(URL, "/", -1, 1) - strlength = Len(URL) - filename=Right(URL,strlength-StartPos) - If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If - - Wscript.echo("Downloading: " & URL) - xml.Open "GET", URL, False - xml.Send - - const ForReading = 1 , ForWriting = 2 , ForAppending = 8 - Set MyFile = fso.OpenTextFile(DestFolder & filename ,ForWriting, True) - For i = 1 to lenb(xml.responseBody) - MyFile.write Chr(Ascb(midb(xml.responseBody,i,1))) - Next - MyFile.Close() - -End Sub - -Function Showpath(folderspec) - Set f = FSO.GetFolder(folderspec) - showpath = f.path & "\" -End Function - - diff --git a/libs/spandsp/src/msvc/vc10proj.foot b/libs/spandsp/src/msvc/vc10proj.foot deleted file mode 100644 index be77f0a5a8..0000000000 --- a/libs/spandsp/src/msvc/vc10proj.foot +++ /dev/null @@ -1,33 +0,0 @@ - - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - - - - - {401a40cd-5db4-4e34-ac68-fa99e9fac014} - false - - - {dee932ab-5911-4700-9eeb-8c7090a0a330} - false - - - {329a6fa0-0fcc-4435-a950-e670aefa9838} - false - - - - - - diff --git a/libs/spandsp/src/msvc/vc10proj.head b/libs/spandsp/src/msvc/vc10proj.head deleted file mode 100644 index 37f2b12b29..0000000000 --- a/libs/spandsp/src/msvc/vc10proj.head +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - libspandsp - {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} - libspandsp - Win32Proj - - - - DynamicLibrary - Unicode - true - - - DynamicLibrary - Unicode - - - DynamicLibrary - Unicode - true - - - DynamicLibrary - Unicode - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - true - false - true - false - - - - $(IntDir)BuildLog $(ProjectName).htm - - - Disabled - .;..\..\src\spandsp;..\..\src;..\..\src\msvc;.\spandsp;.\msvc;..\..\tiff-4.0.2\libtiff;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - CompileAsC - 4127;%(DisableSpecificWarnings) - - - true - Windows - false - MachineX86 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - .;.\spandsp;.\msvc;..\..\tiff-4.0.2\libtiff;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - MultiThreadedDLL - Level4 - 4127;%(DisableSpecificWarnings) - - - true - Windows - true - true - false - MachineX86 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - Disabled - .;.\spandsp;.\msvc;..\..\tiff-4.0.2\libtiff;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - CompileAsC - 4127;%(DisableSpecificWarnings) - - - true - Windows - false - MachineX64 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - .;.\spandsp;.\msvc;..\..\tiff-4.0.2\libtiff;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - MultiThreadedDLL - Level4 - 4127;%(DisableSpecificWarnings) - - - true - Windows - true - true - false - MachineX64 - - - diff --git a/libs/spandsp/src/msvc/vc12proj.foot b/libs/spandsp/src/msvc/vc12proj.foot deleted file mode 100644 index e67b5d098f..0000000000 --- a/libs/spandsp/src/msvc/vc12proj.foot +++ /dev/null @@ -1,47 +0,0 @@ - - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" - $(ProjectDir)%(Filename)%(Extension);%(Outputs) - - - - - {019dbd2a-273d-4ba4-bf86-b5efe2ed76b1} - false - - - {401a40cd-5db4-4e34-ac68-fa99e9fac014} - false - - - {dee932ab-5911-4700-9eeb-8c7090a0a330} - false - - - {85f0cf8c-c7ab-48f6-ba19-cc94cf87f981} - - - {2386b892-35f5-46cf-a0f0-10394d2fbf9b} - - - {329a6fa0-0fcc-4435-a950-e670aefa9838} - false - - - {eddb8ab9-c53e-44c0-a620-0e86c2cbd5d5} - false - - - - - - diff --git a/libs/spandsp/src/msvc/vc12proj.head b/libs/spandsp/src/msvc/vc12proj.head deleted file mode 100644 index 396eed7ae2..0000000000 --- a/libs/spandsp/src/msvc/vc12proj.head +++ /dev/null @@ -1,161 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - libspandsp - {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} - libspandsp - Win32Proj - - - - DynamicLibrary - Unicode - true - v110 - - - DynamicLibrary - Unicode - v110 - - - DynamicLibrary - Unicode - true - v110 - - - DynamicLibrary - Unicode - v110 - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - true - false - true - false - - - - $(IntDir)BuildLog $(ProjectName).htm - - - Disabled - .;.\spandsp;.\msvc;..\tiff-4.0.3\tiff-4.0.3\libtiff;..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - CompileAsC - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - false - MachineX86 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - .;.\spandsp;.\msvc;..\tiff-4.0.3\tiff-4.0.3\libtiff;..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - MultiThreadedDLL - Level4 - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - true - true - false - MachineX86 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - Disabled - .;.\spandsp;.\msvc;..\tiff-4.0.3\tiff-4.0.3\libtiff;..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Level4 - CompileAsC - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - false - MachineX64 - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - .;.\spandsp;.\msvc;..\tiff-4.0.3\tiff-4.0.3\libtiff;..\jpeg-8d;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) - MultiThreadedDLL - Level4 - 4127;4324;4267;4306;%(DisableSpecificWarnings) - - - true - Windows - true - true - false - MachineX64 - - - diff --git a/libs/spandsp/src/msvc/vc8proj.foot b/libs/spandsp/src/msvc/vc8proj.foot deleted file mode 100644 index 4d2bee2efe..0000000000 --- a/libs/spandsp/src/msvc/vc8proj.foot +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/vc8proj.head b/libs/spandsp/src/msvc/vc8proj.head deleted file mode 100644 index d7757339d1..0000000000 --- a/libs/spandsp/src/msvc/vc8proj.head +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/vc9proj.foot b/libs/spandsp/src/msvc/vc9proj.foot deleted file mode 100644 index 2b3a80acaf..0000000000 --- a/libs/spandsp/src/msvc/vc9proj.foot +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/msvc/vc9proj.head b/libs/spandsp/src/msvc/vc9proj.head deleted file mode 100644 index fbbdba6378..0000000000 --- a/libs/spandsp/src/msvc/vc9proj.head +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/spandsp/src/noise.c b/libs/spandsp/src/noise.c deleted file mode 100644 index 1a8f58842e..0000000000 --- a/libs/spandsp/src/noise.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * noise.c - A low complexity audio noise generator, suitable for - * real time generation (current AWGN, and Hoth) - * - * 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. - */ - -/*! \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 -#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" - -#include "spandsp/private/noise.h" - -SPAN_DECLARE(int16_t) noise(noise_state_t *s) -{ - int32_t val; - int i; - - /* The central limit theorem says if you add a few random numbers together, - the result starts to look Gaussian. Quantities above 7 give diminishing - returns. Quantites above 20 are exceedingly Gaussian. */ - val = 0; - for (i = 0; i < s->quality; i++) - { - s->rndnum = 1664525U*s->rndnum + 1013904223U; - val += ((int32_t) s->rndnum) >> 22; - } - if (s->class_of_noise == NOISE_CLASS_HOTH) - { - /* Hoth noise is room-like. It should be sculpted, at the high and low ends, - and roll off at 5dB/octave across the main part of the band. However, - merely rolling off at 6dB/octave across the band gets you close - to the subjective effect. */ - s->state = (3*val + 5*s->state) >> 3; - /* Bring the overall power level back to the pre-filtered level. This - simple approx. leaves the signal about 0.35dB low. */ - val = s->state << 1; - } - return saturate16((val*s->rms) >> 10); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(noise_state_t *) noise_init_dbov(noise_state_t *s, int seed, float level, int class_of_noise, int quality) -{ - float rms; - - if (s == NULL) - { - if ((s = (noise_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->rndnum = (uint32_t) seed; - rms = 32768.0f*powf(10.0f, level/20.0f); - if (quality < 4) - s->quality = 4; - else if (quality > 20) - s->quality = 20; - else - s->quality = quality; - if (class_of_noise == NOISE_CLASS_HOTH) - { - /* Allow for the gain of the filter */ - rms *= 1.043f; - } - s->rms = (int32_t) (rms*sqrtf(12.0f/s->quality)); - s->class_of_noise = class_of_noise; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(noise_state_t *) noise_init_dbm0(noise_state_t *s, int seed, float level, int class_of_noise, int quality) -{ - return noise_init_dbov(s, seed, (level - DBM0_MAX_POWER), class_of_noise, quality); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) noise_release(noise_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) noise_free(noise_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/oki_adpcm.c b/libs/spandsp/src/oki_adpcm.c deleted file mode 100644 index 0e5e8f6659..0000000000 --- a/libs/spandsp/src/oki_adpcm.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * oki_adpcm.c - Conversion routines between linear 16 bit PCM data and - * OKI (Dialogic) ADPCM format. Supports with the 32kbps - * and 24kbps variants used by Dialogic. - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 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. - * - * The actual OKI ADPCM encode and decode method is derived from freely - * available code, whose exact origins seem uncertain. - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/oki_adpcm.h" -#include "spandsp/private/oki_adpcm.h" - -/* Routines to convert 12 bit linear samples to the Oki ADPCM coding format, - widely used in CTI, because Dialogic use it. */ - -/* OKI ADPCM step variation table */ -static const int16_t step_size[49] = -{ - 16, 17, 19, 21, 23, 25, 28, 31, - 34, 37, 41, 45, 50, 55, 60, 66, - 73, 80, 88, 97, 107, 118, 130, 143, - 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, - 1552 -}; - -static const int16_t step_adjustment[8] = -{ - -1, -1, -1, -1, 2, 4, 6, 8 -}; - -/* Band limiting filter, to allow sample rate conversion to and - from 6k samples/second. */ -static const float cutoff_coeffs[] = -{ - -3.648392e-4f, - 5.062391e-4f, - 1.206247e-3f, - 1.804452e-3f, - 1.691750e-3f, - 4.083405e-4f, - -1.931085e-3f, - -4.452107e-3f, - -5.794821e-3f, - -4.778489e-3f, - -1.161266e-3f, - 3.928504e-3f, - 8.259786e-3f, - 9.500425e-3f, - 6.512800e-3f, - 2.227856e-4f, - -6.531275e-3f, - -1.026843e-2f, - -8.718062e-3f, - -2.280487e-3f, - 5.817733e-3f, - 1.096777e-2f, - 9.634404e-3f, - 1.569301e-3f, - -9.522632e-3f, - -1.748273e-2f, - -1.684408e-2f, - -6.100054e-3f, - 1.071206e-2f, - 2.525209e-2f, - 2.871779e-2f, - 1.664411e-2f, - -7.706268e-3f, - -3.331083e-2f, - -4.521249e-2f, - -3.085962e-2f, - 1.373653e-2f, - 8.089593e-2f, - 1.529060e-1f, - 2.080487e-1f, - 2.286834e-1f, - 2.080487e-1f, - 1.529060e-1f, - 8.089593e-2f, - 1.373653e-2f, - -3.085962e-2f, - -4.521249e-2f, - -3.331083e-2f, - -7.706268e-3f, - 1.664411e-2f, - 2.871779e-2f, - 2.525209e-2f, - 1.071206e-2f, - -6.100054e-3f, - -1.684408e-2f, - -1.748273e-2f, - -9.522632e-3f, - 1.569301e-3f, - 9.634404e-3f, - 1.096777e-2f, - 5.817733e-3f, - -2.280487e-3f, - -8.718062e-3f, - -1.026843e-2f, - -6.531275e-3f, - 2.227856e-4f, - 6.512800e-3f, - 9.500425e-3f, - 8.259786e-3f, - 3.928504e-3f, - -1.161266e-3f, - -4.778489e-3f, - -5.794821e-3f, - -4.452107e-3f, - -1.931085e-3f, - 4.083405e-4f, - 1.691750e-3f, - 1.804452e-3f, - 1.206247e-3f, - 5.062391e-4f, - -3.648392e-4f -}; - -static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm) -{ - int16_t d; - int16_t ss; - int16_t linear; - - /* Doing the next part as follows: - * - * x = adpcm & 0x07; - * e = (step_size[s->step_index]*(x + x + 1)) >> 3; - * - * Seems an obvious improvement on a modern machine, but remember - * the truncation errors do not come out the same. It would - * not, therefore, be an exact match for what this code is doing. - * - * Just what a Dialogic card does, I do not know! - */ - - ss = step_size[s->step_index]; - d = ss >> 3; - if (adpcm & 0x01) - d += (ss >> 2); - /*endif*/ - if (adpcm & 0x02) - d += (ss >> 1); - /*endif*/ - if (adpcm & 0x04) - d += ss; - /*endif*/ - if (adpcm & 0x08) - d = -d; - /*endif*/ - linear = s->last + d; - - /* Saturate the values to +/- 2^11 (supposed to be 12 bits) */ - if (linear > 2047) - linear = 2047; - else if (linear < -2048) - linear = -2048; - /*endif*/ - - s->last = linear; - s->step_index += step_adjustment[adpcm & 0x07]; - if (s->step_index < 0) - s->step_index = 0; - else if (s->step_index > 48) - s->step_index = 48; - /*endif*/ - /* Note: the result here is a 12 bit value */ - return linear; -} -/*- End of function --------------------------------------------------------*/ - -static uint8_t encode(oki_adpcm_state_t *s, int16_t linear) -{ - int16_t d; - int16_t ss; - uint8_t adpcm; - - ss = step_size[s->step_index]; - d = (linear >> 4) - s->last; - adpcm = (uint8_t) 0x00; - if (d < 0) - { - adpcm = (uint8_t) 0x08; - d = -d; - } - /*endif*/ - if (d >= ss) - { - adpcm |= (uint8_t) 0x04; - d -= ss; - } - /*endif*/ - if (d >= (ss >> 1)) - { - adpcm |= (uint8_t) 0x02; - d -= (ss >> 1); - } - /*endif*/ - if (d >= (ss >> 2)) - adpcm |= (uint8_t) 0x01; - /*endif*/ - - /* Use the decoder to set the estimate of the last sample. */ - /* It also will adjust the step_index for us. */ - s->last = decode(s, adpcm); - return adpcm; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(oki_adpcm_state_t *) oki_adpcm_init(oki_adpcm_state_t *s, int bit_rate) -{ - if (bit_rate != 32000 && bit_rate != 24000) - return NULL; - if (s == NULL) - { - if ((s = (oki_adpcm_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->bit_rate = bit_rate; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) oki_adpcm_release(oki_adpcm_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) oki_adpcm_free(oki_adpcm_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) oki_adpcm_decode(oki_adpcm_state_t *s, - int16_t amp[], - const uint8_t oki_data[], - int oki_bytes) -{ - int i; - int x; - int l; - int n; - int samples; - float z; - -#if (_MSC_VER >= 1400) - __analysis_assume(s->phase >= 0 && s->phase <= 4); -#endif - samples = 0; - if (s->bit_rate == 32000) - { - for (i = 0; i < oki_bytes; i++) - { - amp[samples++] = decode(s, (oki_data[i] >> 4) & 0xF) << 4; - amp[samples++] = decode(s, oki_data[i] & 0xF) << 4; - } - /*endwhile*/ - } - else - { - n = 0; - for (i = 0; i < oki_bytes; ) - { - /* 6k to 8k sample/second conversion */ - if (s->phase) - { - s->history[s->ptr++] = - decode(s, (n++ & 1) ? (oki_data[i++] & 0xF) : ((oki_data[i] >> 4) & 0xF)) << 4; - s->ptr &= (32 - 1); - } - /*endif*/ - z = 0.0f; - for (l = 80 - 3 + s->phase, x = s->ptr - 1; l >= 0; l -= 4, x--) - z += cutoff_coeffs[l]*s->history[x & (32 - 1)]; - amp[samples++] = (int16_t) (z*4.0f); - if (++s->phase > 3) - s->phase = 0; - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - return samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) oki_adpcm_encode(oki_adpcm_state_t *s, - uint8_t oki_data[], - const int16_t amp[], - int len) -{ - int x; - int l; - int n; - int bytes; - float z; - - bytes = 0; - if (s->bit_rate == 32000) - { - for (n = 0; n < len; n++) - { - s->oki_byte = (s->oki_byte << 4) | encode(s, amp[n]); - if ((s->mark++ & 1)) - oki_data[bytes++] = s->oki_byte; - /*endif*/ - } - /*endfor*/ - } - else - { - n = 0; - for (;;) - { - /* 8k to 6k sample/second conversion */ - if (s->phase > 2) - { - s->history[s->ptr++] = amp[n]; - s->ptr &= (32 - 1); - s->phase = 0; - if (++n >= len) - break; - /*endif*/ - } - /*endif*/ - s->history[s->ptr++] = amp[n]; - s->ptr &= (32 - 1); - z = 0.0f; - for (l = 80 - s->phase, x = s->ptr - 1; l >= 0; l -= 3, x--) - z += cutoff_coeffs[l]*s->history[x & (32 - 1)]; - /*endfor*/ - s->oki_byte = (s->oki_byte << 4) | encode(s, (int16_t) (z*3.0f)); - if ((s->mark++ & 1)) - oki_data[bytes++] = s->oki_byte; - /*endif*/ - s->phase++; - if (++n >= len) - break; - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - return bytes; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/playout.c b/libs/spandsp/src/playout.c deleted file mode 100644 index 9ad0d8dcf2..0000000000 --- a/libs/spandsp/src/playout.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * playout.c - * - * Written by Steve Underwood - * - * Copyright (C) 2005 Steve Underwood - * - * All rights reserved. - * - * This was kicked off from jitter buffering code - * Copyright (C) 2004, Horizon Wimba, Inc. - * Author Steve Kann - * However, there isn't a lot of the original left, now. The original - * was licenced under the LGPL, so any remaining fragments are - * compatible with the GPL licence used here. - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#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; - - if ((frame = s->first_frame) == NULL) - return NULL; - - if (sender_stamp >= frame->sender_stamp) - { - /* Remove this frame from the queue */ - if (frame->later) - { - frame->later->earlier = NULL; - s->first_frame = frame->later; - } - else - { - /* The queue is now empty */ - s->first_frame = NULL; - s->last_frame = NULL; - } - return frame; - } - - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(timestamp_t) playout_next_due(playout_state_t *s) -{ - return s->last_speech_sender_stamp + s->last_speech_sender_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(timestamp_t) playout_current_length(playout_state_t *s) -{ - return s->target_buffer_length; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(playout_frame_t *) playout_get_unconditional(playout_state_t *s) -{ - playout_frame_t *frame; - - if ((frame = queue_get(s, 0x7FFFFFFF))) - { - /* Put it on the free list */ - frame->later = s->free_frames; - s->free_frames = frame; - - /* We return the frame pointer, even though it's on the free list. - The caller *must* copy the data before this frame has any chance - of being reused. */ - } - return frame; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) playout_get(playout_state_t *s, playout_frame_t *frameout, timestamp_t now) -{ - playout_frame_t *frame; - - /* Make the last_speech_sender_stamp the current expected one. */ - s->last_speech_sender_stamp += s->last_speech_sender_len; - if ((frame = queue_get(s, s->last_speech_sender_stamp)) == NULL) - { - /* The required frame was not received (or at least not in time) */ - s->frames_missing++; - return PLAYOUT_FILLIN; - } - - if (s->dynamic && frame->type == PLAYOUT_TYPE_SPEECH) - { - /* Assess whether the buffer length is appropriate */ - if (!s->not_first) - { - /* Prime things the first time through */ - 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 */ - s->state_late += ((((frame->receiver_stamp > s->latest_expected) ? 0x10000000 : 0) - s->state_late) >> 8); - s->state_just_in_time += ((((frame->receiver_stamp > s->latest_expected - frame->sender_len) ? 0x10000000 : 0) - s->state_just_in_time) >> 8); - s->latest_expected += frame->sender_len; - - if (s->state_late > s->dropable_threshold) - { - if (s->since_last_step < 10) - { - if (s->target_buffer_length < s->max_length - 2) - { - /* The late bin is too big - increase buffering */ - s->target_buffer_length += 3*frame->sender_len; - s->latest_expected += 3*frame->sender_len; - s->state_just_in_time = s->dropable_threshold; - s->state_late = 0; - s->since_last_step = 0; - - s->last_speech_sender_stamp -= 3*s->last_speech_sender_len; - } - } - else - { - if (s->target_buffer_length < s->max_length) - { - /* The late bin is too big - increase buffering */ - s->target_buffer_length += frame->sender_len; - s->latest_expected += frame->sender_len; - s->state_just_in_time = s->dropable_threshold; - s->state_late = 0; - s->since_last_step = 0; - - s->last_speech_sender_stamp -= s->last_speech_sender_len; - } - } - } - else if (s->since_last_step > 500 && s->state_just_in_time < s->dropable_threshold) - { - if (s->target_buffer_length > s->min_length) - { - /* The just-in-time bin is pretty small - decrease buffering */ - s->target_buffer_length -= frame->sender_len; - s->latest_expected -= frame->sender_len; - s->state_just_in_time = s->dropable_threshold; - s->state_late = 0; - s->since_last_step = 0; - - s->last_speech_sender_stamp += s->last_speech_sender_len; - } - } - s->since_last_step++; - } - - /* If its not a speech frame, just return it. */ - if (frame->type != PLAYOUT_TYPE_SPEECH) - { - /* Rewind last_speech_sender_stamp, since this isn't speech */ - s->last_speech_sender_stamp -= s->last_speech_sender_len; - - *frameout = *frame; - /* Put it on the free list */ - frame->later = s->free_frames; - s->free_frames = frame; - - s->frames_out++; - return PLAYOUT_OK; - } - if (frame->sender_stamp < s->last_speech_sender_stamp) - { - /* This speech frame is late */ - *frameout = *frame; - /* Put it on the free list */ - frame->later = s->free_frames; - s->free_frames = frame; - - /* Rewind last_speech_sender_stamp, since we're just dumping */ - s->last_speech_sender_stamp -= s->last_speech_sender_len; - s->frames_out++; - s->frames_late++; - s->frames_missing--; - return PLAYOUT_DROP; - } - /* Keep track of frame sizes, to allow for variable sized frames */ - if (frame->sender_len > 0) - s->last_speech_sender_len = frame->sender_len; - - /* Normal case. Return the frame, and increment stuff */ - *frameout = *frame; - /* Put it on the free list */ - frame->later = s->free_frames; - s->free_frames = frame; - - s->frames_out++; - return PLAYOUT_OK; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) playout_put(playout_state_t *s, void *data, int type, timestamp_t sender_len, timestamp_t sender_stamp, timestamp_t receiver_stamp) -{ - playout_frame_t *frame; - playout_frame_t *p; - - /* When a frame arrives we just queue it in order. We leave all the tricky stuff until frames - are read from the queue. */ - s->frames_in++; - - /* Acquire a frame */ - if ((frame = s->free_frames)) - { - s->free_frames = frame->later; - } - else - { - if ((frame = (playout_frame_t *) span_alloc(sizeof(*frame))) == NULL) - return PLAYOUT_ERROR; - } - - /* Fill out the frame */ - frame->data = data; - frame->type = type; - frame->sender_stamp = sender_stamp; - frame->sender_len = sender_len; - frame->receiver_stamp = receiver_stamp; - - /* Frames are kept in a list, sorted by the timestamp assigned by the sender. */ - if (s->last_frame == NULL) - { - /* The queue is empty. */ - frame->later = NULL; - frame->earlier = NULL; - s->first_frame = frame; - s->last_frame = frame; - } - else if (sender_stamp >= s->last_frame->sender_stamp) - { - /* Frame goes at the end of the queue. */ - frame->later = NULL; - frame->earlier = s->last_frame; - s->last_frame->later = frame; - s->last_frame = frame; - } - else - { - /* Frame is out of sequence. */ - s->frames_oos++; - - /* Find where it should go in the queue */ - p = s->last_frame; - while (sender_stamp < p->sender_stamp && p->earlier) - p = p->earlier; - - if (p->earlier) - { - /* It needs to go somewhere in the queue */ - frame->later = p->later; - frame->earlier = p; - p->later->earlier = frame; - p->later = frame; - } - else - { - /* It needs to go at the very beginning of the queue */ - frame->later = p; - frame->earlier = NULL; - p->earlier = frame; - s->first_frame = frame; - } - } - - if (s->start && type == PLAYOUT_TYPE_SPEECH) - { - s->last_speech_sender_stamp = sender_stamp - sender_len - s->min_length; - s->last_speech_sender_len = sender_len; - s->start = false; - } - - return PLAYOUT_OK; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) playout_restart(playout_state_t *s, int min_length, int max_length) -{ - playout_frame_t *frame; - playout_frame_t *next; - - /* Free all the frames on the free list */ - for (frame = s->free_frames; frame; frame = next) - { - next = frame->later; - span_free(frame); - } - - memset(s, 0, sizeof(*s)); - s->dynamic = (min_length < max_length); - 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->since_last_step = 0x7FFFFFFF; - /* Start with the minimum buffer length allowed, and work from there */ - s->actual_buffer_length = - s->target_buffer_length = (s->max_length - s->min_length)/2; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(playout_state_t *) playout_init(int min_length, int max_length) -{ - playout_state_t *s; - - 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); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) playout_release(playout_state_t *s) -{ - playout_frame_t *frame; - playout_frame_t *next; - - /* Free all the frames in the queue. In most cases these should have been - removed already, so their associated data could be freed. */ - for (frame = s->first_frame; frame; frame = next) - { - next = frame->later; - span_free(frame); - } - /* Free all the frames on the free list */ - for (frame = s->free_frames; frame; frame = next) - { - next = frame->later; - span_free(frame); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) playout_free(playout_state_t *s) -{ - if (s) - { - playout_release(s); - /* Finally, free ourselves! */ - span_free(s); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/plc.c b/libs/spandsp/src/plc.c deleted file mode 100644 index 007c9604d0..0000000000 --- a/libs/spandsp/src/plc.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * plc.c - * - * 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(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 -#include "floating_fudge.h" -#include - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/saturated.h" -#include "spandsp/vector_int.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 */ - -static void save_history(plc_state_t *s, int16_t *buf, int len) -{ - if (len >= PLC_HISTORY_LEN) - { - /* Just keep the last part of the new data, starting at the beginning of the buffer */ - vec_copyi16(s->history, &buf[len - PLC_HISTORY_LEN], PLC_HISTORY_LEN); - s->buf_ptr = 0; - return; - } - if (s->buf_ptr + len > PLC_HISTORY_LEN) - { - /* Wraps around - must break into two sections */ - vec_copyi16(&s->history[s->buf_ptr], buf, PLC_HISTORY_LEN - s->buf_ptr); - len -= (PLC_HISTORY_LEN - s->buf_ptr); - vec_copyi16(s->history, &buf[PLC_HISTORY_LEN - s->buf_ptr], len); - s->buf_ptr = len; - return; - } - /* Can use just one section */ - vec_copyi16(&s->history[s->buf_ptr], buf, len); - s->buf_ptr += len; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void normalise_history(plc_state_t *s) -{ - int16_t tmp[PLC_HISTORY_LEN]; - - if (s->buf_ptr == 0) - return; - vec_copyi16(tmp, s->history, s->buf_ptr); - vec_movei16(s->history, &s->history[s->buf_ptr], PLC_HISTORY_LEN - s->buf_ptr); - vec_copyi16(&s->history[PLC_HISTORY_LEN - s->buf_ptr], tmp, s->buf_ptr); - s->buf_ptr = 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len) -{ - int i; - int j; - int acc; - int min_acc; - int pitch; - - pitch = min_pitch; - min_acc = INT_MAX; - for (i = max_pitch; i <= min_pitch; i++) - { - acc = 0; - for (j = 0; j < len; j++) - acc += abs(amp[i + j] - amp[j]); - if (acc < min_acc) - { - min_acc = acc; - pitch = i; - } - } - return pitch; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) plc_rx(plc_state_t *s, int16_t amp[], int len) -{ - int i; - int pitch_overlap; - float old_step; - float new_step; - float old_weight; - float new_weight; - float gain; - - if (s->missing_samples) - { - /* Although we have a real signal, we need to smooth it to fit well - with the synthetic signal we used for the previous block */ - - /* The start of the real data is overlapped with the next 1/4 cycle - of the synthetic data. */ - pitch_overlap = s->pitch >> 2; - if (pitch_overlap > len) - pitch_overlap = len; - gain = 1.0f - s->missing_samples*ATTENUATION_INCREMENT; - if (gain < 0.0f) - gain = 0.0f; - new_step = 1.0f/pitch_overlap; - old_step = new_step*gain; - new_weight = new_step; - old_weight = (1.0f - new_step)*gain; - for (i = 0; i < pitch_overlap; i++) - { - amp[i] = fsaturate(old_weight*s->pitchbuf[s->pitch_offset] + new_weight*amp[i]); - if (++s->pitch_offset >= s->pitch) - s->pitch_offset = 0; - new_weight += new_step; - old_weight -= old_step; - if (old_weight < 0.0f) - old_weight = 0.0f; - } - s->missing_samples = 0; - } - save_history(s, amp, len); - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) plc_fillin(plc_state_t *s, int16_t amp[], int len) -{ - int i; - int pitch_overlap; - float old_step; - float new_step; - float old_weight; - float new_weight; - float gain; - int orig_len; - - orig_len = len; - if (s->missing_samples == 0) - { - /* As the gap in real speech starts we need to assess the last known pitch, - and prepare the synthetic data we will use for fill-in */ - normalise_history(s); - s->pitch = amdf_pitch(PLC_PITCH_MIN, PLC_PITCH_MAX, s->history + PLC_HISTORY_LEN - CORRELATION_SPAN - PLC_PITCH_MIN, CORRELATION_SPAN); - /* We overlap a 1/4 wavelength */ - pitch_overlap = s->pitch >> 2; - /* Cook up a single cycle of pitch, using a single of the real signal with 1/4 - cycle OLA'ed to make the ends join up nicely */ - /* The first 3/4 of the cycle is a simple copy */ - for (i = 0; i < s->pitch - pitch_overlap; i++) - s->pitchbuf[i] = s->history[PLC_HISTORY_LEN - s->pitch + i]; - /* The last 1/4 of the cycle is overlapped with the end of the previous cycle */ - new_step = 1.0f/pitch_overlap; - new_weight = new_step; - for ( ; i < s->pitch; i++) - { - s->pitchbuf[i] = s->history[PLC_HISTORY_LEN - s->pitch + i]*(1.0f - new_weight) + s->history[PLC_HISTORY_LEN - 2*s->pitch + i]*new_weight; - new_weight += new_step; - } - /* We should now be ready to fill in the gap with repeated, decaying cycles - of what is in pitchbuf */ - - gain = 1.0f; - /* We need to OLA the first 1/4 wavelength of the synthetic data, to smooth - it into the previous real data. To avoid the need to introduce a delay - in the stream, reverse the last 1/4 wavelength, and OLA with that. */ - new_step = 1.0f/pitch_overlap; - old_step = new_step; - new_weight = new_step; - old_weight = 1.0f - new_step; - for (i = 0; i < pitch_overlap; i++) - { - amp[i] = fsaturate(old_weight*s->history[PLC_HISTORY_LEN - 1 - i] + new_weight*s->pitchbuf[i]); - new_weight += new_step; - old_weight -= old_step; - if (old_weight < 0.0f) - old_weight = 0.0f; - } - s->pitch_offset = i; - } - else - { - gain = 1.0f - s->missing_samples*ATTENUATION_INCREMENT; - i = 0; - } - for ( ; gain > 0.0f && i < len; i++) - { - amp[i] = (int16_t) (s->pitchbuf[s->pitch_offset]*gain); - gain -= ATTENUATION_INCREMENT; - if (++s->pitch_offset >= s->pitch) - s->pitch_offset = 0; - } - for ( ; i < len; i++) - amp[i] = 0; - s->missing_samples += orig_len; - save_history(s, amp, len); - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(plc_state_t *) plc_init(plc_state_t *s) -{ - if (s == NULL) - { - if ((s = (plc_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) plc_release(plc_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) plc_free(plc_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/power_meter.c b/libs/spandsp/src/power_meter.c deleted file mode 100644 index 147fb47029..0000000000 --- a/libs/spandsp/src/power_meter.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * power_meter.c - * - * 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 */ - -#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 -#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 *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - s->shift = shift; - s->reading = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) power_meter_release(power_meter_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) power_meter_free(power_meter_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(power_meter_t *) power_meter_damping(power_meter_t *s, int shift) -{ - s->shift = shift; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) power_meter_update(power_meter_t *s, int16_t amp) -{ - s->reading += ((amp*amp - s->reading) >> s->shift); - return s->reading; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) power_meter_level_dbm0(float level) -{ - float l; - - level -= DBM0_MAX_POWER; - if (level > 0.0) - level = 0.0; - l = powf(10.0f, level/10.0f)*(32767.0f*32767.0f); - return (int32_t) l; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) power_meter_level_dbov(float level) -{ - float l; - - if (level > 0.0) - level = 0.0; - l = powf(10.0f, level/10.0f)*(32767.0f*32767.0f); - return (int32_t) l; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) power_meter_current(power_meter_t *s) -{ - return s->reading; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) power_meter_current_dbm0(power_meter_t *s) -{ - if (s->reading <= 0) - return -96.329f + DBM0_MAX_POWER; - /* This is based on A-law, but u-law is only 0.03dB different, so don't worry. */ - return 10.0f*log10f((float) s->reading/(32767.0f*32767.0f) + 1.0e-10f) + DBM0_MAX_POWER; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) power_meter_current_dbov(power_meter_t *s) -{ - if (s->reading <= 0) - return -96.329f; - return 10.0f*log10f((float) s->reading/(32767.0f*32767.0f) + 1.0e-10f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) power_surge_detector(power_surge_detector_state_t *s, int16_t amp) -{ - int32_t pow_short; - int32_t pow_medium; - - pow_short = power_meter_update(&s->short_term, amp); - pow_medium = power_meter_update(&s->medium_term, amp); - if (pow_medium < s->min) - return 0; - if (!s->signal_present) - { - if (pow_short <= s->surge*(pow_medium >> 10)) - return 0; - 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->medium_term.reading = s->short_term.reading; - return 0; - } - } - return pow_short; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) power_surge_detector_current_dbm0(power_surge_detector_state_t *s) -{ - return power_meter_current_dbm0(&s->short_term); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) power_surge_detector_current_dbov(power_surge_detector_state_t *s) -{ - return power_meter_current_dbov(&s->short_term); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(power_surge_detector_state_t *) power_surge_detector_init(power_surge_detector_state_t *s, float min, float surge) -{ - float ratio; - - if (s == NULL) - { - if ((s = (power_surge_detector_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - power_meter_init(&s->short_term, 4); - power_meter_init(&s->medium_term, 7); - ratio = powf(10.0f, surge/10.0f); - s->surge = 1024.0f*ratio; - s->sag = 1024.0f/ratio; - s->min = power_meter_level_dbm0(min); - s->medium_term.reading = s->min + 1; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) power_surge_detector_release(power_surge_detector_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) power_surge_detector_free(power_surge_detector_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/queue.c b/libs/spandsp/src/queue.c deleted file mode 100644 index 98f19e3962..0000000000 --- a/libs/spandsp/src/queue.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * queue.c - simple in-process message queuing - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#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(bool) queue_empty(queue_state_t *s) -{ - return (s->iptr == s->optr); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_free_space(queue_state_t *s) -{ - int len; - - if ((len = s->optr - s->iptr - 1) < 0) - len += s->len; - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_contents(queue_state_t *s) -{ - int len; - - if ((len = s->iptr - s->optr) < 0) - len += s->len; - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) queue_flush(queue_state_t *s) -{ - s->optr = s->iptr; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len) -{ - int real_len; - int to_end; - int iptr; - int optr; - - /* Snapshot the values (although only iptr should be changeable during this processing) */ - iptr = s->iptr; - optr = s->optr; - if ((real_len = iptr - optr) < 0) - real_len += s->len; - /*endif*/ - if (real_len < len) - { - if (s->flags & QUEUE_READ_ATOMIC) - return -1; - /*endif*/ - } - else - { - real_len = len; - } - /*endif*/ - if (real_len == 0) - return 0; - /*endif*/ - to_end = s->len - optr; - if (iptr < optr && to_end < real_len) - { - /* A two step process */ - if (buf) - { - memcpy(buf, &s->data[optr], to_end); - memcpy(&buf[to_end], s->data, real_len - to_end); - } - /*endif*/ - } - else - { - /* A one step process */ - if (buf) - memcpy(buf, &s->data[optr], real_len); - /*endif*/ - } - /*endif*/ - return real_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len) -{ - int real_len; - int to_end; - int new_optr; - int iptr; - int optr; - - /* Snapshot the values (although only iptr should be changeable during this processing) */ - iptr = s->iptr; - optr = s->optr; - if ((real_len = iptr - optr) < 0) - real_len += s->len; - /*endif*/ - if (real_len < len) - { - if (s->flags & QUEUE_READ_ATOMIC) - return -1; - /*endif*/ - } - else - { - real_len = len; - } - /*endif*/ - if (real_len == 0) - return 0; - /*endif*/ - to_end = s->len - optr; - if (iptr < optr && to_end < real_len) - { - /* A two step process */ - if (buf) - { - memcpy(buf, &s->data[optr], to_end); - memcpy(&buf[to_end], s->data, real_len - to_end); - } - /*endif*/ - new_optr = real_len - to_end; - } - else - { - /* A one step process */ - if (buf) - memcpy(buf, &s->data[optr], real_len); - /*endif*/ - new_optr = optr + real_len; - if (new_optr >= s->len) - new_optr = 0; - /*endif*/ - } - /*endif*/ - /* Only change the pointer now we have really finished */ - s->optr = new_optr; - return real_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_read_byte(queue_state_t *s) -{ - int real_len; - int iptr; - int optr; - int byte; - - /* Snapshot the values (although only iptr should be changeable during this processing) */ - iptr = s->iptr; - optr = s->optr; - if ((real_len = iptr - optr) < 0) - real_len += s->len; - /*endif*/ - if (real_len < 1) - return -1; - /*endif*/ - byte = s->data[optr]; - if (++optr >= s->len) - optr = 0; - /*endif*/ - /* Only change the pointer now we have really finished */ - s->optr = optr; - return byte; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len) -{ - int real_len; - int to_end; - int new_iptr; - int iptr; - int optr; - - /* Snapshot the values (although only optr should be changeable during this processing) */ - iptr = s->iptr; - optr = s->optr; - - if ((real_len = optr - iptr - 1) < 0) - real_len += s->len; - /*endif*/ - if (real_len < len) - { - if (s->flags & QUEUE_WRITE_ATOMIC) - return -1; - /*endif*/ - } - else - { - real_len = len; - } - /*endif*/ - if (real_len == 0) - return 0; - /*endif*/ - to_end = s->len - iptr; - if (iptr < optr || to_end >= real_len) - { - /* A one step process */ - memcpy(&s->data[iptr], buf, real_len); - new_iptr = iptr + real_len; - if (new_iptr >= s->len) - new_iptr = 0; - /*endif*/ - } - else - { - /* A two step process */ - memcpy(&s->data[iptr], buf, to_end); - memcpy(s->data, &buf[to_end], real_len - to_end); - new_iptr = real_len - to_end; - } - /*endif*/ - /* Only change the pointer now we have really finished */ - s->iptr = new_iptr; - return real_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_write_byte(queue_state_t *s, uint8_t byte) -{ - int real_len; - int iptr; - int optr; - - /* Snapshot the values (although only optr should be changeable during this processing) */ - iptr = s->iptr; - optr = s->optr; - - if ((real_len = optr - iptr - 1) < 0) - real_len += s->len; - /*endif*/ - if (real_len < 1) - { - if (s->flags & QUEUE_WRITE_ATOMIC) - return -1; - /*endif*/ - return 0; - } - /*endif*/ - s->data[iptr] = byte; - if (++iptr >= s->len) - iptr = 0; - /*endif*/ - /* Only change the pointer now we have really finished */ - s->iptr = iptr; - return 1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_state_test_msg(queue_state_t *s) -{ - uint16_t lenx; - - if (queue_view(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t)) - return -1; - /*endif*/ - return lenx; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_read_msg(queue_state_t *s, uint8_t *buf, int len) -{ - uint16_t lenx; - - /* If we assume the write message was atomic, this read message should be - safe when conducted in multiple chunks */ - if (queue_read(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t)) - return -1; - /*endif*/ - /* If we got this far, the actual message chunk should be guaranteed to be - available */ - if (lenx == 0) - return 0; - /*endif*/ - if ((int) lenx > len) - { - len = queue_read(s, buf, len); - /* Discard the rest of the message */ - queue_read(s, NULL, lenx - len); - return len; - } - /*endif*/ - return queue_read(s, buf, lenx); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len) -{ - int real_len; - int to_end; - int new_iptr; - int iptr; - int optr; - uint16_t lenx; - - /* Snapshot the values (although only optr should be changeable during this processing) */ - iptr = s->iptr; - optr = s->optr; - - if ((real_len = optr - iptr - 1) < 0) - real_len += s->len; - /*endif*/ - if (real_len < len + (int) sizeof(uint16_t)) - return -1; - /*endif*/ - real_len = len + (int) sizeof(uint16_t); - - to_end = s->len - iptr; - lenx = (uint16_t) len; - if (iptr < optr || to_end >= real_len) - { - /* A one step process */ - memcpy(&s->data[iptr], &lenx, sizeof(uint16_t)); - memcpy(&s->data[iptr + sizeof(uint16_t)], buf, len); - new_iptr = iptr + real_len; - if (new_iptr >= s->len) - new_iptr = 0; - /*endif*/ - } - else - { - /* A two step process */ - if (to_end >= sizeof(uint16_t)) - { - /* The actual message wraps around the end of the buffer */ - memcpy(&s->data[iptr], &lenx, sizeof(uint16_t)); - memcpy(&s->data[iptr + sizeof(uint16_t)], buf, to_end - sizeof(uint16_t)); - memcpy(s->data, &buf[to_end - sizeof(uint16_t)], real_len - to_end); - } - else - { - /* The message length wraps around the end of the buffer */ - memcpy(&s->data[iptr], (uint8_t *) &lenx, to_end); - memcpy(s->data, ((uint8_t *) &lenx) + to_end, sizeof(uint16_t) - to_end); - memcpy(&s->data[sizeof(uint16_t) - to_end], buf, len); - } - new_iptr = real_len - to_end; - } - /*endif*/ - /* Only change the pointer now we have really finished */ - s->iptr = new_iptr; - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(queue_state_t *) queue_init(queue_state_t *s, int len, int flags) -{ - if (s == NULL) - { - if ((s = (queue_state_t *) span_alloc(sizeof(*s) + len + 1)) == NULL) - return NULL; - } - s->iptr = - s->optr = 0; - s->flags = flags; - s->len = len + 1; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_release(queue_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) queue_free(queue_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/schedule.c b/libs/spandsp/src/schedule.c deleted file mode 100644 index 93916dea1d..0000000000 --- a/libs/spandsp/src/schedule.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * schedule.c - * - * 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#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" - -#include "spandsp/private/logging.h" -#include "spandsp/private/schedule.h" - -SPAN_DECLARE(int) span_schedule_event(span_sched_state_t *s, int us, span_sched_callback_func_t function, void *user_data) -{ - int i; - - for (i = 0; i < s->max_to_date; i++) - { - if (s->sched[i].callback == NULL) - break; - /*endif*/ - } - /*endfor*/ - if (i >= s->allocated) - { - s->allocated += 5; - s->sched = (span_sched_t *) span_realloc(s->sched, sizeof(span_sched_t)*s->allocated); - } - /*endif*/ - if (i >= s->max_to_date) - s->max_to_date = i + 1; - /*endif*/ - s->sched[i].when = s->ticker + us; - s->sched[i].callback = function; - s->sched[i].user_data = user_data; - return i; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint64_t) span_schedule_next(span_sched_state_t *s) -{ - int i; - uint64_t earliest; - - earliest = ~((uint64_t) 0); - for (i = 0; i < s->max_to_date; i++) - { - if (s->sched[i].callback && earliest > s->sched[i].when) - earliest = s->sched[i].when; - /*endif*/ - } - /*endfor*/ - return earliest; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint64_t) span_schedule_time(span_sched_state_t *s) -{ - return s->ticker; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) span_schedule_update(span_sched_state_t *s, int us) -{ - int i; - span_sched_callback_func_t callback; - void *user_data; - - s->ticker += us; - for (i = 0; i < s->max_to_date; i++) - { - if (s->sched[i].callback && s->sched[i].when <= s->ticker) - { - callback = s->sched[i].callback; - user_data = s->sched[i].user_data; - s->sched[i].callback = NULL; - s->sched[i].user_data = NULL; - callback(s, user_data); - } - /*endif*/ - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) span_schedule_del(span_sched_state_t *s, int i) -{ - if (i >= s->max_to_date - || - i < 0 - || - s->sched[i].callback == NULL) - { - span_log(&s->logging, SPAN_LOG_WARNING, "Requested to delete invalid scheduled ID %d ?\n", i); - return; - } - /*endif*/ - s->sched[i].callback = NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(span_sched_state_t *) span_schedule_init(span_sched_state_t *s) -{ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "SCHEDULE"); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_schedule_release(span_sched_state_t *s) -{ - if (s->sched) - { - span_free(s->sched); - s->sched = NULL; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_schedule_free(span_sched_state_t *s) -{ - if (s) - { - span_schedule_release(s); - span_free(s); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/sig_tone.c b/libs/spandsp/src/sig_tone.c deleted file mode 100644 index b21cd9f57d..0000000000 --- a/libs/spandsp/src/sig_tone.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * sig_tone.c - Signalling tone processing for the 2280Hz, 2400Hz, 2600Hz - * and similar signalling tones used in older protocols. - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#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/fast_convert.h" -#include "spandsp/saturated.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex.h" -#include "spandsp/power_meter.h" -#include "spandsp/dds.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/sig_tone.h" - -#include "spandsp/private/power_meter.h" -#include "spandsp/private/sig_tone.h" - -/*! PI */ -#define PI 3.14159265358979323 - -enum -{ - NOTCH_COEFF_SET_2280HZ = 0, - NOTCH_COEFF_SET_2400HZ, - NOTCH_COEFF_SET_2600HZ -}; - -/* The coefficients for the data notch filters. These filters are also the - guard filters for tone detection. */ -static const sig_tone_notch_coeffs_t notch_coeffs[3] = -{ - { /* 2280 Hz */ -#if defined(SPANDSP_USE_FIXED_POINT) - { 3600, 14397, 32767}, - { 0, -9425, -28954}, - { 0, 14196, 32767}, - { 0, -17393, -28954}, - 12, -#else - {0.878906f, 0.439362f, 1.0f}, - {0.0f, -0.287627f, -0.883605f}, - {0.0f, 0.433228f, 1.0f}, - {0.0f, -0.530792f, -0.883605f}, -#endif - }, - { /* 2400Hz */ -#if defined(SPANDSP_USE_FIXED_POINT) - { 3530, 20055, 32767}, - { 0, -14950, -28341}, - { 0, 20349, 32767}, - { 0, -22633, -28341}, - 12, -#else - {0.862000f, 0.612055f, 1.0f}, - {0.0f, -0.456264f, -0.864899f}, - {0.0f, 0.621021f, 1.0f}, - {0.0f, -0.690738f, -0.864899f}, -#endif - }, - { /* 2600Hz */ -#if defined(SPANDSP_USE_FIXED_POINT) - { 3530, 29569, 32767}, - { 0, -24010, -28341}, - { 0, 29844, 32767}, - { 0, -31208, -28341}, - 12, -#else - {0.862000f, 0.902374f, 1.0f}, - {0.0f, -0.732727f, -0.864899f}, - {0.0f, 0.910766f, 1.0f}, - {0.0f, -0.952393f, -0.864899f}, -#endif - } -}; - -static const sig_tone_flat_coeffs_t flat_coeffs[1] = -{ - { -#if defined(SPANDSP_USE_FIXED_POINT) - { 12900, -16384, -16384}, - { 0, -8578, -11796}, - 15, -#else - {0.393676f, -0.5f, -0.5f}, - {0.0f, -0.261778f, -0.359985f}, -#endif - } -}; - -static const sig_tone_descriptor_t sig_tones[3] = -{ - { - /* 2280Hz (e.g. AC15, and many other European protocols) */ - {2280, 0}, - {{-10, -20}, {0, 0}}, /* -10+-1 dBm0 and -20+-1 dBm0 */ - ms_to_samples(400), /* High to low timout - 300ms to 550ms */ - ms_to_samples(225), /* Sharp to flat timeout */ - ms_to_samples(225), /* Notch insertion timeout */ - - ms_to_samples(3), /* Tone on persistence check */ - ms_to_samples(8), /* Tone off persistence check */ - - 1, - { - ¬ch_coeffs[NOTCH_COEFF_SET_2280HZ], - NULL, - }, - &flat_coeffs[NOTCH_COEFF_SET_2280HZ], - -#if defined(SPANDSP_USE_FIXED_POINT) - 13, - -30, - -30 -#else - 13.0f, - -30.0f, - -30.0f -#endif - }, - { - /* 2600Hz (e.g. many US protocols) */ - {2600, 0}, - {{-8, -8}, {0, 0}}, - ms_to_samples(0), - ms_to_samples(0), - ms_to_samples(225), - - ms_to_samples(3), - ms_to_samples(8), - - 1, - { - ¬ch_coeffs[NOTCH_COEFF_SET_2600HZ], - NULL, - }, - NULL, - -#if defined(SPANDSP_USE_FIXED_POINT) - 16, - -30, - -30 -#else - 15.6f, - -30.0f, - -30.0f -#endif - }, - { - /* 2400Hz/2600Hz (e.g. SS5 and SS5bis) */ - {2400, 2600}, - {{-8, -8}, {-8, -8}}, - ms_to_samples(0), - ms_to_samples(0), - ms_to_samples(225), - - ms_to_samples(3), - ms_to_samples(8), - - 2, - { - ¬ch_coeffs[NOTCH_COEFF_SET_2400HZ], - ¬ch_coeffs[NOTCH_COEFF_SET_2600HZ] - }, - NULL, - -#if defined(SPANDSP_USE_FIXED_POINT) - 16, - -30, - -30 -#else - 15.6f, - -30.0f, - -30.0f -#endif - } -}; - -static const int tone_present_bits[3] = -{ - SIG_TONE_1_PRESENT, - SIG_TONE_2_PRESENT, - SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT -}; - -static const int tone_change_bits[3] = -{ - SIG_TONE_1_CHANGE, - SIG_TONE_2_CHANGE, - SIG_TONE_1_CHANGE | SIG_TONE_2_CHANGE -}; - -static const int coeff_sets[3] = -{ - 0, - 1, - 0 -}; - -SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len) -{ - int i; - int j; - int k; - int n; - int16_t tone; - bool need_update; - int high_low; - - for (i = 0; i < len; i += n) - { - if (s->current_tx_timeout) - { - if (s->current_tx_timeout <= len - i) - { - n = s->current_tx_timeout; - need_update = true; - } - else - { - n = len - i; - need_update = false; - } - s->current_tx_timeout -= n; - } - else - { - n = len - i; - need_update = false; - } - if (!(s->current_tx_tone & SIG_TONE_TX_PASSTHROUGH)) - vec_zeroi16(&[i], n); - /*endif*/ - if ((s->current_tx_tone & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) - { - /* Are we in the early phase (high tone energy level), or the sustaining - phase (low tone energy level) of tone generation? */ - /* This doesn't try to get the high/low timing precise, as there is no - value in doing so. It works block by block, and the blocks are normally - quite short. */ - if (s->high_low_timer > 0) - { - if (n > s->high_low_timer) - n = s->high_low_timer; - s->high_low_timer -= n; - high_low = 0; - } - else - { - high_low = 1; - } - /*endif*/ - for (k = 0; k < s->desc->tones; k++) - { - if ((s->current_tx_tone & tone_present_bits[k]) && s->phase_rate[k]) - { - for (j = i; j < i + n; j++) - { - tone = dds_mod(&s->phase_acc[k], s->phase_rate[k], s->tone_scaling[k][high_low], 0); - amp[j] = sat_add16(amp[j], tone); - } - /*endfor*/ - } - /*endif*/ - } - } - /*endif*/ - if (need_update && s->sig_update) - s->sig_update(s->user_data, SIG_TONE_TX_UPDATE_REQUEST, 0, 0); - /*endif*/ - } - /*endfor*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) sig_tone_tx_set_mode(sig_tone_tx_state_t *s, int mode, int duration) -{ - int old_tones; - int new_tones; - - old_tones = s->current_tx_tone & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT); - new_tones = mode & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT); - if (new_tones && old_tones != new_tones) - s->high_low_timer = s->desc->high_low_timeout; - /*endif*/ - /* If a tone is being turned on, let's start the phase from zero */ - if ((mode & SIG_TONE_1_PRESENT) && !(s->current_tx_tone & SIG_TONE_1_PRESENT)) - s->phase_acc[0] = 0; - if ((mode & SIG_TONE_2_PRESENT) && !(s->current_tx_tone & SIG_TONE_2_PRESENT)) - s->phase_acc[1] = 0; - s->current_tx_tone = mode; - s->current_tx_timeout = duration; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(sig_tone_tx_state_t *) sig_tone_tx_init(sig_tone_tx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data) -{ - int i; - - if (sig_update == NULL || tone_type < 1 || tone_type > 3) - return NULL; - /*endif*/ - - if (s == NULL) - { - if ((s = (sig_tone_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - s->sig_update = sig_update; - s->user_data = user_data; - - s->desc = &sig_tones[tone_type - 1]; - - for (i = 0; i < 2; i++) - { - if (s->desc->tone_freq[i]) - s->phase_rate[i] = dds_phase_rate((float) s->desc->tone_freq[i]); - else - s->phase_rate[i] = 0; - s->tone_scaling[i][0] = dds_scaling_dbm0((float) s->desc->tone_amp[i][0]); - s->tone_scaling[i][1] = dds_scaling_dbm0((float) s->desc->tone_amp[i][1]); - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) sig_tone_tx_release(sig_tone_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) sig_tone_tx_free(sig_tone_tx_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int nnn = 0; - -SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t x; - int32_t v; - int16_t notched_signal[3] = {0}; - int16_t bandpass_signal; - int16_t signal; -#else - float x; - float v; - float notched_signal[3] = {0}; - float bandpass_signal; - float signal; -#endif - int i; - int j; - int k; - int l; - int m; - int32_t notch_power[3] = {0}; - int32_t flat_power; - int immediate; - - l = s->desc->tones; - if (l == 2) - l = 3; - notch_power[1] = - notch_power[2] = INT32_MAX; - for (i = 0; i < len; i++) - { - if (s->signalling_state_duration < INT_MAX) - s->signalling_state_duration++; - /*endif*/ - signal = amp[i]; - for (j = 0; j < l; j++) - { - k = coeff_sets[j]; - /* The notch filter is two cascaded biquads. */ -#if defined(SPANDSP_USE_FIXED_POINT) - v = ((int32_t) signal*s->desc->notch[k]->a1[0]) - + ((int32_t) s->tone[j].notch_z1[0]*s->desc->notch[k]->b1[1]) - + ((int32_t) s->tone[j].notch_z1[1]*s->desc->notch[k]->b1[2]); - x = v >> 15; - v += ((int32_t) s->tone[j].notch_z1[0]*s->desc->notch[k]->a1[1]) - + ((int32_t) s->tone[j].notch_z1[1]*s->desc->notch[k]->a1[2]); - s->tone[j].notch_z1[1] = s->tone[j].notch_z1[0]; - s->tone[j].notch_z1[0] = x; - v += ((int32_t) s->tone[j].notch_z2[0]*s->desc->notch[k]->b2[1]) - + ((int32_t) s->tone[j].notch_z2[1]*s->desc->notch[k]->b2[2]); - x = v >> 15; - v += ((int32_t) s->tone[j].notch_z2[0]*s->desc->notch[k]->a2[1]) - + ((int32_t) s->tone[j].notch_z2[1]*s->desc->notch[k]->a2[2]); - s->tone[j].notch_z2[1] = s->tone[j].notch_z2[0]; - s->tone[j].notch_z2[0] = x; - notched_signal[j] = v >> s->desc->notch[k]->postscale; -#else - v = signal*s->desc->notch[k]->a1[0] - + s->tone[j].notch_z1[0]*s->desc->notch[k]->b1[1] - + s->tone[j].notch_z1[1]*s->desc->notch[k]->b1[2]; - x = v; - v += s->tone[j].notch_z1[0]*s->desc->notch[k]->a1[1] - + s->tone[j].notch_z1[1]*s->desc->notch[k]->a1[2]; - s->tone[j].notch_z1[1] = s->tone[j].notch_z1[0]; - s->tone[j].notch_z1[0] = x; - v += s->tone[j].notch_z2[0]*s->desc->notch[k]->b2[1] - + s->tone[j].notch_z2[1]*s->desc->notch[k]->b2[2]; - x = v; - v += s->tone[j].notch_z2[0]*s->desc->notch[k]->a2[1] - + s->tone[j].notch_z2[1]*s->desc->notch[k]->a2[2]; - s->tone[j].notch_z2[1] = s->tone[j].notch_z2[0]; - s->tone[j].notch_z2[0] = x; - notched_signal[j] = v; -#endif - /* Modulus and leaky integrate the notched data. The result of - this isn't used in low tone detect mode, but we must keep the - power measurement rolling along. */ - notch_power[j] = power_meter_update(&s->tone[j].power, notched_signal[j]); - if (j == 1) - signal = notched_signal[j]; - } - 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; - /*endif*/ - } - else - { - s->flat_mode_timeout = s->desc->sharp_flat_timeout; - s->flat_mode = false; - } - /*endif*/ - - immediate = -1; - if (s->flat_mode) - { - //printf("Flat mode %d %d\n", s->flat_mode_timeout, s->desc->sharp_flat_timeout); - /* Flat mode */ - bandpass_signal = amp[i]; - if (s->desc->flat) - { - /* The bandpass filter is a single bi-quad stage */ -#if defined(SPANDSP_USE_FIXED_POINT) - v = ((int32_t) amp[i]*s->desc->flat->a[0]) - + ((int32_t) s->flat_z[0]*s->desc->flat->b[1]) - + ((int32_t) s->flat_z[1]*s->desc->flat->b[2]); - x = v >> 15; - v += ((int32_t) s->flat_z[0]*s->desc->flat->a[1]) - + ((int32_t) s->flat_z[1]*s->desc->flat->a[2]); - s->flat_z[1] = s->flat_z[0]; - s->flat_z[0] = x; - bandpass_signal = v >> s->desc->flat->postscale; -#else - v = amp[i]*s->desc->flat->a[0] - + s->flat_z[0]*s->desc->flat->b[1] - + s->flat_z[1]*s->desc->flat->b[2]; - x = v; - v += s->flat_z[0]*s->desc->flat->a[1] - + s->flat_z[1]*s->desc->flat->a[2]; - s->flat_z[1] = s->flat_z[0]; - s->flat_z[0] = x; - bandpass_signal = v; -#endif - } - flat_power = power_meter_update(&s->flat_power, bandpass_signal); - - /* For the flat receiver we use a simple power threshold! */ - if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) - { - if (flat_power < s->flat_detection_threshold) - { - s->signalling_state &= ~tone_present_bits[0]; - s->signalling_state |= tone_change_bits[0]; - } - /*endif*/ - } - else - { - if (flat_power > s->flat_detection_threshold) - s->signalling_state |= (tone_present_bits[0] | tone_change_bits[0]); - /*endif*/ - } - /*endif*/ - - /* Notch insertion logic */ - /* tone_present and tone_on are equivalent in flat mode */ - if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) - { - s->notch_insertion_timeout = s->desc->notch_lag_time; - } - else - { - if (s->notch_insertion_timeout) - s->notch_insertion_timeout--; - /*endif*/ - } - /*endif*/ - } - else - { - /* Sharp mode */ - flat_power = power_meter_update(&s->flat_power, amp[i]); - - /* Persistence checking and notch insertion logic */ - if (flat_power >= s->sharp_detection_threshold) - { - /* Which is the better of the single tone responses? */ - m = (notch_power[0] < notch_power[1]) ? 0 : 1; - /* Single tone has precedence. If the better one fails to detect, try - for a dual tone signal. */ - if ((notch_power[m] >> 6)*s->detection_ratio < (flat_power >> 6)) - immediate = m; - else if ((notch_power[2] >> 6)*s->detection_ratio < (flat_power >> 7)) - immediate = 2; - } - //printf("Immediate = %d %d %d\n", immediate, s->signalling_state, s->tone_persistence_timeout); - if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) - { - if (immediate != s->current_notch_filter) - { - /* No tone is detected this sample */ - if (--s->tone_persistence_timeout == 0) - { - /* Tone off is confirmed */ - s->tone_persistence_timeout = s->desc->tone_on_check_time; - s->signalling_state |= ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT)) << 1); - s->signalling_state &= ~(SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT); - } - /*endif*/ - } - else - { - s->tone_persistence_timeout = s->desc->tone_off_check_time; - } - /*endif*/ - } - else - { - if (s->notch_insertion_timeout) - s->notch_insertion_timeout--; - /*endif*/ - if (immediate >= 0 && immediate == s->last_sample_tone_present) - { - /* Consistent tone detected this sample */ - if (--s->tone_persistence_timeout == 0) - { - /* Tone on is confirmed */ - s->tone_persistence_timeout = s->desc->tone_off_check_time; - s->notch_insertion_timeout = s->desc->notch_lag_time; - s->signalling_state |= (tone_present_bits[immediate] | tone_change_bits[immediate]); - s->current_notch_filter = immediate; - } - /*endif*/ - } - else - { - s->tone_persistence_timeout = s->desc->tone_on_check_time; - } - /*endif*/ - } - /*endif*/ - //printf("XXX %d %d %d %d %d %d\n", nnn++, notch_power[0], notch_power[1], notch_power[2], flat_power, immediate*10000000); - } - /*endif*/ - if ((s->signalling_state & (SIG_TONE_1_CHANGE | SIG_TONE_2_CHANGE))) - { - if (s->sig_update) - s->sig_update(s->user_data, s->signalling_state, 0, s->signalling_state_duration); - /*endif*/ - s->signalling_state &= ~(SIG_TONE_1_CHANGE | SIG_TONE_2_CHANGE); - s->signalling_state_duration = 0; - } - /*endif*/ - - if ((s->current_rx_tone & SIG_TONE_RX_PASSTHROUGH)) - { - if ((s->current_rx_tone & SIG_TONE_RX_FILTER_TONE) || s->notch_insertion_timeout) -#if defined(SPANDSP_USE_FIXED_POINT) - amp[i] = saturate16(notched_signal[s->current_notch_filter]); -#else - amp[i] = fsaturatef(notched_signal[s->current_notch_filter]); -#endif - /*endif*/ - } - else - { - /* Simply mute the media path */ - amp[i] = 0; - } - /*endif*/ - s->last_sample_tone_present = immediate; - } - /*endfor*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) sig_tone_rx_set_mode(sig_tone_rx_state_t *s, int mode, int duration) -{ - s->current_rx_tone = mode; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(sig_tone_rx_state_t *) sig_tone_rx_init(sig_tone_rx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data) -{ - int i; -#if !defined(SPANDSP_USE_FIXED_POINT) - int j; -#endif - - if (sig_update == NULL || tone_type < 1 || tone_type > 3) - return NULL; - /*endif*/ - - if (s == NULL) - { - if ((s = (sig_tone_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); -#if !defined(SPANDSP_USE_FIXED_POINT) - for (j = 0; j < 3; j++) - { - for (i = 0; i < 2; i++) - { - s->tone[j].notch_z1[i] = 0.0f; - s->tone[j].notch_z2[i] = 0.0f; - } - } - for (i = 0; i < 2; i++) - s->flat_z[i] = 0.0f; -#endif - s->last_sample_tone_present = -1; - - s->sig_update = sig_update; - s->user_data = user_data; - - s->desc = &sig_tones[tone_type - 1]; - - for (i = 0; i < 3; i++) - power_meter_init(&s->tone[i].power, 5); - power_meter_init(&s->flat_power, 5); - - s->flat_detection_threshold = power_meter_level_dbm0(s->desc->flat_detection_threshold); - s->sharp_detection_threshold = power_meter_level_dbm0(s->desc->sharp_detection_threshold); - s->detection_ratio = powf(10.0f, s->desc->detection_ratio/10.0f) + 1.0f; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) sig_tone_rx_release(sig_tone_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) sig_tone_rx_free(sig_tone_rx_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/silence_gen.c b/libs/spandsp/src/silence_gen.c deleted file mode 100644 index e2da8fa387..0000000000 --- a/libs/spandsp/src/silence_gen.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * silence_gen.c - A silence generator, for inserting timed silences. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/async.h" -#include "spandsp/silence_gen.h" - -#include "spandsp/private/silence_gen.h" - -SPAN_DECLARE(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len) -{ - if (s->remaining_samples != INT_MAX) - { - if (max_len >= s->remaining_samples) - { - max_len = s->remaining_samples; - if (max_len && s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE); - } - s->remaining_samples -= max_len; - } - if (INT_MAX - s->total_samples >= max_len) - s->total_samples += max_len; - memset(amp, 0, max_len*sizeof(int16_t)); - return max_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) silence_gen_always(silence_gen_state_t *s) -{ - s->remaining_samples = INT_MAX; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) silence_gen_set(silence_gen_state_t *s, int silent_samples) -{ - s->remaining_samples = silent_samples; - s->total_samples = 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) silence_gen_alter(silence_gen_state_t *s, int silent_samples) -{ - /* Block negative silences */ - if (silent_samples < 0) - { - if (-silent_samples > s->remaining_samples) - silent_samples = -s->remaining_samples; - } - s->remaining_samples += silent_samples; - s->total_samples += silent_samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) silence_gen_remainder(silence_gen_state_t *s) -{ - return s->remaining_samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) silence_gen_generated(silence_gen_state_t *s) -{ - return s->total_samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(silence_gen_state_t *) silence_gen_init(silence_gen_state_t *s, int silent_samples) -{ - if (s == NULL) - { - if ((s = (silence_gen_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->remaining_samples = silent_samples; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) silence_gen_release(silence_gen_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -/* The following dummy routines, to absorb data, don't really have a proper home, - so they have been put here. */ - -SPAN_DECLARE(int) span_dummy_rx(void *user_data, const int16_t amp[], int len) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_dummy_mod(void *user_data, int16_t amp[], int len) -{ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) span_dummy_rx_fillin(void *user_data, int len) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp.h.in b/libs/spandsp/src/spandsp.h.in deleted file mode 100644 index 7ec041f195..0000000000 --- a/libs/spandsp/src/spandsp.h.in +++ /dev/null @@ -1,151 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * spandsp.h - The head guy amongst the headers - * - * 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 */ - -#if !defined(_SPANDSP_H_) -#define _SPANDSP_H_ - -@SPANDSP_USE_FIXED_POINT@ -@SPANDSP_MISALIGNED_ACCESS_FAILS@ - -@SPANDSP_USE_EXPORT_CAPABILITY@ - -@SPANDSP_SUPPORT_T43@ -@SPANDSP_SUPPORT_V32BIS@ -@SPANDSP_SUPPORT_V34@ -@SPANDSP_SUPPORT_TIFF_FX@ - -#include -@INSERT_INTTYPES_HEADER@ -#include -#include -#include -@INSERT_MATH_HEADER@ -@INSERT_STDBOOL_HEADER@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) -#include -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/ademco_contactid.h b/libs/spandsp/src/spandsp/ademco_contactid.h deleted file mode 100644 index 43d807fb9b..0000000000 --- a/libs/spandsp/src/spandsp/ademco_contactid.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * ademco_contactid.h Ademco ContactID alarm protocol - * - * 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 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_ADEMCO_CONTACTID_H_) -#define _SPANDSP_ADEMCO_CONTACTID_H_ - -enum -{ - ADEMCO_CONTACTID_MESSAGE_TYPE_18 = 0x18, - ADEMCO_CONTACTID_MESSAGE_TYPE_98 = 0x98 -}; - -enum -{ - ADEMCO_CONTACTID_QUALIFIER_NEW_EVENT = 1, - ADEMCO_CONTACTID_QUALIFIER_NEW_RESTORE = 3, - ADEMCO_CONTACTID_QUALIFIER_STATUS_REPORT = 6 -}; - -enum -{ - ADEMCO_CONTACTID_DATA_IS_ZONE = 0, - ADEMCO_CONTACTID_DATA_IS_USER = 1 -}; - -enum -{ - ADEMCO_CONTACTID_MEDICAL = 0x100, - ADEMCO_CONTACTID_PERSONAL_EMERGENCY = 0x101, - ADEMCO_CONTACTID_FAIL_TO_REPORT_IN = 0x102, - ADEMCO_CONTACTID_FIRE = 0x110, - ADEMCO_CONTACTID_SMOKE = 0x111, - ADEMCO_CONTACTID_COMBUSTION = 0x112, - ADEMCO_CONTACTID_WATER_FLOW = 0x113, - ADEMCO_CONTACTID_HEAT = 0x114, - ADEMCO_CONTACTID_PULL_STATION = 0x115, - ADEMCO_CONTACTID_DUCT = 0x116, - ADEMCO_CONTACTID_FLAME = 0x117, - ADEMCO_CONTACTID_NEAR_ALARM_A = 0x118, - ADEMCO_CONTACTID_PANIC = 0x120, - ADEMCO_CONTACTID_DURESS = 0x121, - ADEMCO_CONTACTID_SILENT = 0x122, - ADEMCO_CONTACTID_AUDIBLE = 0x123, - ADEMCO_CONTACTID_DURESS_ACCESS_GRANTED = 0x124, - ADEMCO_CONTACTID_DURESS_EGRESS_GRANTED = 0x125, - ADEMCO_CONTACTID_BURGLARY = 0x130, - ADEMCO_CONTACTID_PERIMETER = 0x131, - ADEMCO_CONTACTID_INTERIOR = 0x132, - ADEMCO_CONTACTID_24_HOUR_SAFE = 0x133, - ADEMCO_CONTACTID_ENTRY_EXIT = 0x134, - ADEMCO_CONTACTID_DAY_NIGHT = 0x135, - ADEMCO_CONTACTID_OUTDOOR = 0x136, - ADEMCO_CONTACTID_TAMPER = 0x137, - ADEMCO_CONTACTID_NEAR_ALARM_B = 0x138, - ADEMCO_CONTACTID_INTRUSION_VERIFIER = 0x139, - ADEMCO_CONTACTID_GENERAL_ALARM = 0x140, - ADEMCO_CONTACTID_POLLING_LOOP_OPEN_A = 0x141, - ADEMCO_CONTACTID_POLLING_LOOP_SHORT_A = 0x142, - ADEMCO_CONTACTID_EXPANSION_MODULE_FAILURE_A = 0x143, - ADEMCO_CONTACTID_SENSOR_TAMPER_A = 0x144, - ADEMCO_CONTACTID_EXPANSION_MODULE_TAMPER = 0x145, - ADEMCO_CONTACTID_SILENT_BURGLARY = 0x146, - ADEMCO_CONTACTID_SENSOR_SUPERVISION_FAILURE = 0x147, - ADEMCO_CONTACTID_24_HOUR_NONBURGLARY = 0x150, - ADEMCO_CONTACTID_GAS_DETECTED = 0x151, - ADEMCO_CONTACTID_REFRIGERATION = 0x152, - ADEMCO_CONTACTID_LOSS_OF_HEAT = 0x153, - ADEMCO_CONTACTID_WATER_LEAKAGE = 0x154, - ADEMCO_CONTACTID_FOIL_BREAK = 0x155, - ADEMCO_CONTACTID_DAY_TROUBLE = 0x156, - ADEMCO_CONTACTID_LOW_BOTTLED_GAS_LEVEL = 0x157, - ADEMCO_CONTACTID_HIGH_TEMP = 0x158, - ADEMCO_CONTACTID_LOW_TEMP = 0x159, - ADEMCO_CONTACTID_LOSS_OF_AIR_FLOW = 0x161, - ADEMCO_CONTACTID_CARBON_MONOXIDE_DETECTED = 0x162, - ADEMCO_CONTACTID_TANK_LEVEL = 0x163, - ADEMCO_CONTACTID_FIRE_SUPERVISORY = 0x200, - ADEMCO_CONTACTID_LOW_WATER_PRESSURE = 0x201, - ADEMCO_CONTACTID_LOW_CO2 = 0x202, - ADEMCO_CONTACTID_GATE_VALVE_SENSOR = 0x203, - ADEMCO_CONTACTID_LOW_WATER_LEVEL = 0x204, - ADEMCO_CONTACTID_PUMP_ACTIVATED = 0x205, - ADEMCO_CONTACTID_PUMP_FAILURE = 0x206, - ADEMCO_CONTACTID_SYSTEM_TROUBLE = 0x300, - ADEMCO_CONTACTID_AC_LOSS = 0x301, - ADEMCO_CONTACTID_LOW_SYSTEM_BATTERY = 0x302, - ADEMCO_CONTACTID_RAM_CHECKSUM_BAD = 0x303, - ADEMCO_CONTACTID_ROM_CHECKSUM_BAD = 0x304, - ADEMCO_CONTACTID_SYSTEM_RESET = 0x305, - ADEMCO_CONTACTID_PANEL_PROGRAMMING_CHANGED = 0x306, - ADEMCO_CONTACTID_SELFTEST_FAILURE = 0x307, - ADEMCO_CONTACTID_SYSTEM_SHUTDOWN = 0x308, - ADEMCO_CONTACTID_BATTERY_TEST_FAILURE = 0x309, - ADEMCO_CONTACTID_GROUND_FAULT = 0x310, - ADEMCO_CONTACTID_BATTERY_MISSING_DEAD = 0x311, - ADEMCO_CONTACTID_POWER_SUPPLY_OVERCURRENT = 0x312, - ADEMCO_CONTACTID_ENGINEER_RESET = 0x313, - ADEMCO_CONTACTID_SOUNDER_RELAY = 0x320, - ADEMCO_CONTACTID_BELL_1 = 0x321, - ADEMCO_CONTACTID_BELL_2 = 0x322, - ADEMCO_CONTACTID_ALARM_RELAY = 0x323, - ADEMCO_CONTACTID_TROUBLE_RELAY = 0x324, - ADEMCO_CONTACTID_REVERSING_RELAY = 0x325, - ADEMCO_CONTACTID_NOTIFICATION_APPLIANCE_CKT_3 = 0x326, - ADEMCO_CONTACTID_NOTIFICATION_APPLIANCE_CKT_4 = 0x327, - ADEMCO_CONTACTID_SYSTEM_PERIPHERAL_TROUBLE = 0x330, - ADEMCO_CONTACTID_POLLING_LOOP_OPEN_B = 0x331, - ADEMCO_CONTACTID_POLLING_LOOP_SHORT_B = 0x332, - ADEMCO_CONTACTID_EXPANSION_MODULE_FAILURE_B = 0x333, - ADEMCO_CONTACTID_REPEATER_FAILURE = 0x334, - ADEMCO_CONTACTID_LOCAL_PRINTER_OUT_OF_PAPER = 0x335, - ADEMCO_CONTACTID_LOCAL_PRINTER_FAILURE = 0x336, - ADEMCO_CONTACTID_EXP_MODULE_DC_LOSS = 0x337, - ADEMCO_CONTACTID_EXP_MODULE_LOW_BATTERY = 0x338, - ADEMCO_CONTACTID_EXP_MODULE_RESET = 0x339, - ADEMCO_CONTACTID_EXP_MODULE_TAMPER = 0x341, - ADEMCO_CONTACTID_EXP_MODULE_AC_LOSS = 0x342, - ADEMCO_CONTACTID_EXP_MODULE_SELFTEST_FAIL = 0x343, - ADEMCO_CONTACTID_RF_RECEIVER_JAM_DETECT = 0x344, - ADEMCO_CONTACTID_COMMUNICATION_TROUBLE = 0x350, - ADEMCO_CONTACTID_TELCO_1_FAULT = 0x351, - ADEMCO_CONTACTID_TELCO_2_FAULT = 0x352, - ADEMCO_CONTACTID_LONG_RANGE_RADIO_TRANSMITTER_FAULT = 0x353, - ADEMCO_CONTACTID_FAILURE_TO_COMMUNICATE_EVENT = 0x354, - ADEMCO_CONTACTID_LOSS_OF_RADIO_SUPERVISION = 0x355, - ADEMCO_CONTACTID_LOSS_OF_CENTRAL_POLLING = 0x356, - ADEMCO_CONTACTID_LONG_RANGE_RADIO_VSWR_PROBLEM = 0x357, - ADEMCO_CONTACTID_PROTECTION_LOOP = 0x370, - ADEMCO_CONTACTID_PROTECTION_LOOP_OPEN = 0x371, - ADEMCO_CONTACTID_PROTECTION_LOOP_SHORT = 0x372, - ADEMCO_CONTACTID_FIRE_TROUBLE = 0x373, - ADEMCO_CONTACTID_EXIT_ERROR_ALARM_ZONE = 0x374, - ADEMCO_CONTACTID_PANIC_ZONE_TROUBLE = 0x375, - ADEMCO_CONTACTID_HOLDUP_ZONE_TROUBLE = 0x376, - ADEMCO_CONTACTID_SWINGER_TROUBLE = 0x377, - ADEMCO_CONTACTID_CROSSZONE_TROUBLE = 0x378, - ADEMCO_CONTACTID_SENSOR_TROUBLE = 0x380, - ADEMCO_CONTACTID_LOSS_OF_SUPERVISION__RF = 0x381, - ADEMCO_CONTACTID_LOSS_OF_SUPERVISION__RPM = 0x382, - ADEMCO_CONTACTID_SENSOR_TAMPER_B = 0x383, - ADEMCO_CONTACTID_RF_LOW_BATTERY = 0x384, - ADEMCO_CONTACTID_SMOKE_DETECTOR_HIGH_SENSITIVITY = 0x385, - ADEMCO_CONTACTID_SMOKE_DETECTOR_LOW_SENSITIVITY = 0x386, - ADEMCO_CONTACTID_INTRUSION_DETECTOR_HIGH_SENSITIVITY = 0x387, - ADEMCO_CONTACTID_INTRUSION_DETECTOR_LOW_SENSITIVITY = 0x388, - ADEMCO_CONTACTID_SENSOR_SELFTEST_FAILURE = 0x389, - ADEMCO_CONTACTID_SENSOR_WATCH_TROUBLE = 0x391, - ADEMCO_CONTACTID_DRIFT_COMPENSATION_ERROR = 0x392, - ADEMCO_CONTACTID_MAINTENANCE_ALERT = 0x393, - ADEMCO_CONTACTID_OPEN_CLOSE = 0x400, - ADEMCO_CONTACTID_OC_BY_USER = 0x401, - ADEMCO_CONTACTID_GROUP_OC = 0x402, - ADEMCO_CONTACTID_AUTOMATIC_OC = 0x403, - ADEMCO_CONTACTID_LATE_TO_OC = 0x404, - ADEMCO_CONTACTID_DEFERRED_OC = 0x405, - ADEMCO_CONTACTID_CANCEL = 0x406, - ADEMCO_CONTACTID_REMOTE_ARM_DISARM = 0x407, - ADEMCO_CONTACTID_QUICK_ARM = 0x408, - ADEMCO_CONTACTID_KEYSWITCH_OC = 0x409, - ADEMCO_CONTACTID_ARMED_STAY = 0x441, - ADEMCO_CONTACTID_KEYSWITCH_ARMED_STAY = 0x442, - ADEMCO_CONTACTID_EXCEPTION_OC = 0x450, - ADEMCO_CONTACTID_EARLY_OC = 0x451, - ADEMCO_CONTACTID_LATE_OC = 0x452, - ADEMCO_CONTACTID_FAILED_TO_OPEN = 0x453, - ADEMCO_CONTACTID_FAILED_TO_CLOSE = 0x454, - ADEMCO_CONTACTID_AUTOARM_FAILED = 0x455, - ADEMCO_CONTACTID_PARTIAL_ARM = 0x456, - ADEMCO_CONTACTID_EXIT_ERROR_USER = 0x457, - ADEMCO_CONTACTID_USER_ON_PREMISES = 0x458, - ADEMCO_CONTACTID_RECENT_CLOSE = 0x459, - ADEMCO_CONTACTID_WRONG_CODE_ENTRY = 0x461, - ADEMCO_CONTACTID_LEGAL_CODE_ENTRY = 0x462, - ADEMCO_CONTACTID_REARM_AFTER_ALARM = 0x463, - ADEMCO_CONTACTID_AUTOARM_TIME_EXTENDED = 0x464, - ADEMCO_CONTACTID_PANIC_ALARM_RESET = 0x465, - ADEMCO_CONTACTID_SERVICE_ON_OFF_PREMISES = 0x466, - ADEMCO_CONTACTID_CALLBACK_REQUEST_MADE = 0x411, - ADEMCO_CONTACTID_SUCCESSFUL_DOWNLOAD_ACCESS = 0x412, - ADEMCO_CONTACTID_UNSUCCESSFUL_ACCESS = 0x413, - ADEMCO_CONTACTID_SYSTEM_SHUTDOWN_COMMAND_RECEIVED = 0x414, - ADEMCO_CONTACTID_DIALER_SHUTDOWN_COMMAND_RECEIVED = 0x415, - ADEMCO_CONTACTID_SUCCESSFUL_UPLOAD = 0x416, - ADEMCO_CONTACTID_ACCESS_DENIED = 0x421, - ADEMCO_CONTACTID_ACCESS_REPORT_BY_USER = 0x422, - ADEMCO_CONTACTID_FORCED_ACCESS = 0x423, - ADEMCO_CONTACTID_EGRESS_DENIED = 0x424, - ADEMCO_CONTACTID_EGRESS_GRANTED = 0x425, - ADEMCO_CONTACTID_ACCESS_DOOR_PROPPED_OPEN = 0x426, - ADEMCO_CONTACTID_ACCESS_POINT_DOOR_STATUS_MONITOR_TROUBLE = 0x427, - ADEMCO_CONTACTID_ACCESS_POINT_REQUEST_TO_EXIT_TROUBLE = 0x428, - ADEMCO_CONTACTID_ACCESS_PROGRAM_MODE_ENTRY = 0x429, - ADEMCO_CONTACTID_ACCESS_PROGRAM_MODE_EXIT = 0x430, - ADEMCO_CONTACTID_ACCESS_THREAT_LEVEL_CHANGE = 0x431, - ADEMCO_CONTACTID_ACCESS_RELAY_TRIGGER_FAIL = 0x432, - ADEMCO_CONTACTID_ACCESS_RTE_SHUNT = 0x433, - ADEMCO_CONTACTID_ACCESS_DSM_SHUNT = 0x434, - ADEMCO_CONTACTID_ACCESS_READER_DISABLE = 0x501, - ADEMCO_CONTACTID_SOUNDER_RELAY_DISABLE = 0x520, - ADEMCO_CONTACTID_BELL_1_DISABLE = 0x521, - ADEMCO_CONTACTID_BELL_2_DISABLE = 0x522, - ADEMCO_CONTACTID_ALARM_RELAY_DISABLE = 0x523, - ADEMCO_CONTACTID_TROUBLE_RELAY_DISABLE = 0x524, - ADEMCO_CONTACTID_REVERSING_RELAY_DISABLE = 0x525, - ADEMCO_CONTACTID_NOTIFICATION_APPLIANCE_CKT_3_DISABLE = 0x526, - ADEMCO_CONTACTID_NOTIFICATION_APPLIANCE_CKT_4_DISABLE = 0x527, - ADEMCO_CONTACTID_MODULE_ADDED = 0x531, - ADEMCO_CONTACTID_MODULE_REMOVED = 0x532, - ADEMCO_CONTACTID_DIALER_DISABLED = 0x551, - ADEMCO_CONTACTID_RADIO_TRANSMITTER_DISABLED = 0x552, - ADEMCO_CONTACTID_REMOTE_UPLOAD_DOWNLOAD_DISABLED = 0x553, - ADEMCO_CONTACTID_ZONE_SENSOR_BYPASS = 0x570, - ADEMCO_CONTACTID_FIRE_BYPASS = 0x571, - ADEMCO_CONTACTID_24_HOUR_ZONE_BYPASS = 0x572, - ADEMCO_CONTACTID_BURG_BYPASS = 0x573, - ADEMCO_CONTACTID_GROUP_BYPASS = 0x574, - ADEMCO_CONTACTID_SWINGER_BYPASS = 0x575, - ADEMCO_CONTACTID_ACCESS_ZONE_SHUNT = 0x576, - ADEMCO_CONTACTID_ACCESS_POINT_BYPASS = 0x577, - ADEMCO_CONTACTID_MANUAL_TRIGGER_TEST_REPORT = 0x601, - ADEMCO_CONTACTID_PERIODIC_TEST_REPORT = 0x602, - ADEMCO_CONTACTID_PERIODIC_RF_TRANSMISSION = 0x603, - ADEMCO_CONTACTID_FIRE_TEST = 0x604, - ADEMCO_CONTACTID_STATUS_REPORT_TO_FOLLOW = 0x605, - ADEMCO_CONTACTID_LISTENIN_TO_FOLLOW = 0x606, - ADEMCO_CONTACTID_WALK_TEST_MODE = 0x607, - ADEMCO_CONTACTID_PERIODIC_TEST__SYSTEM_TROUBLE_PRESENT = 0x608, - ADEMCO_CONTACTID_VIDEO_TRANSMITTER_ACTIVE = 0x609, - ADEMCO_CONTACTID_POINT_TESTED_OK = 0x611, - ADEMCO_CONTACTID_POINT_NOT_TESTED = 0x612, - ADEMCO_CONTACTID_INTRUSION_ZONE_WALK_TESTED = 0x613, - ADEMCO_CONTACTID_FIRE_ZONE_WALK_TESTED = 0x614, - ADEMCO_CONTACTID_PANIC_ZONE_WALK_TESTED = 0x615, - ADEMCO_CONTACTID_SERVICE_REQUEST = 0x616, - ADEMCO_CONTACTID_EVENT_LOG_RESET = 0x621, - ADEMCO_CONTACTID_EVENT_LOG_50PC_FULL = 0x622, - ADEMCO_CONTACTID_EVENT_LOG_90PC_FULL = 0x623, - ADEMCO_CONTACTID_EVENT_LOG_OVERFLOW = 0x624, - ADEMCO_CONTACTID_TIME_DATE_RESET = 0x625, - ADEMCO_CONTACTID_TIME_DATE_INACCURATE = 0x626, - ADEMCO_CONTACTID_PROGRAM_MODE_ENTRY = 0x627, - ADEMCO_CONTACTID_PROGRAM_MODE_EXIT = 0x628, - ADEMCO_CONTACTID_32_HOUR_EVENT_LOG_MARKER = 0x629, - ADEMCO_CONTACTID_SCHEDULE_CHANGE = 0x630, - ADEMCO_CONTACTID_EXCEPTION_SCHEDULE_CHANGE = 0x631, - ADEMCO_CONTACTID_ACCESS_SCHEDULE_CHANGE = 0x632, - ADEMCO_CONTACTID_SENIOR_WATCH_TROUBLE = 0x641, - ADEMCO_CONTACTID_LATCHKEY_SUPERVISION = 0x642, - ADEMCO_CONTACTID_RESERVED_FOR_ADEMCO_USE_1 = 0x651, - ADEMCO_CONTACTID_RESERVED_FOR_ADEMCO_USE_2 = 0x652, - ADEMCO_CONTACTID_RESERVED_FOR_ADEMCO_USE_3 = 0x653, - ADEMCO_CONTACTID_SYSTEM_INACTIVITY = 0x654, - ADEMCO_CONTACTID_DOWNLOAD_ABORT = 0x900, - ADEMCO_CONTACTID_DOWNLOAD_START_END = 0x901, - ADEMCO_CONTACTID_DOWNLOAD_INTERRUPTED = 0x902, - ADEMCO_CONTACTID_AUTOCLOSE_WITH_BYPASS = 0x910, - ADEMCO_CONTACTID_BYPASS_CLOSING = 0x911, - ADEMCO_CONTACTID_32_HOUR_NO_READ_OF_EVENT_LOG = 0x999 -}; - -typedef struct ademco_contactid_sender_state_s ademco_contactid_sender_state_t; - -typedef struct ademco_contactid_receiver_state_s ademco_contactid_receiver_state_t; - -typedef struct -{ - int acct; - int mt; - int q; - int xyz; - int gg; - int ccc; -} ademco_contactid_report_t; - -typedef void (*ademco_contactid_report_func_t)(void *user_data, const ademco_contactid_report_t *report); - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(const char *) ademco_contactid_msg_qualifier_to_str(int q); - -SPAN_DECLARE(const char *) ademco_contactid_event_to_str(int xyz); - -SPAN_DECLARE(int) encode_msg(char buf[], const ademco_contactid_report_t *report); - -SPAN_DECLARE(int) decode_msg(ademco_contactid_report_t *report, const char buf[]); - -SPAN_DECLARE(int) ademco_contactid_receiver_log_msg(ademco_contactid_receiver_state_t *s, const ademco_contactid_report_t *report); - -SPAN_DECLARE(int) ademco_contactid_receiver_tx(ademco_contactid_receiver_state_t *s, int16_t amp[], int max_samples); - -SPAN_DECLARE(int) ademco_contactid_receiver_rx(ademco_contactid_receiver_state_t *s, const int16_t amp[], int samples); - -SPAN_DECLARE(int) ademco_contactid_receiver_fillin(ademco_contactid_receiver_state_t *s, int samples); - -SPAN_DECLARE(logging_state_t *) ademco_contactid_receiver_get_logging_state(ademco_contactid_receiver_state_t *s); - -SPAN_DECLARE(void) ademco_contactid_receiver_set_realtime_callback(ademco_contactid_receiver_state_t *s, - ademco_contactid_report_func_t callback, - void *user_data); - -SPAN_DECLARE(ademco_contactid_receiver_state_t *) ademco_contactid_receiver_init(ademco_contactid_receiver_state_t *s, - ademco_contactid_report_func_t callback, - void *user_data); - -SPAN_DECLARE(int) ademco_contactid_receiver_release(ademco_contactid_receiver_state_t *s); - -SPAN_DECLARE(int) ademco_contactid_receiver_free(ademco_contactid_receiver_state_t *s); - - - -SPAN_DECLARE(int) ademco_contactid_sender_tx(ademco_contactid_sender_state_t *s, int16_t amp[], int max_samples); - -SPAN_DECLARE(int) ademco_contactid_sender_rx(ademco_contactid_sender_state_t *s, const int16_t amp[], int samples); - -SPAN_DECLARE(int) ademco_contactid_sender_fillin(ademco_contactid_sender_state_t *s, int samples); - -SPAN_DECLARE(int) ademco_contactid_sender_put(ademco_contactid_sender_state_t *s, const ademco_contactid_report_t *report); - -SPAN_DECLARE(logging_state_t *) ademco_contactid_sender_get_logging_state(ademco_contactid_sender_state_t *s); - -SPAN_DECLARE(void) ademco_contactid_sender_set_realtime_callback(ademco_contactid_sender_state_t *s, - tone_report_func_t callback, - void *user_data); - -SPAN_DECLARE(ademco_contactid_sender_state_t *) ademco_contactid_sender_init(ademco_contactid_sender_state_t *s, - tone_report_func_t callback, - void *user_data); - -SPAN_DECLARE(int) ademco_contactid_sender_release(ademco_contactid_sender_state_t *s); - -SPAN_DECLARE(int) ademco_contactid_sender_free(ademco_contactid_sender_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/adsi.h b/libs/spandsp/src/spandsp/adsi.h deleted file mode 100644 index 751f57c03d..0000000000 --- a/libs/spandsp/src/spandsp/adsi.h +++ /dev/null @@ -1,526 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * adsi.h - Analogue display services interface and other call ID related handling. - * - * 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 */ - -#if !defined(_SPANDSP_ADSI_H_) -#define _SPANDSP_ADSI_H_ - -/*! \page adsi_page ADSI transmission and reception -\section adsi_page_sec_1 What does it do? -Although ADSI has a specific meaning in some places, the term is used here to indicate -any form of Analogue Display Service Interface, which includes caller ID, SMS, and others. - -The ADSI module provides for the transmission and reception of ADSI messages -in various formats. Currently, the supported formats are: - - - Bellcore/Telcordia GR-30 CORE CLASS (Custom Local Area Signaling Services) standard - (North America, Australia, China, Taiwan, and Hong Kong). - - - ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) FSK standard - (France, Germany, Norway, Italy, Spain, South Africa, Turkey, and the UK). - - - ETSI Caller-ID support for the UK, British Telecom SIN227 and SIN242. - - - ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard - variant 1 (Belgium, Brazil, Denmark, Finland, Iceland, India, Netherlands, Saudi Arabia, - Sweden and Uruguay). - - - ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard - variant 2 (Denmark and Holland). - - - ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard - variant 3. - - - ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard - variant 4. (Taiwan and Kuwait). - - - ETSI Caller-ID support in UK (British Telecom), British Telecomm SIN227, SIN242. - - - Nippon Telegraph & Telephone Corporation JCLIP (Japanese Calling Line Identity - Presentation) standard. - - - Telecommunications Authority of Singapore ACLIP (Analog Calling Line Identity - Presentation) standard. - - - TDD (Telecommunications Device for the Deaf). - -\section adsi_page_sec_2 How does it work? - -\section adsi_page_sec_2a The Bellcore CLASS specification -Most FSK based CLI formats are similar to the US CLASS one, which is as follows: - -The alert tone for CLI during a call is at least 100ms of silence, then -2130Hz + 2750Hz for 88ms to 110ms. When CLI is presented at ringing time, -this tone is not sent. In the US, CLI is usually sent between the first -two rings. This silence period is long in the US, so the message fits easily. -In other places, where the standard ring tone has much smaller silences, -a line voltage reversal is used to wake up a power saving receiver, then the -message is sent, then the phone begins to ring. - -The message is sent using a Bell 202 FSK modem. The data rate is 1200 bits -per second. The message protocol uses 8-bit data words (bytes), each bounded -by a start bit and a stop bit. - -Channel Carrier Message Message Data Checksum -Seizure Signal Type Length Word(s) Word -Signal Word Word - -\section adsi_page_sec_2a1 CHANNEL SEIZURE SIGNAL -The channel seizure is 30 continuous bytes of 55h (01010101), including -the start and stop bits (i.e. 300 bits of alternations in total). -This provides a detectable alternating function to the CPE (i.e. the -modem data pump). - -\section adsi_page_sec_2a2 CARRIER SIGNAL -The carrier signal consists of 180 bits of 1s. This may be reduced to 80 -bits of 1s for caller ID on call waiting. - -\section adsi_page_sec_2a3 MESSAGE TYPE WORD -Various message types are defined. The commonest ones for the US CLASS -standard are: - - - Type 0x04 (SDMF) - single data message. Simple caller ID (CND) - - Type 0x80 (MDMF) - multiple data message. A more flexible caller ID, - with extra information. - -Other messages support message waiting, for voice mail, and other display features. - -\section adsi_page_sec_2a4 MESSAGE LENGTH WORD -The message length word specifies the total number of data words -to follow. - -\section adsi_page_sec_2a5 DATA WORDS -The data words contain the actual message. - -\section adsi_page_sec_2a6 CHECKSUM WORD -The Checksum Word contains the twos complement of the modulo 256 -sum of the other words in the data message (i.e., message type, -message length, and data words). The receiving equipment may -calculate the modulo 256 sum of the received words and add this -sum to the received checksum word. A result of zero generally -indicates that the message was correctly received. Message -retransmission is not supported. The sumcheck word should be followed -by a minimum of two stop bits. - -\section adsi_page_sec_2b The ETSI CLIP specification -The ETSI CLIP specification uses similar messages to the Bellcore specification. -They are not, however, identical. First, ETSI use the V.23 modem standard, rather -than Bell 202. Second, different fields, and different message types are available. - -The wake up indication generally differs from the Bellcore specification, to -accomodate differences in European ring cadences. - -\section adsi_page_sec_2c The ETSI caller ID by DTMF specification -CLI by DTMF is usually sent in a very simple way. The exchange does not give -any prior warning (no reversal, or ring) to wake up the receiver. It just -sends a string of DTMF digits. Around the world several variants of this -basic scheme are used. - -One variant of the digit string is used in Belgium, Brazil, Denmark, Finland, Iceland, -India, Netherlands, Saudi Arabia, Sweden and Uruguay: - - - ADBC - -Each of these fields may be omitted. The following special information codes are defined - - - "00" indicates the calling party number is not available. - - "10" indicates that the presentation of the calling party number is restricted. - -A second variant of the digit string is one of the following: - - - A# - - D1# Number not available because the caller has restricted it. - - D2# Number not available because the call is international. - - D3# Number not available due to technical reasons. - -A third variant of the digit string is used in Taiwan and Kuwait: - - - DC - -A forth variant of the digit string is used in Denmark and Holland: - - - # - -There is no distinctive start marker in this format. - -\section adsi_page_sec_2d The Japanese specification from NTT - -The Japanese caller ID specification is considerably different from any of the others. It -uses V.23 modem signals, but the message structure is uniqeue. Also, the message is delivered -while off hook. This results in a sequence - - - The phone line rings - - CPE answers and waits for the caller ID message - - CPE hangs up on receipt of the caller ID message - - The phone line rings a second time - - The CPE answers a second time, connecting the called party with the caller. - -Timeouts are, obviously, required to ensure this system behaves well when the caller ID message -or the second ring are missing. -*/ - -enum -{ - ADSI_STANDARD_NONE = 0, - ADSI_STANDARD_CLASS = 1, - ADSI_STANDARD_CLIP = 2, - ADSI_STANDARD_ACLIP = 3, - ADSI_STANDARD_JCLIP = 4, - ADSI_STANDARD_CLIP_DTMF = 5, - ADSI_STANDARD_TDD = 6 -}; - -/* In some of the messages code characters are used, as follows: - 'C' for public callbox - 'L' for long distance - 'O' for overseas - 'P' for private - 'S' for service conflict - - Taiwan and Kuwait change this pattern to: - 'C' for coin/public callbox - 'I' for international call - 'O' for out of area call - 'P' for private - */ - -/*! Definitions for CLASS (Custom Local Area Signaling Services) */ -enum -{ - /*! Single data message caller ID */ - CLASS_SDMF_CALLERID = 0x04, - /*! Multiple data message caller ID */ - CLASS_MDMF_CALLERID = 0x80, - /*! Single data message message waiting */ - CLASS_SDMF_MSG_WAITING = 0x06, - /*! Multiple data message message waiting */ - CLASS_MDMF_MSG_WAITING = 0x82 -}; - -/*! CLASS MDMF message IDs */ -enum -{ - /*! Date and time (MMDDHHMM) */ - MCLASS_DATETIME = 0x01, - /*! Caller number */ - MCLASS_CALLER_NUMBER = 0x02, - /*! Dialed number */ - MCLASS_DIALED_NUMBER = 0x03, - /*! Caller number absent: 'O' or 'P' */ - MCLASS_ABSENCE1 = 0x04, - /*! Call forward: universal ('0'), on busy ('1'), or on unanswered ('2') */ - MCLASS_REDIRECT = 0x05, - /*! Long distance: 'L' */ - MCLASS_QUALIFIER = 0x06, - /*! Caller's name */ - MCLASS_CALLER_NAME = 0x07, - /*! Caller's name absent: 'O' or 'P' */ - MCLASS_ABSENCE2 = 0x08, - /*! Alternate route */ - MCLASS_ALT_ROUTE = 0x09 -}; - -/*! CLASS MDMF message waiting message IDs */ -/*! Message waiting/not waiting */ -#define MCLASS_VISUAL_INDICATOR 0x0B - -/*! Definitions for CLIP (Calling Line Identity Presentation) (from ETS 300 659-1) */ -enum -{ - /*! Multiple data message caller ID */ - CLIP_MDMF_CALLERID = 0x80, - /*! Multiple data message message waiting */ - CLIP_MDMF_MSG_WAITING = 0x82, - /*! Multiple data message charge information */ - CLIP_MDMF_CHARGE_INFO = 0x86, - /*! Multiple data message SMS */ - CLIP_MDMF_SMS = 0x89 -}; - -/*! CLIP message IDs (from ETS 300 659-1) */ -enum -{ - /*! Date and time (MMDDHHMM) */ - CLIP_DATETIME = 0x01, - /*! Caller number (AKA calling line identity) */ - CLIP_CALLER_NUMBER = 0x02, - /*! Dialed number (AKA called line identity) */ - CLIP_DIALED_NUMBER = 0x03, - /*! Caller number absent: 'O' or 'P' (AKA reason for absence of calling line identity) */ - CLIP_ABSENCE1 = 0x04, - /*! Caller's name (AKA calling party name) */ - CLIP_CALLER_NAME = 0x07, - /*! Caller's name absent: 'O' or 'P' (AKA reason for absence of calling party name) */ - CLIP_ABSENCE2 = 0x08, - /*! Visual indicator */ - CLIP_VISUAL_INDICATOR = 0x0B, - /*! Message ID */ - CLIP_MESSAGE_ID = 0x0D, - /*! Complementary calling line identity */ - CLIP_COMPLEMENTARY_CALLER_NUMBER = 0x10, - /*! Call type - voice call (1), ring-back-when-free call (2), calling name delivery (3) or msg waiting call(0x81) */ - CLIP_CALLTYPE = 0x11, - /*! Number of messages */ - CLIP_NUM_MSG = 0x13, - /*! Type of forwarded call */ - CLIP_TYPE_OF_FORWARDED_CALL = 0x15, - /*! Type of calling user */ - CLIP_TYPE_OF_CALLING_USER = 0x16, - /*! Redirecting number */ - CLIP_REDIR_NUMBER = 0x1A, - /*! Charge */ - CLIP_CHARGE = 0x20, - /*! Duration of the call */ - CLIP_DURATION = 0x23, - /*! Additional charge */ - CLIP_ADD_CHARGE = 0x21, - /*! Display information */ - CLIP_DISPLAY_INFO = 0x50, - /*! Service information */ - CLIP_SERVICE_INFO = 0x55 -}; - -/*! Definitions for A-CLIP (Analog Calling Line Identity Presentation) */ -enum -{ - /*! Single data message caller ID frame */ - ACLIP_SDMF_CALLERID = 0x04, - /*! Multiple data message caller ID frame */ - ACLIP_MDMF_CALLERID = 0x80 -}; - -/*! A-CLIP MDM message IDs */ -enum -{ - /*! Date and time (MMDDHHMM) */ - ACLIP_DATETIME = 0x01, - /*! Caller number */ - ACLIP_CALLER_NUMBER = 0x02, - /*! Dialed number */ - ACLIP_DIALED_NUMBER = 0x03, - /*! Caller number absent: 'O' or 'P' */ - ACLIP_NUMBER_ABSENCE = 0x04, - /*! Call forward: universal, on busy, or on unanswered */ - ACLIP_REDIRECT = 0x05, - /*! Long distance call: 'L' */ - ACLIP_QUALIFIER = 0x06, - /*! Caller's name */ - ACLIP_CALLER_NAME = 0x07, - /*! Caller's name absent: 'O' or 'P' */ - ACLIP_NAME_ABSENCE = 0x08 -}; - -/*! Definitions for J-CLIP (Japan Calling Line Identity Presentation) */ -/*! Multiple data message caller ID frame */ -#define JCLIP_MDMF_CALLERID 0x40 - -/*! J-CLIP MDM message IDs */ -enum -{ - /*! Caller number */ - JCLIP_CALLER_NUMBER = 0x02, - /*! Caller number data extension signal */ - JCLIP_CALLER_NUM_DES = 0x21, - /*! Dialed number */ - JCLIP_DIALED_NUMBER = 0x09, - /*! Dialed number data extension signal */ - JCLIP_DIALED_NUM_DES = 0x22, - /*! Caller number absent: 'C', 'O', 'P' or 'S' */ - JCLIP_ABSENCE = 0x04 -}; - -/* Definitions for CLIP-DTMF and its variants */ - -/*! Caller number is '#' terminated DTMF. */ -#define CLIP_DTMF_HASH_TERMINATED '#' -/*! Caller number is 'C' terminated DTMF. */ -#define CLIP_DTMF_C_TERMINATED 'C' - -/*! Caller number */ -#define CLIP_DTMF_HASH_CALLER_NUMBER 'A' -/*! Caller number absent: private (1), overseas (2) or not available (3) */ -#define CLIP_DTMF_HASH_ABSENCE 'D' -/*! Caller ID field with no explicit field type */ -#define CLIP_DTMF_HASH_UNSPECIFIED 0 - -/*! Caller number */ -#define CLIP_DTMF_C_CALLER_NUMBER 'A' -/*! Diverting number */ -#define CLIP_DTMF_C_REDIRECT_NUMBER 'D' -/*! Caller number absent: private/restricted (00) or not available (10) */ -#define CLIP_DTMF_C_ABSENCE 'B' - -/*! - ADSI transmitter descriptor. This contains all the state information for an ADSI - (caller ID, CLASS, CLIP, ACLIP) transmit channel. - */ -typedef struct adsi_tx_state_s adsi_tx_state_t; - -/*! - ADSI receiver descriptor. This contains all the state information for an ADSI - (caller ID, CLASS, CLIP, ACLIP, JCLIP) receive channel. - */ -typedef struct adsi_rx_state_s adsi_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Get the logging context associated with an ADSI receive context. - \brief Get the logging context associated with an ADSI receive context. - \param s The ADSI receive context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) adsi_rx_get_logging_state(adsi_rx_state_t *s); - -/*! \brief Initialise an ADSI receive context. - \param s The ADSI receive context. - \param standard The code for the ADSI standard to be used. - \param put_msg A callback routine called to deliver the received messages - to the application. - \param user_data An opaque pointer for the callback routine. - \return A pointer to the initialised context, or NULL if there was a problem. -*/ -SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s, - int standard, - put_msg_func_t put_msg, - void *user_data); - -/*! \brief Release an ADSI receive context. - \param s The ADSI receive context. - \return 0 for OK. -*/ -SPAN_DECLARE(int) adsi_rx_release(adsi_rx_state_t *s); - -/*! \brief Free the resources of an ADSI receive context. - \param s The ADSI receive context. - \return 0 for OK. -*/ -SPAN_DECLARE(int) adsi_rx_free(adsi_rx_state_t *s); - -/*! \brief Receive a chunk of ADSI audio. - \param s The ADSI receive context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) adsi_rx(adsi_rx_state_t *s, const int16_t amp[], int len); - -/*! Get the logging context associated with an ADSI transmit context. - \brief Get the logging context associated with an ADSI transmit context. - \param s The ADSI transmit context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) adsi_tx_get_logging_state(adsi_tx_state_t *s); - -/*! \brief Initialise an ADSI transmit context. - \param s The ADSI transmit context. - \param standard The code for the ADSI standard to be used. - \return A pointer to the initialised context, or NULL if there was a problem. -*/ -SPAN_DECLARE(adsi_tx_state_t *) adsi_tx_init(adsi_tx_state_t *s, int standard); - -/*! \brief Release an ADSI transmit context. - \param s The ADSI transmit context. - \return 0 for OK. -*/ -SPAN_DECLARE(int) adsi_tx_release(adsi_tx_state_t *s); - -/*! \brief Free the resources of an ADSI transmit context. - \param s The ADSI transmit context. - \return 0 for OK. -*/ -SPAN_DECLARE(int) adsi_tx_free(adsi_tx_state_t *s); - -/*! \brief Adjust the preamble associated with an ADSI transmit context. - \param s The ADSI transmit context. - \param preamble_len The number of bits of preamble. - \param preamble_ones_len The number of bits of continuous one before a message. - \param postamble_ones_len The number of bits of continuous one after a message. - \param stop_bits The number of stop bits per character. -*/ -SPAN_DECLARE(void) adsi_tx_set_preamble(adsi_tx_state_t *s, - int preamble_len, - int preamble_ones_len, - int postamble_ones_len, - int stop_bits); - -/*! \brief Generate a block of ADSI audio samples. - \param s The ADSI transmit context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) adsi_tx(adsi_tx_state_t *s, int16_t amp[], int max_len); - -/*! \brief Request generation of an ADSI alert tone. - \param s The ADSI transmit context. -*/ -SPAN_DECLARE(void) adsi_tx_send_alert_tone(adsi_tx_state_t *s); - -/*! \brief Put a message into the input buffer of an ADSI transmit context. - \param s The ADSI transmit context. - \param msg The message. - \param len The length of the message. - \return The length actually added. If a message is already in progress - in the transmitter, this function will return zero, as it will - not successfully add the message to the buffer. If the message is - invalid (e.g. it is too long), this function will return -1. -*/ -SPAN_DECLARE(int) adsi_tx_put_message(adsi_tx_state_t *s, const uint8_t *msg, int len); - -/*! \brief Get a field from an ADSI message. - \param s The ADSI receive context. - \param msg The message buffer. - \param msg_len The length of the message. - \param pos Current position within the message. Set to -1 when starting a message. - \param field_type The type code for the field. - \param field_body Pointer to the body of the field. - \param field_len The length of the field, or -1 for no more fields, or -2 for message structure corrupt. -*/ -SPAN_DECLARE(int) adsi_next_field(adsi_rx_state_t *s, const uint8_t *msg, int msg_len, int pos, uint8_t *field_type, uint8_t const **field_body, int *field_len); - -/*! \brief Insert the header or a field into an ADSI message. - \param s The ADSI transmit context. - \param msg The message buffer. - \param len The current length of the message. - \param field_type The type code for the new field. - \param field_body Pointer to the body of the new field. - \param field_len The length of the new field. -*/ -SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint8_t field_type, uint8_t const *field_body, int field_len); - -/*! \brief Return a short name for an ADSI standard - \param standard The code for the standard. - \return A pointer to the name. -*/ -SPAN_DECLARE(const char *) adsi_standard_to_str(int standard); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/alloc.h b/libs/spandsp/src/spandsp/alloc.h deleted file mode 100644 index 3bb691b05a..0000000000 --- a/libs/spandsp/src/spandsp/alloc.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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/arctan2.h b/libs/spandsp/src/spandsp/arctan2.h deleted file mode 100644 index aefac60d67..0000000000 --- a/libs/spandsp/src/spandsp/arctan2.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * arctan2.h - A quick rough approximate arc tan - * - * 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 */ - -#if !defined(_SPANDSP_ARCTAN2_H_) -#define _SPANDSP_ARCTAN2_H_ - -/*! \page arctan2_page Fast approximate four quadrant arc-tangent -\section arctan2_page_sec_1 What does it do? -This module provides a fast approximate 4-quadrant arc tangent function, -based on something at dspguru.com. The worst case error is about 4.07 degrees. -This is fine for many "where am I" type evaluations in comms. work. - -\section arctan2_page_sec_2 How does it work? -???. -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* This returns its answer as a signed 32 bit integer phase value. */ -static __inline__ int32_t arctan2(float y, float x) -{ - float abs_y; - float angle; - - if (y == 0.0f) - { - if (x < 0.0f) - return 0x80000000; - return 0x00000000; - } - if (x == 0.0f) - { - if (y < 0.0f) - return 0xc0000000; - return 0x40000000; - } - - abs_y = fabsf(y); - - /* If we are in quadrant II or III, flip things around */ - if (x < 0.0f) - angle = 3.0f - (x + abs_y)/(abs_y - x); - else - angle = 1.0f - (x - abs_y)/(abs_y + x); - angle *= 536870912.0f; - - /* If we are in quadrant III or IV, negate to return an - answer in the range +-pi */ - if (y < 0.0f) - angle = -angle; - return (int32_t) angle; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -/* This returns its answer in radians, in the range +-pi. */ -static __inline__ float arctan2f(float y, float x) -{ - float angle; - float fx; - float fy; - - if (y == 0.0f) - { - if (x < 0.0f) - return 3.1415926f; - return 0.0f; - } - if (x == 0.0f) - { - if (y < 0.0f) - return 3.1415926f*1.5f; - return 3.1415926f*0.5f; - } - fx = fabsf(x); - fy = fabsf(y); - /* Deal with the octants */ - /* N.B. 0.28125 == (1/4 + 1/32) */ - if (fy > fx) - angle = 3.1415926f/2.0f - fx*fy/(y*y + 0.28125f*x*x); - else - angle = fy*fx/(x*x + 0.28125f*y*y); - - /* Deal with the quadrants, to bring the final answer to the range +-pi */ - if (x < 0.0f) - angle = 3.1415926f - angle; - if (y < 0.0f) - angle = -angle; - return angle; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/async.h b/libs/spandsp/src/spandsp/async.h deleted file mode 100644 index 290b3acc1d..0000000000 --- a/libs/spandsp/src/spandsp/async.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * async.h - Asynchronous serial bit stream encoding and decoding - * - * 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 */ - -/*! \page async_page Asynchronous bit stream processing -\section async_page_sec_1 What does it do? -The asynchronous serial bit stream processing module provides -generation and decoding facilities for most asynchronous data -formats. It supports: - - 1 or 2 stop bits. - - Odd, even or no parity. - - 5, 6, 7, or 8 bit characters. - - V.14 rate adaption. -The input to this module is a bit stream. This means any symbol synchronisation -and decoding must occur before data is fed to this module. - -\section async_page_sec_2 The transmitter -???. - -\section async_page_sec_3 The receiver -???. -*/ - -#if !defined(_SPANDSP_ASYNC_H_) -#define _SPANDSP_ASYNC_H_ - -/*! Special "bit" values for the bitstream put and get functions, and the signal status functions. */ -enum -{ - /*! \brief The carrier signal has dropped. */ - SIG_STATUS_CARRIER_DOWN = -1, - /*! \brief The carrier signal is up. This merely indicates that carrier - energy has been seen. It is not an indication that the carrier is either - valid, or of the expected type. */ - SIG_STATUS_CARRIER_UP = -2, - /*! \brief The modem is training. This is an early indication that the - signal seems to be of the right type. This may be needed in time critical - applications, like T.38, to forward an early indication of what is happening - on the wire. */ - SIG_STATUS_TRAINING_IN_PROGRESS = -3, - /*! \brief The modem has trained, and is ready for data exchange. */ - SIG_STATUS_TRAINING_SUCCEEDED = -4, - /*! \brief The modem has failed to train. */ - SIG_STATUS_TRAINING_FAILED = -5, - /*! \brief Packet framing (e.g. HDLC framing) is OK. */ - SIG_STATUS_FRAMING_OK = -6, - /*! \brief The data stream has ended. */ - SIG_STATUS_END_OF_DATA = -7, - /*! \brief An abort signal (e.g. an HDLC abort) has been received. */ - SIG_STATUS_ABORT = -8, - /*! \brief A break signal (e.g. an async break) has been received. */ - SIG_STATUS_BREAK = -9, - /*! \brief A modem has completed its task, and shut down. */ - SIG_STATUS_SHUTDOWN_COMPLETE = -10, - /*! \brief Regular octet report for things like HDLC to the MTP standards. */ - SIG_STATUS_OCTET_REPORT = -11, - /*! \brief Notification that a modem has detected signal quality degradation. */ - SIG_STATUS_POOR_SIGNAL_QUALITY = -12, - /*! \brief Notification that a modem retrain has occurred. */ - SIG_STATUS_MODEM_RETRAIN_OCCURRED = -13, - /*! \brief The link protocol (e.g. V.42) has connected. */ - SIG_STATUS_LINK_CONNECTED = -14, - /*! \brief The link protocol (e.g. V.42) has disconnected. */ - SIG_STATUS_LINK_DISCONNECTED = -15, - /*! \brief An error has occurred in the link protocol (e.g. V.42). */ - SIG_STATUS_LINK_ERROR = -16, - /*! \brief Keep the link in an idle state, as there is nothing to send. */ - SIG_STATUS_LINK_IDLE = -17 -}; - -/*! Message put function for data pumps */ -typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len); - -/*! Message get function for data pumps */ -typedef int (*get_msg_func_t)(void *user_data, uint8_t *msg, int max_len); - -/*! Byte put function for data pumps */ -typedef void (*put_byte_func_t)(void *user_data, int byte); - -/*! Byte get function for data pumps */ -typedef int (*get_byte_func_t)(void *user_data); - -/*! Bit put function for data pumps */ -typedef void (*put_bit_func_t)(void *user_data, int bit); - -/*! Bit get function for data pumps */ -typedef int (*get_bit_func_t)(void *user_data); - -/*! Status change callback function for data pumps */ -typedef void (*modem_status_func_t)(void *user_data, int status); - -/*! - Asynchronous data transmit descriptor. This defines the state of a single - working instance of a byte to asynchronous serial converter, for use - in FSK modems. -*/ -typedef struct async_tx_state_s async_tx_state_t; - -/*! - Asynchronous data receive descriptor. This defines the state of a single - working instance of an asynchronous serial to byte converter, for use - in FSK modems. -*/ -typedef struct async_rx_state_s async_rx_state_t; - -enum -{ - /*! No parity bit should be used */ - ASYNC_PARITY_NONE = 0, - /*! An even parity bit will exist, after the data bits */ - ASYNC_PARITY_EVEN, - /*! An odd parity bit will exist, after the data bits */ - ASYNC_PARITY_ODD -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Convert a signal status to a short text description. - \brief Convert a signal status to a short text description. - \param status The modem signal status. - \return A pointer to the description. */ -SPAN_DECLARE(const char *) signal_status_to_str(int status); - -/*! Accept a bit from a received serial bit stream - \brief Accept a bit from a received serial bit stream - \param user_data An opaque point which must point to a receiver context. - \param bit The new bit. Some special values are supported for this field. - - SIG_STATUS_CARRIER_UP - - SIG_STATUS_CARRIER_DOWN - - SIG_STATUS_TRAINING_SUCCEEDED - - SIG_STATUS_TRAINING_FAILED - - SIG_STATUS_END_OF_DATA */ -SPAN_DECLARE(void) async_rx_put_bit(void *user_data, int bit); - -/*! Initialise an asynchronous data receiver context. - \brief Initialise an asynchronous data receiver context. - \param s The receiver context. - \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 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. */ -SPAN_DECLARE(async_rx_state_t *) async_rx_init(async_rx_state_t *s, - int data_bits, - int parity_bits, - int stop_bits, - bool use_v14, - put_byte_func_t put_byte, - void *user_data); - -SPAN_DECLARE(int) async_rx_release(async_rx_state_t *s); - -SPAN_DECLARE(int) async_rx_free(async_rx_state_t *s); - -/*! Set a minimum number of bit times of stop bit state before character transmission commences. - \brief Set a minimum number of bit times of stop bit state before character transmission commences. - \param user_data An opaque point which must point to a transmitter context. - \param the number of bits. */ -SPAN_DECLARE(void) async_tx_presend_bits(async_tx_state_t *s, int bits); - -/*! Get the next bit of a transmitted serial bit stream. - \brief Get the next bit of a transmitted serial bit stream. - \param user_data An opaque point which must point to a transmitter context. - \return the next bit, or PUTBIT_END_OF_DATA to indicate the data stream has ended. */ -SPAN_DECLARE(int) async_tx_get_bit(void *user_data); - -/*! Initialise an asynchronous data transmit context. - \brief Initialise an asynchronous data transmit context. - \param s The transmitter context. - \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 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. */ -SPAN_DECLARE(async_tx_state_t *) async_tx_init(async_tx_state_t *s, - int data_bits, - int parity_bits, - int stop_bits, - bool use_v14, - get_byte_func_t get_byte, - void *user_data); - -SPAN_DECLARE(int) async_tx_release(async_tx_state_t *s); - -SPAN_DECLARE(int) async_tx_free(async_tx_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/at_interpreter.h b/libs/spandsp/src/spandsp/at_interpreter.h deleted file mode 100644 index f645f70892..0000000000 --- a/libs/spandsp/src/spandsp/at_interpreter.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * at_interpreter.h - AT command interpreter to V.251, V.252, V.253, T.31 and the 3GPP specs. - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 2005, 2006 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_AT_INTERPRETER_H_) -#define _SPANDSP_AT_INTERPRETER_H_ - -/*! \page at_page AT command interpreter -\section at_page_sec_1 What does it do? -The AT interpreter module implements V.251, V.252, V.253, T.31 and various 3GPP -modem control commands. - -\section at_page_sec_2 How does it work? -*/ - -typedef struct at_state_s at_state_t; - -typedef int (*at_modem_control_handler_t)(void *user_data, int op, const char *num); -typedef int (*at_tx_handler_t)(void *user_data, const uint8_t *buf, size_t len); -typedef int (*at_class1_handler_t)(void *user_data, int direction, int operation, int val); - -enum at_rx_mode_e -{ - AT_MODE_ONHOOK_COMMAND, - AT_MODE_OFFHOOK_COMMAND, - AT_MODE_CONNECTED, - AT_MODE_DELIVERY, - AT_MODE_HDLC, - AT_MODE_STUFFED -}; - -enum at_call_event_e -{ - AT_CALL_EVENT_ALERTING = 1, - AT_CALL_EVENT_CONNECTED, - AT_CALL_EVENT_ANSWERED, - AT_CALL_EVENT_BUSY, - AT_CALL_EVENT_NO_DIALTONE, - AT_CALL_EVENT_NO_ANSWER, - AT_CALL_EVENT_HANGUP -}; - -enum at_modem_control_operation_e -{ - /*! Start an outgoing call. */ - AT_MODEM_CONTROL_CALL, - /*! Answer an incoming call. */ - AT_MODEM_CONTROL_ANSWER, - /*! Hangup a call. */ - AT_MODEM_CONTROL_HANGUP, - /*! Take the line off hook. */ - AT_MODEM_CONTROL_OFFHOOK, - /*! Put the line on hook. */ - AT_MODEM_CONTROL_ONHOOK, - /*! Control V.24 Circuit 108, "data terminal ready". */ - AT_MODEM_CONTROL_DTR, - /*! Control V.24 Circuit 105, "request to send". */ - AT_MODEM_CONTROL_RTS, - /*! Control V.24 Circuit 106, "clear to send". */ - AT_MODEM_CONTROL_CTS, - /*! Control V.24 Circuit 109, "receive line signal detector" (i.e. carrier detect). */ - AT_MODEM_CONTROL_CAR, - /*! Control V.24 Circuit 125, "ring indicator". */ - AT_MODEM_CONTROL_RNG, - /*! Control V.24 Circuit 107, "data set ready". */ - AT_MODEM_CONTROL_DSR, - /*! Set the caller ID for outgoing calls. */ - AT_MODEM_CONTROL_SETID, - /* The remainder of the control functions should not get past the modem, to the - application. */ - AT_MODEM_CONTROL_RESTART, - AT_MODEM_CONTROL_DTE_TIMEOUT -}; - -enum -{ - AT_RESPONSE_CODE_OK = 0, - AT_RESPONSE_CODE_CONNECT, - AT_RESPONSE_CODE_RING, - AT_RESPONSE_CODE_NO_CARRIER, - AT_RESPONSE_CODE_ERROR, - AT_RESPONSE_CODE_XXX, - AT_RESPONSE_CODE_NO_DIALTONE, - AT_RESPONSE_CODE_BUSY, - AT_RESPONSE_CODE_NO_ANSWER, - AT_RESPONSE_CODE_FCERROR, - AT_RESPONSE_CODE_FRH3 -}; - -/*! - AT profile. -*/ -typedef struct -{ - /*! 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 */ - bool pulse_dial; - /*! ??? */ - int double_escape; - /*! ??? */ - int adaptive_receive; - /*! The state of all possible S registers */ - uint8_t s_regs[100]; -} at_profile_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(const char *) at_call_state_to_str(int state); - -SPAN_DECLARE(const char *) at_modem_control_to_str(int state); - -SPAN_DECLARE(void) at_set_at_rx_mode(at_state_t *s, int new_mode); - -SPAN_DECLARE(void) at_put_response(at_state_t *s, const char *t); - -SPAN_DECLARE(void) at_put_numeric_response(at_state_t *s, int val); - -SPAN_DECLARE(void) at_put_response_code(at_state_t *s, int code); - -SPAN_DECLARE(void) at_reset_call_info(at_state_t *s); - -/*! Set the call information for an AT interpreter. - \brief Set the call information for an AT interpreter. - \param s The AT interpreter context. - \param id . - \param value . */ -SPAN_DECLARE(void) at_set_call_info(at_state_t *s, char const *id, char const *value); - -SPAN_DECLARE(void) at_display_call_info(at_state_t *s); - -SPAN_DECLARE(int) at_modem_control(at_state_t *s, int op, const char *num); - -SPAN_DECLARE(void) at_call_event(at_state_t *s, int event); - -SPAN_DECLARE(void) at_interpreter(at_state_t *s, const char *cmd, int len); - -SPAN_DECLARE(void) at_set_class1_handler(at_state_t *s, at_class1_handler_t handler, void *user_data); - -/*! Get the logging context associated with an AT interpreter context. - \brief Get the logging context associated with an AT interpreter context. - \param s The AT context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) at_get_logging_state(at_state_t *s); - -SPAN_DECLARE(void) at_set_modem_control_handler(at_state_t *s, - at_modem_control_handler_t modem_control_handler, - void *modem_control_user_data); - -SPAN_DECLARE(void) at_set_at_tx_handler(at_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data); - -/*! Initialise an AT interpreter context. - \brief Initialise an AT interpreter context. - \param s The AT context. - \param at_tx_handler x. - \param at_tx_user_data x. - \param modem_control_handler x. - \param modem_control_user_data x. - \return A pointer to the AT context, or NULL if there was a problem. */ -SPAN_DECLARE(at_state_t *) at_init(at_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data, - at_modem_control_handler_t modem_control_handler, - void *modem_control_user_data); - -/*! Release an AT interpreter context. - \brief Release an AT interpreter context. - \param s The AT context. - \return 0 for OK */ -SPAN_DECLARE(int) at_release(at_state_t *s); - -/*! Free an AT interpreter context. - \brief Free an AT interpreter context. - \param s The AT context. - \return 0 for OK */ -SPAN_DECLARE(int) at_free(at_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/awgn.h b/libs/spandsp/src/spandsp/awgn.h deleted file mode 100644 index e61ffc42db..0000000000 --- a/libs/spandsp/src/spandsp/awgn.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * awgn.h - An additive Gaussian white noise generator - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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 */ - -/* This code is based on some demonstration code in a research - paper somewhere. I can't track down where I got the original from, - so that due recognition can be given. The original had no explicit - copyright notice, and I hope nobody objects to its use here. - - Having a reasonable Gaussian noise generator is pretty important for - telephony testing (in fact, pretty much any DSP testing), and this - one seems to have served me OK. Since the generation of Gaussian - noise is only for test purposes, and not a core system component, - I don't intend to worry excessively about copyright issues, unless - someone worries me. - - The non-core nature of this code also explains why it is unlikely - to ever be optimised. */ - -#if !defined(_SPANDSP_AWGN_H_) -#define _SPANDSP_AWGN_H_ - -/*! \page awgn_page Additive white gaussian noise (AWGN) generation - -\section awgn_page_sec_1 What does it do? -Adding noise is not the most useful thing in most DSP applications, but it is -awfully useful for test suites. - -\section awgn_page_sec_2 How does it work? - -This code is based on some demonstration code in a research paper somewhere. I -can't track down where I got the original from, so that due recognition can be -given. The original had no explicit copyright notice, and I hope nobody objects -to its use here. - -Having a reasonable Gaussian noise generator is pretty important for telephony -testing (in fact, pretty much any DSP testing), and this one seems to have -served me OK. Since the generation of Gaussian noise is only for test purposes, -and not a core system component, I don't intend to worry excessively about -copyright issues, unless someone worries me. - -The non-core nature of this code also explains why it is unlikely to ever be -optimised. -*/ - -/*! - AWGN generator descriptor. This contains all the state information for an AWGN generator. - */ -typedef struct awgn_state_s awgn_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(awgn_state_t *) awgn_init_dbm0(awgn_state_t *s, int idum, float level); - -SPAN_DECLARE(awgn_state_t *) awgn_init_dbov(awgn_state_t *s, int idum, float level); - -SPAN_DECLARE(int) awgn_release(awgn_state_t *s); - -SPAN_DECLARE(int) awgn_free(awgn_state_t *s); - -SPAN_DECLARE(int16_t) awgn(awgn_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/bell_r2_mf.h b/libs/spandsp/src/spandsp/bell_r2_mf.h deleted file mode 100644 index 2d40848a34..0000000000 --- a/libs/spandsp/src/spandsp/bell_r2_mf.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bell_r2_mf.h - Bell MF and MFC/R2 tone generation and detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_BELL_R2_MF_H_) -#define _SPANDSP_BELL_R2_MF_H_ - -/*! \page mfc_r2_tone_generation_page MFC/R2 tone generation -\section mfc_r2_tone_generation_page_sec_1 What does it do? -The MFC/R2 tone generation module provides for the generation of the -repertoire of 15 dual tones needs for the digital MFC/R2 signalling protocol. - -\section mfc_r2_tone_generation_page_sec_2 How does it work? -*/ - -/*! \page bell_mf_tone_generation_page Bell MF tone generation -\section bell_mf_tone_generation_page_sec_1 What does it do? -The Bell MF tone generation module provides for the generation of the -repertoire of 15 dual tones needs for various Bell MF signalling protocols. - -\section bell_mf_tone_generation_page_sec_2 How does it work? -Basic Bell MF tone generation specs: - - Tone on time = KP: 100+-7ms. All other signals: 68+-7ms - - Tone off time (between digits) = 68+-7ms - - Frequency tolerance +- 1.5% - - Signal level -7+-1dBm per frequency -*/ - -/*! \page mfc_r2_tone_rx_page MFC/R2 tone receiver - -\section mfc_r2_tone_rx_page_sec_1 What does it do? -The MFC/R2 tone receiver module provides for the detection of the -repertoire of 15 dual tones needs for the digital MFC/R2 signalling protocol. -It is compliant with ITU-T Q.441D. - -\section mfc_r2_tone_rx_page_sec_2 How does it work? -Basic MFC/R2 tone detection specs: - - Receiver response range: -5dBm to -35dBm - - Difference in level for a pair of frequencies - - Adjacent tones: <5dB - - Non-adjacent tones: <7dB - - Receiver not to detect a signal of 2 frequencies of level -5dB and - duration <7ms. - - Receiver not to recognise a signal of 2 frequencies having a difference - in level >=20dB. - - Max received signal frequency error: +-10Hz - - The sum of the operate and release times of a 2 frequency signal not to - exceed 80ms (there are no individual specs for the operate and release - times). - - Receiver not to release for signal interruptions <=7ms. - - System malfunction due to signal interruptions >7ms (typically 20ms) is - prevented by further logic elements. -*/ - -/*! \page bell_mf_tone_rx_page Bell MF tone receiver - -\section bell_mf_tone_rx_page_sec_1 What does it do? -The Bell MF tone receiver module provides for the detection of the -repertoire of 15 dual tones needs for various Bell MF signalling protocols. -It is compliant with ITU-T Q.320, ITU-T Q.322, ITU-T Q.323B. - -\section bell_mf_tone_rx_page_sec_2 How does it work? -Basic Bell MF tone detection specs: - - Frequency tolerance +- 1.5% +-10Hz - - Signal level -14dBm to 0dBm - - Perform a "two and only two tones present" test. - - Twist <= 6dB accepted - - Receiver sensitive to signals above -22dBm per frequency - - Test for a minimum of 55ms if KP, or 30ms of other signals. - - Signals to be recognised if the two tones arrive within 8ms of each other. - - Invalid signals result in the return of the re-order tone. - -Note: Above -3dBm the signal starts to clip. We can detect with a little clipping, - but not up to 0dBm, which the above spec seems to require. There isn't a lot - we can do about that. Is the spec. incorrectly worded about the dBm0 reference - point, or have I misunderstood it? -*/ - -/*! The maximum number of Bell MF digits we can buffer. */ -#define MAX_BELL_MF_DIGITS 128 - -/*! - Bell MF generator state descriptor. This defines the state of a single - working instance of a Bell MF generator. -*/ -typedef struct bell_mf_tx_state_s bell_mf_tx_state_t; - -/*! - Bell MF digit detector descriptor. -*/ -typedef struct bell_mf_rx_state_s bell_mf_rx_state_t; - -/*! - MFC/R2 tone detector descriptor. -*/ -typedef struct r2_mf_tx_state_s r2_mf_tx_state_t; - -/*! - MFC/R2 tone detector descriptor. -*/ -typedef struct r2_mf_rx_state_s r2_mf_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Generate a buffer of Bell MF tones. - \param s The Bell MF generator context. - \param amp The buffer for the generated signal. - \param max_samples The required number of generated samples. - \return The number of samples actually generated. This may be less than - max_samples if the input buffer empties. */ -SPAN_DECLARE(int) bell_mf_tx(bell_mf_tx_state_t *s, int16_t amp[], int max_samples); - -/*! \brief Put a string of digits in a Bell MF generator's input buffer. - \param s The Bell MF generator context. - \param digits The string of digits to be added. - \param len The length of the string of digits. If negative, the string is - assumed to be a NULL terminated string. - \return The number of digits actually added. This may be less than the - length of the digit string, if the buffer fills up. */ -SPAN_DECLARE(int) bell_mf_tx_put(bell_mf_tx_state_t *s, const char *digits, int len); - -/*! \brief Initialise a Bell MF generator context. - \param s The Bell MF generator context. - \return A pointer to the Bell MF generator context.*/ -SPAN_DECLARE(bell_mf_tx_state_t *) bell_mf_tx_init(bell_mf_tx_state_t *s); - -/*! \brief Release a Bell MF generator context. - \param s The Bell MF generator context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) bell_mf_tx_release(bell_mf_tx_state_t *s); - -/*! \brief Free a Bell MF generator context. - \param s The Bell MF generator context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) bell_mf_tx_free(bell_mf_tx_state_t *s); - -/*! \brief Generate a block of R2 MF tones. - \param s The R2 MF generator context. - \param amp The buffer for the generated signal. - \param samples The required number of generated samples. - \return The number of samples actually generated. */ -SPAN_DECLARE(int) r2_mf_tx(r2_mf_tx_state_t *s, int16_t amp[], int samples); - -/*! \brief Generate a block of R2 MF tones. - \param s The R2 MF generator context. - \param digit The digit to be generated. - \return 0 for OK, or -1 for a bad request. */ -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 - 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, bool fwd); - -/*! \brief Release an R2 MF tone generator context. - \param s The R2 MF tone generator context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) r2_mf_tx_release(r2_mf_tx_state_t *s); - -/*! \brief Free an R2 MF tone generator context. - \param s The R2 MF tone generator context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) r2_mf_tx_free(r2_mf_tx_state_t *s); - -/*! Process a block of received Bell MF audio samples. - \brief Process a block of received Bell MF audio samples. - \param s The Bell MF receiver context. - \param amp The audio sample buffer. - \param samples The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) bell_mf_rx(bell_mf_rx_state_t *s, const int16_t amp[], int samples); - -/*! \brief Get a string of digits from a Bell MF receiver's output buffer. - \param s The Bell MF receiver context. - \param buf The buffer for the received digits. - \param max The maximum number of digits to be returned, - \return The number of digits actually returned. */ -SPAN_DECLARE(size_t) bell_mf_rx_get(bell_mf_rx_state_t *s, char *buf, int max); - -/*! \brief Initialise a Bell MF receiver context. - \param s The Bell MF receiver context. - \param callback An optional callback routine, used to report received digits. If - no callback routine is set, digits may be collected, using the bell_mf_rx_get() - function. - \param user_data An opaque pointer which is associated with the context, - and supplied in callbacks. - \return A pointer to the Bell MF receiver context.*/ -SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s, - digits_rx_callback_t callback, - void *user_data); - -/*! \brief Release a Bell MF receiver context. - \param s The Bell MF receiver context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) bell_mf_rx_release(bell_mf_rx_state_t *s); - -/*! \brief Free a Bell MF receiver context. - \param s The Bell MF receiver context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) bell_mf_rx_free(bell_mf_rx_state_t *s); - -/*! Process a block of received R2 MF audio samples. - \brief Process a block of received R2 MF audio samples. - \param s The R2 MF receiver context. - \param amp The audio sample buffer. - \param samples The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples); - -/*! \brief Get the current digit from an R2 MF receiver. - \param s The R2 MF receiver context. - \return The number digits being received. */ -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 - 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() - function. - \param user_data An opaque pointer which is associated with the context, - 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, - bool fwd, - tone_report_func_t callback, - void *user_data); - -/*! \brief Release an R2 MF receiver context. - \param s The R2 MF receiver context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) r2_mf_rx_release(r2_mf_rx_state_t *s); - -/*! \brief Free an R2 MF receiver context. - \param s The R2 MF receiver context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) r2_mf_rx_free(r2_mf_rx_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/bert.h b/libs/spandsp/src/spandsp/bert.h deleted file mode 100644 index 93d8d08c13..0000000000 --- a/libs/spandsp/src/spandsp/bert.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bert.h - Bit error rate tests. - * - * 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. - */ - -#if !defined(_SPANDSP_BERT_H_) -#define _SPANDSP_BERT_H_ - -/*! \page bert_page The Bit Error Rate tester -\section bert_page_sec_1 What does it do? -The Bit Error Rate tester generates a pseudo random bit stream. It also accepts such -a pattern, synchronises to it, and checks the bit error rate in this stream. - -\section bert_page_sec_2 How does it work? -The Bit Error Rate tester generates a bit stream, with a repeating 2047 bit pseudo -random pattern, using an 11 stage polynomial generator. It also accepts such a pattern, -synchronises to it, and checks the bit error rate in this stream. If the error rate is -excessive the tester assumes synchronisation has been lost, and it attempts to -resynchronise with the stream. - -The bit error rate is continuously assessed against decadic ranges - - > 1 in 10^2 - > 1 in 10^3 - > 1 in 10^4 - > 1 in 10^5 - > 1 in 10^6 - > 1 in 10^7 - < 1 in 10^7 -To ensure fairly smooth results from this assessment, each decadic level is assessed -over 10/error rate bits. That is, to assess if the signal's BER is above or below 1 in 10^5 -the software looks over 10*10^5 => 10^6 bits. -*/ - -enum -{ - BERT_REPORT_SYNCED = 0, - BERT_REPORT_UNSYNCED, - BERT_REPORT_REGULAR, - BERT_REPORT_GT_10_2, - BERT_REPORT_LT_10_2, - BERT_REPORT_LT_10_3, - BERT_REPORT_LT_10_4, - BERT_REPORT_LT_10_5, - BERT_REPORT_LT_10_6, - BERT_REPORT_LT_10_7 -}; - -/* The QBF strings should be: - "VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )" - "ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )" -*/ - -enum -{ - BERT_PATTERN_ZEROS = 0, - BERT_PATTERN_ONES, - BERT_PATTERN_7_TO_1, - BERT_PATTERN_3_TO_1, - BERT_PATTERN_1_TO_1, - BERT_PATTERN_1_TO_3, - BERT_PATTERN_1_TO_7, - BERT_PATTERN_QBF, - BERT_PATTERN_ITU_O151_23, - BERT_PATTERN_ITU_O151_20, - BERT_PATTERN_ITU_O151_15, - BERT_PATTERN_ITU_O152_11, - BERT_PATTERN_ITU_O153_9 -}; - -/*! - Bit error rate tester (BERT) results descriptor. This is used to report the - results of a BER test. -*/ -typedef struct -{ - int total_bits; - int bad_bits; - int resyncs; -} bert_results_t; - -typedef void (*bert_report_func_t)(void *user_data, int reason, bert_results_t *bert_results); - -/*! - Bit error rate tester (BERT) descriptor. This defines the working state for a - single instance of the BERT. -*/ -typedef struct bert_state_s bert_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Return a short description of a BERT event. - \param event The event type. - \return A pointer to a short text string describing the event. */ -SPAN_DECLARE(const char *) bert_event_to_str(int event); - -/*! Initialise a BERT context. - \param s The BERT context. - \param limit The maximum test duration. - \param pattern One of the supported BERT signal patterns. - \param resync_len ??? - \param resync_percent The percentage of bad bits which will cause a resync. - \return The BERT context. */ -SPAN_DECLARE(bert_state_t *) bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent); - -SPAN_DECLARE(int) bert_release(bert_state_t *s); - -SPAN_DECLARE(int) bert_free(bert_state_t *s); - -/*! Get the next bit of the BERT sequence from the generator. - \param s The BERT context. - \return The bit. */ -SPAN_DECLARE(int) bert_get_bit(bert_state_t *s); - -/*! Put the next bit of the BERT sequence to the analyser. - \param s The BERT context. - \param bit The bit. */ -SPAN_DECLARE(void) bert_put_bit(bert_state_t *s, int bit); - -/*! Set the callback function for reporting the test status. - \param s The BERT context. - \param freq The required frequency of regular reports. - \param reporter The callback function. - \param user_data An opaque pointer passed to the reporter routine. */ -SPAN_DECLARE(void) bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data); - -/*! Get the results of the BERT. - \param s The BERT context. - \param results The results. - \return The size of the result structure. */ -SPAN_DECLARE(int) bert_result(bert_state_t *s, bert_results_t *results); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/biquad.h b/libs/spandsp/src/spandsp/biquad.h deleted file mode 100644 index 95e8517e1c..0000000000 --- a/libs/spandsp/src/spandsp/biquad.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * biquad.h - General telephony bi-quad section routines (currently this just - * handles canonic/type 2 form) - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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. - */ - -/*! \page biquad_page Bi-quadratic filter sections -\section biquad_page_sec_1 What does it do? -???. - -\section biquad_page_sec_2 How does it work? -???. -*/ - -#if !defined(_SPANDSP_BIQUAD_H_) -#define _SPANDSP_BIQUAD_H_ - -typedef struct -{ - int32_t gain; - int32_t a1; - int32_t a2; - int32_t b1; - int32_t b2; - - int32_t z1; - int32_t z2; - -#if FIRST_ORDER_NOISE_SHAPING - int32_t residue; -#elif SECOND_ORDER_NOISE_SHAPING - int32_t residue1; - int32_t residue2; -#endif -} biquad2_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ void biquad2_init(biquad2_state_t *bq, - int32_t gain, - int32_t a1, - int32_t a2, - int32_t b1, - int32_t b2) -{ - bq->gain = gain; - bq->a1 = a1; - bq->a2 = a2; - bq->b1 = b1; - bq->b2 = b2; - - bq->z1 = 0; - bq->z2 = 0; - -#if FIRST_ORDER_NOISE_SHAPING - bq->residue = 0; -#elif SECOND_ORDER_NOISE_SHAPING - bq->residue1 = 0; - bq->residue2 = 0; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t biquad2(biquad2_state_t *bq, int16_t sample) -{ - int32_t y; - int32_t z0; - - z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; - y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; - - bq->z2 = bq->z1; - bq->z1 = z0 >> 15; -#if FIRST_ORDER_NOISE_SHAPING - y += bq->residue; - bq->residue = y & 0x7FFF; -#elif SECOND_ORDER_NOISE_SHAPING - y += (2*bq->residue1 - bq->residue2); - bq->residue2 = bq->residue1; - bq->residue1 = y & 0x7FFF; -#endif - y >>= 15; - return (int16_t) y; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/bit_operations.h b/libs/spandsp/src/spandsp/bit_operations.h deleted file mode 100644 index 7b5b5aface..0000000000 --- a/libs/spandsp/src/spandsp/bit_operations.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bit_operations.h - Various bit level operations, such as bit reversal - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_BIT_OPERATIONS_H_) -#define _SPANDSP_BIT_OPERATIONS_H_ - -#if defined(__i386__) || defined(__x86_64__) -#if !defined(__SUNPRO_C) || (__SUNPRO_C >= 0x0590) -#define SPANDSP_USE_86_ASM -#endif -#endif - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \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(uint32_t bits) -{ -#if defined(SPANDSP_USE_86_ASM) - int res; - - __asm__ (" xorl %[res],%[res];\n" - " decl %[res];\n" - " bsrl %[bits],%[res]\n" - : [res] "=&r" (res) - : [bits] "rm" (bits)); - return res; -#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int res; - - __asm__("clz %[res], %[bits]" - : [res] "=r" (res) - : [bits] "r" (bits)); - return 31 - res; -#elif defined(__ppc__) || defined(__powerpc__) - int res; - - __asm__ ("cntlzw %[res],%[bits];\n" - : [res] "=&r" (res) - : [bits] "r" (bits)); - return 31 - res; -#elif defined(_M_IX86) - /* Visual Studio i386 */ - __asm - { - xor eax, eax - dec eax - bsr eax, bits - } -#elif defined(_M_X64) - /* Visual Studio x86_64 */ - /* TODO: Need the appropriate x86_64 code */ - int res; - - if (bits == 0) - return -1; - res = 0; - if (bits & 0xFFFF0000) - { - bits &= 0xFFFF0000; - res += 16; - } - if (bits & 0xFF00FF00) - { - bits &= 0xFF00FF00; - res += 8; - } - if (bits & 0xF0F0F0F0) - { - bits &= 0xF0F0F0F0; - res += 4; - } - if (bits & 0xCCCCCCCC) - { - bits &= 0xCCCCCCCC; - res += 2; - } - if (bits & 0xAAAAAAAA) - { - bits &= 0xAAAAAAAA; - res += 1; - } - return res; -#else - int res; - - if (bits == 0) - return -1; - res = 0; - if (bits & 0xFFFF0000) - { - bits &= 0xFFFF0000; - res += 16; - } - if (bits & 0xFF00FF00) - { - bits &= 0xFF00FF00; - res += 8; - } - if (bits & 0xF0F0F0F0) - { - bits &= 0xF0F0F0F0; - res += 4; - } - if (bits & 0xCCCCCCCC) - { - bits &= 0xCCCCCCCC; - res += 2; - } - if (bits & 0xAAAAAAAA) - { - bits &= 0xAAAAAAAA; - res += 1; - } - return res; -#endif -} -/*- End of function --------------------------------------------------------*/ - -/*! \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(uint32_t bits) -{ - int res; - -#if defined(SPANDSP_USE_86_ASM) - __asm__ (" xorl %[res],%[res];\n" - " decl %[res];\n" - " bsfl %[bits],%[res]\n" - : [res] "=&r" (res) - : [bits] "rm" (bits)); - return res; -#else - if (bits == 0) - return -1; - res = 31; - if (bits & 0x0000FFFF) - { - bits &= 0x0000FFFF; - res -= 16; - } - if (bits & 0x00FF00FF) - { - bits &= 0x00FF00FF; - res -= 8; - } - if (bits & 0x0F0F0F0F) - { - bits &= 0x0F0F0F0F; - res -= 4; - } - if (bits & 0x33333333) - { - bits &= 0x33333333; - res -= 2; - } - if (bits & 0x55555555) - { - bits &= 0x55555555; - res -= 1; - } - return res; -#endif -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Bit reverse a byte. - \param data The byte to be reversed. - \return The bit reversed version of data. */ -static __inline__ uint8_t bit_reverse8(uint8_t x) -{ -#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) - /* If multiply is fast */ - return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16; -#else - /* If multiply is slow, but we have a barrel shifter */ - x = (x >> 4) | (x << 4); - x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2); - return ((x & 0xAA) >> 1) | ((x & 0x55) << 1); -#endif -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Bit reverse a 16 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -SPAN_DECLARE(uint16_t) bit_reverse16(uint16_t data); - -/*! \brief Bit reverse a 32 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -SPAN_DECLARE(uint32_t) bit_reverse32(uint32_t data); - -/*! \brief Bit reverse each of the four bytes in a 32 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -SPAN_DECLARE(uint32_t) bit_reverse_4bytes(uint32_t data); - -#if defined(__x86_64__) -/*! \brief Bit reverse each of the eight bytes in a 64 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -SPAN_DECLARE(uint64_t) bit_reverse_8bytes(uint64_t data); -#endif - -/*! \brief Bit reverse each byte in a buffer. - \param to The buffer to place the reversed data in. - \param from The buffer containing the data to be reversed. - \param len The length of the data in the buffer. */ -SPAN_DECLARE(void) bit_reverse(uint8_t to[], const uint8_t from[], int len); - -/*! \brief Find the number of set bits in a 32 bit word. - \param x The word to be searched. - \return The number of set bits. */ -SPAN_DECLARE(int) one_bits32(uint32_t x); - -/*! \brief Create a mask as wide as the number in a 32 bit word. - \param x The word to be searched. - \return The mask. */ -SPAN_DECLARE(uint32_t) make_mask32(uint32_t x); - -/*! \brief Create a mask as wide as the number in a 16 bit word. - \param x The word to be searched. - \return The mask. */ -SPAN_DECLARE(uint16_t) make_mask16(uint16_t x); - -/*! \brief Find the least significant one in a word, and return a word - with just that bit set. - \param x The word to be searched. - \return The word with the single set bit. */ -static __inline__ uint32_t least_significant_one32(uint32_t x) -{ - return (x & (-(int32_t) x)); -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Find the most significant one in a word, and return a word - with just that bit set. - \param x The word to be searched. - \return The word with the single set bit. */ -static __inline__ uint32_t most_significant_one32(uint32_t x) -{ -#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__) - return 1 << top_bit(x); -#else - x = make_mask32(x); - return (x ^ (x >> 1)); -#endif -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Find the parity of a byte. - \param x The byte to be checked. - \return 1 for odd, or 0 for even. */ -static __inline__ int parity8(uint8_t x) -{ - x = (x ^ (x >> 4)) & 0x0F; - return (0x6996 >> x) & 1; -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Find the parity of a 16 bit word. - \param x The word to be checked. - \return 1 for odd, or 0 for even. */ -static __inline__ int parity16(uint16_t x) -{ - x ^= (x >> 8); - x = (x ^ (x >> 4)) & 0x0F; - return (0x6996 >> x) & 1; -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Find the parity of a 32 bit word. - \param x The word to be checked. - \return 1 for odd, or 0 for even. */ -static __inline__ int parity32(uint32_t x) -{ - x ^= (x >> 16); - x ^= (x >> 8); - x = (x ^ (x >> 4)) & 0x0F; - return (0x6996 >> x) & 1; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/bitstream.h b/libs/spandsp/src/spandsp/bitstream.h deleted file mode 100644 index edbaedb48f..0000000000 --- a/libs/spandsp/src/spandsp/bitstream.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bitstream.h - Bitstream composition and decomposition routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_BITSTREAM_H_) -#define _SPANDSP_BITSTREAM_H_ - -/*! \page bitstream_page Bitstream composition and decomposition -\section bitstream_page_sec_1 What does it do? - -\section bitstream_page_sec_2 How does it work? -*/ - -/*! Bitstream handler state */ -typedef struct bitstream_state_s bitstream_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Put a chunk of bits into the output buffer. - \param s A pointer to the bitstream context. - \param c A pointer to the bitstream output buffer. - \param value The value to be pushed into the output buffer. - \param bits The number of bits of value to be pushed. 1 to 25 bits is valid. */ -SPAN_DECLARE(void) bitstream_put(bitstream_state_t *s, uint8_t **c, uint32_t value, int bits); - -/*! \brief Get a chunk of bits from the input buffer. - \param s A pointer to the bitstream context. - \param c A pointer to the bitstream input buffer. - \param bits The number of bits of value to be grabbed. 1 to 25 bits is valid. - \return The value retrieved from the input buffer. */ -SPAN_DECLARE(uint32_t) bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits); - -/*! \brief Emit any residual bits to the output buffer, without actually flushing them. - This is useful for getting the buffer fully up to date, ready for things - like CRC calculations, while allowing bitstream_put() to be used to continue - the message later. - \param s A pointer to the bitstream context. - \param c A pointer to the bitstream output buffer. */ -SPAN_DECLARE(void) bitstream_emit(bitstream_state_t *s, uint8_t **c); - -/*! \brief Flush any residual bits to the output buffer. - \param s A pointer to the bitstream context. - \param c A pointer to the bitstream output buffer. */ -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. - \return A pointer to the bitstream context. */ -SPAN_DECLARE(bitstream_state_t *) bitstream_init(bitstream_state_t *s, int direction); - -SPAN_DECLARE(int) bitstream_release(bitstream_state_t *s); - -SPAN_DECLARE(int) bitstream_free(bitstream_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/complex.h b/libs/spandsp/src/spandsp/complex.h deleted file mode 100644 index 4958a5898f..0000000000 --- a/libs/spandsp/src/spandsp/complex.h +++ /dev/null @@ -1,511 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex.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 */ - -/*! \page complex_page Complex number support -\section complex_page_sec_1 What does it do? -Complex number support is part of the C99 standard. However, support for this -in C compilers is still patchy. A set of complex number feaures is provided as -a "temporary" measure, until native C language complex number support is -widespread. -*/ - -#if !defined(_SPANDSP_COMPLEX_H_) -#define _SPANDSP_COMPLEX_H_ - -/*! - Floating complex type. -*/ -typedef struct -{ - /*! \brief Real part. */ - float re; - /*! \brief Imaginary part. */ - float im; -} complexf_t; - -/*! - Floating complex type. -*/ -typedef struct -{ - /*! \brief Real part. */ - double re; - /*! \brief Imaginary part. */ - double im; -} complex_t; - -#if defined(HAVE_LONG_DOUBLE) -/*! - Long double complex type. -*/ -typedef struct -{ - /*! \brief Real part. */ - long double re; - /*! \brief Imaginary part. */ - long double im; -} complexl_t; -#endif - -/*! - Complex integer type. -*/ -typedef struct -{ - /*! \brief Real part. */ - int re; - /*! \brief Imaginary part. */ - int im; -} complexi_t; - -/*! - Complex 16 bit integer type. -*/ -typedef struct -{ - /*! \brief Real part. */ - int16_t re; - /*! \brief Imaginary part. */ - int16_t im; -} complexi16_t; - -/*! - Complex 32 bit integer type. -*/ -typedef struct -{ - /*! \brief Real part. */ - int32_t re; - /*! \brief Imaginary part. */ - int32_t im; -} complexi32_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ complexf_t complex_setf(float re, float im) -{ - complexf_t z; - - z.re = re; - z.im = im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t complex_set(double re, double im) -{ - complex_t z; - - z.re = re; - z.im = im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ complexl_t complex_setl(long double re, long double im) -{ - complexl_t z; - - z.re = re; - z.im = im; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ complexi_t complex_seti(int re, int im) -{ - complexi_t z; - - z.re = re; - z.im = im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi16_t complex_seti16(int16_t re, int16_t im) -{ - complexi16_t z; - - z.re = re; - z.im = im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi32_t complex_seti32(int32_t re, int32_t im) -{ - complexi32_t z; - - z.re = re; - z.im = im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexf_t complex_addf(const complexf_t *x, const complexf_t *y) -{ - complexf_t z; - - z.re = x->re + y->re; - z.im = x->im + y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t complex_add(const complex_t *x, const complex_t *y) -{ - complex_t z; - - z.re = x->re + y->re; - z.im = x->im + y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ complexl_t complex_addl(const complexl_t *x, const complexl_t *y) -{ - complexl_t z; - - z.re = x->re + y->re; - z.im = x->im + y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ complexi_t complex_addi(const complexi_t *x, const complexi_t *y) -{ - complexi_t z; - - z.re = x->re + y->re; - z.im = x->im + y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi16_t complex_addi16(const complexi16_t *x, const complexi16_t *y) -{ - complexi16_t z; - - z.re = x->re + y->re; - z.im = x->im + y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi32_t complex_addi32(const complexi32_t *x, const complexi32_t *y) -{ - complexi32_t z; - - z.re = x->re + y->re; - z.im = x->im + y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexf_t complex_subf(const complexf_t *x, const complexf_t *y) -{ - complexf_t z; - - z.re = x->re - y->re; - z.im = x->im - y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t complex_sub(const complex_t *x, const complex_t *y) -{ - complex_t z; - - z.re = x->re - y->re; - z.im = x->im - y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ complexl_t complex_subl(const complexl_t *x, const complexl_t *y) -{ - complexl_t z; - - z.re = x->re - y->re; - z.im = x->im - y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ complexi_t complex_subi(const complexi_t *x, const complexi_t *y) -{ - complexi_t z; - - z.re = x->re - y->re; - z.im = x->im - y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi16_t complex_subi16(const complexi16_t *x, const complexi16_t *y) -{ - complexi16_t z; - - z.re = x->re - y->re; - z.im = x->im - y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi32_t complex_subi32(const complexi32_t *x, const complexi32_t *y) -{ - complexi32_t z; - - z.re = x->re - y->re; - z.im = x->im - y->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexf_t complex_mulf(const complexf_t *x, const complexf_t *y) -{ - complexf_t z; - - z.re = x->re*y->re - x->im*y->im; - z.im = x->re*y->im + x->im*y->re; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t complex_mul(const complex_t *x, const complex_t *y) -{ - complex_t z; - - z.re = x->re*y->re - x->im*y->im; - z.im = x->re*y->im + x->im*y->re; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ complexl_t complex_mull(const complexl_t *x, const complexl_t *y) -{ - complexl_t z; - - z.re = x->re*y->re - x->im*y->im; - z.im = x->re*y->im + x->im*y->re; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ complexi_t complex_muli(const complexi_t *x, const complexi_t *y) -{ - complexi_t z; - - z.re = x->re*y->re - x->im*y->im; - z.im = x->re*y->im + x->im*y->re; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi16_t complex_muli16(const complexi16_t *x, const complexi16_t *y) -{ - complexi16_t z; - - z.re = (int16_t) ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im); - z.im = (int16_t) ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re); - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi16_t complex_mul_q1_15(const complexi16_t *x, const complexi16_t *y) -{ - complexi16_t z; - - z.re = (int16_t) (((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 15); - z.im = (int16_t) (((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 15); - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi32_t complex_muli32i16(const complexi32_t *x, const complexi16_t *y) -{ - complexi32_t z; - - z.re = x->re*(int32_t) y->re - x->im*(int32_t) y->im; - z.im = x->re*(int32_t) y->im + x->im*(int32_t) y->re; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi32_t complex_muli32(const complexi32_t *x, const complexi32_t *y) -{ - complexi32_t z; - - z.re = x->re*y->re - x->im*y->im; - z.im = x->re*y->im + x->im*y->re; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexf_t complex_divf(const complexf_t *x, const complexf_t *y) -{ - complexf_t z; - float f; - - f = y->re*y->re + y->im*y->im; - z.re = ( x->re*y->re + x->im*y->im)/f; - z.im = (-x->re*y->im + x->im*y->re)/f; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t complex_div(const complex_t *x, const complex_t *y) -{ - complex_t z; - double f; - - f = y->re*y->re + y->im*y->im; - z.re = ( x->re*y->re + x->im*y->im)/f; - z.im = (-x->re*y->im + x->im*y->re)/f; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ complexl_t complex_divl(const complexl_t *x, const complexl_t *y) -{ - complexl_t z; - long double f; - - f = y->re*y->re + y->im*y->im; - z.re = ( x->re*y->re + x->im*y->im)/f; - z.im = (-x->re*y->im + x->im*y->re)/f; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ complexf_t complex_conjf(const complexf_t *x) -{ - complexf_t z; - - z.re = x->re; - z.im = -x->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complex_t complex_conj(const complex_t *x) -{ - complex_t z; - - z.re = x->re; - z.im = -x->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ complexl_t complex_conjl(const complexl_t *x) -{ - complexl_t z; - - z.re = x->re; - z.im = -x->im; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ complexi_t complex_conji(const complexi_t *x) -{ - complexi_t z; - - z.re = x->re; - z.im = -x->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi16_t complex_conji16(const complexi16_t *x) -{ - complexi16_t z; - - z.re = x->re; - z.im = -x->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ complexi32_t complex_conji32(const complexi32_t *x) -{ - complexi32_t z; - - z.re = x->re; - z.im = -x->im; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t poweri16(const complexi16_t *x) -{ - return (int32_t) x->re*x->re + (int32_t) x->im*x->im; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ float powerf(const complexf_t *x) -{ - return x->re*x->re + x->im*x->im; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ double power(const complex_t *x) -{ - return x->re*x->re + x->im*x->im; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ long double powerl(const complexl_t *x) -{ - return x->re*x->re + x->im*x->im; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/complex_filters.h b/libs/spandsp/src/spandsp/complex_filters.h deleted file mode 100644 index 51d3c61c00..0000000000 --- a/libs/spandsp/src/spandsp/complex_filters.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_filters.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_COMPLEX_FILTERS_H_) -#define _SPANDSP_COMPLEX_FILTERS_H_ - -typedef struct filter_s filter_t; - -typedef float (*filter_step_func_t)(filter_t *fi, float x); - -/*! Filter state */ -typedef struct -{ - int nz; - int np; - filter_step_func_t fsf; -} fspec_t; - -struct filter_s -{ - fspec_t *fs; - float sum; - int ptr; /* Only for moving average filters */ - float v[]; -}; - -typedef struct -{ - filter_t *ref; - filter_t *imf; -} cfilter_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(filter_t *) filter_create(fspec_t *fs); -SPAN_DECLARE(void) filter_delete(filter_t *fi); -SPAN_DECLARE(float) filter_step(filter_t *fi, float x); - -SPAN_DECLARE(cfilter_t *) cfilter_create(fspec_t *fs); -SPAN_DECLARE(void) cfilter_delete(cfilter_t *cfi); -SPAN_DECLARE(complexf_t) cfilter_step(cfilter_t *cfi, const complexf_t *z); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/complex_vector_float.h b/libs/spandsp/src/spandsp/complex_vector_float.h deleted file mode 100644 index 68e1302778..0000000000 --- a/libs/spandsp/src/spandsp/complex_vector_float.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_float.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_COMPLEX_VECTOR_FLOAT_H_) -#define _SPANDSP_COMPLEX_VECTOR_FLOAT_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ void cvec_copyf(complexf_t z[], const complexf_t x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_copy(complex_t z[], const complex_t x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ void cvec_copyl(complexl_t z[], const complexl_t x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ void cvec_zerof(complexf_t z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = complex_setf(0.0f, 0.0f); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_zero(complex_t z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = complex_set(0.0, 0.0); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ void cvec_zerol(complexl_t z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = complex_setl(0.0, 0.0); -} -/*- End of function --------------------------------------------------------*/ -#endif - -static __inline__ void cvec_setf(complexf_t z[], complexf_t *x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = *x; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_set(complex_t z[], complex_t *x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = *x; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -static __inline__ void cvec_setl(complexl_t z[], complexl_t *x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = *x; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(void) cvec_mulf(complexf_t z[], const complexf_t x[], const complexf_t y[], int n); - -SPAN_DECLARE(void) cvec_mul(complex_t z[], const complex_t x[], const complex_t y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) cvec_mull(complexl_t z[], const complexl_t x[], const complexl_t y[], int n); -#endif - -/*! \brief Find the dot product of two complex float vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complexf_t) cvec_dot_prodf(const complexf_t x[], const complexf_t y[], int n); - -/*! \brief Find the dot product of two complex double vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complex_t) cvec_dot_prod(const complex_t x[], const complex_t y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -/*! \brief Find the dot product of two complex long double vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complexl_t) cvec_dot_prodl(const complexl_t x[], const complexl_t y[], int n); -#endif - -/*! \brief Find the dot product of two complex float vectors, where the first is a circular buffer - with an offset for the starting position. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \param pos The starting position in the x vector. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complexf_t) cvec_circular_dot_prodf(const complexf_t x[], const complexf_t y[], int n, int pos); - -SPAN_DECLARE(void) cvec_lmsf(const complexf_t x[], complexf_t y[], int n, const complexf_t *error); - -SPAN_DECLARE(void) cvec_circular_lmsf(const complexf_t x[], complexf_t y[], int n, int pos, const complexf_t *error); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/complex_vector_int.h b/libs/spandsp/src/spandsp/complex_vector_int.h deleted file mode 100644 index a77207a63f..0000000000 --- a/libs/spandsp/src/spandsp/complex_vector_int.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_int.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_COMPLEX_VECTOR_INT_H_) -#define _SPANDSP_COMPLEX_VECTOR_INT_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ void cvec_copyi(complexi_t z[], const complexi_t x[], int n) -{ - memcpy(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_copyi16(complexi16_t z[], const complexi16_t x[], int n) -{ - memcpy(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_copyi32(complexi32_t z[], const complexi32_t x[], int n) -{ - memcpy(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_zeroi(complexi_t z[], int n) -{ - memset(z, 0, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_zeroi16(complexi16_t z[], int n) -{ - memset(z, 0, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_zeroi32(complexi32_t z[], int n) -{ - memset(z, 0, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_seti(complexi_t z[], complexi_t *x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = *x; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_seti16(complexi16_t z[], complexi16_t *x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = *x; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void cvec_seti32(complexi32_t z[], complexi32_t *x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = *x; -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Find the dot product of two complex int16_t vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complexi32_t) cvec_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n); - -/*! \brief Find the dot product of two complex int32_t vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complexi32_t) cvec_dot_prodi32(const complexi32_t x[], const complexi32_t y[], int n); - -/*! \brief Find the dot product of two complex int16_t vectors, where the first is a circular buffer - with an offset for the starting position. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \param pos The starting position in the x vector. - \return The dot product of the two vectors. */ -SPAN_DECLARE(complexi32_t) cvec_circular_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n, int pos); - -SPAN_DECLARE(void) cvec_lmsi16(const complexi16_t x[], complexi16_t y[], int n, const complexi16_t *error); - -SPAN_DECLARE(void) cvec_circular_lmsi16(const complexi16_t x[], complexi16_t y[], int n, int pos, const complexi16_t *error); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/crc.h b/libs/spandsp/src/spandsp/crc.h deleted file mode 100644 index 9d02355621..0000000000 --- a/libs/spandsp/src/spandsp/crc.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * crc.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 */ - -/*! \page crc_page CRC - -\section crc_page_sec_1 What does it do? - -\section crc_page_sec_2 How does it work? -*/ - -#if !defined(_SPANDSP_CRC_H_) -#define _SPANDSP_CRC_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Calculate the ITU/CCITT CRC-32 value in buffer. - \param buf The buffer containing the data. - \param len The length of the frame. - \param crc The initial CRC value. This is usually 0xFFFFFFFF, or 0 for a new block (it depends on - the application). It is previous returned CRC value for the continuation of a block. - \return The CRC value. -*/ -SPAN_DECLARE(uint32_t) crc_itu32_calc(const uint8_t *buf, int len, uint32_t crc); - -/*! \brief Append an ITU/CCITT CRC-32 value to a frame. - \param buf The buffer containing the frame. This must be at least 2 bytes longer than - the frame it contains, to allow room for the CRC value. - \param len The length of the frame. - \return The new length of the frame. -*/ -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. -*/ -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. - \param len The length of the frame. - \param crc The initial CRC value. This is usually 0xFFFF, or 0 for a new block (it depends on - the application). It is previous returned CRC value for the continuation of a block. - \return The CRC value. -*/ -SPAN_DECLARE(uint16_t) crc_itu16_calc(const uint8_t *buf, int len, uint16_t crc); - -/*! \brief Calculate the ITU/CCITT CRC-16 value of some bits from a byte. - \param buf The buffer containing the byte of data. - \param len The number of bits, starting from the LSB. - \param crc The initial CRC value. This is usually 0xFFFF, or 0 for a new block (it depends on - the application). It is previous returned CRC value for the continuation of a block. - \return The CRC value. -*/ -SPAN_DECLARE(uint16_t) crc_itu16_bits(uint8_t buf, int len, uint16_t crc); - -/*! \brief Append an ITU/CCITT CRC-16 value to a frame. - \param buf The buffer containing the frame. This must be at least 2 bytes longer than - the frame it contains, to allow room for the CRC value. - \param len The length of the frame. - \return The new length of the frame. -*/ -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. -*/ -SPAN_DECLARE(bool) crc_itu16_check(const uint8_t *buf, int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/data_modems.h b/libs/spandsp/src/spandsp/data_modems.h deleted file mode 100644 index 7dd09f1537..0000000000 --- a/libs/spandsp/src/spandsp/data_modems.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * data_modems.h - definitions for the analogue modem set for data 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_DATA_MODEMS_H_) -#define _SPANDSP_DATA_MODEMS_H_ - -enum -{ - DATA_MODEM_NONE = -1, - DATA_MODEM_FLUSH = 0, - DATA_MODEM_SILENCE, - DATA_MODEM_CED_TONE, - DATA_MODEM_CNG_TONE, - DATA_MODEM_V8, - DATA_MODEM_BELL103, - DATA_MODEM_BELL202, - DATA_MODEM_V21, - DATA_MODEM_V23, - DATA_MODEM_V22BIS, - DATA_MODEM_V32BIS, - DATA_MODEM_V34 -}; - -/*! - The set of modems needed for data, plus the auxilliary stuff, like tone generation. -*/ -typedef struct data_modems_state_s data_modems_state_t; - -typedef int (*data_modems_control_handler_t)(data_modems_state_t *s, void *user_data, int op, const char *num); - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* N.B. the following are currently a work in progress */ -SPAN_DECLARE(const char *) data_modems_modulation_to_str(int modulation_scheme); - -SPAN_DECLARE(void) data_modems_set_tep_mode(data_modems_state_t *s, int use_tep); - -SPAN_DECLARE(logging_state_t *) data_modems_get_logging_state(data_modems_state_t *s); - -SPAN_DECLARE(void) data_modems_call_event(data_modems_state_t *s, int event); - -SPAN_DECLARE(int) data_modems_restart(data_modems_state_t *s); - -SPAN_DECLARE(void) data_modems_set_async_mode(data_modems_state_t *s, - int data_bits, - int parity_bits, - int stop_bits); - -SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which, int baud_rate, int bit_rate); - -SPAN_DECLARE(int) data_modems_rx(data_modems_state_t *s, const int16_t amp[], int len); - -SPAN_DECLARE(int) data_modems_rx_fillin(data_modems_state_t *s, int len); - -SPAN_DECLARE(int) data_modems_tx(data_modems_state_t *s, int16_t amp[], int max_len); - -SPAN_DECLARE(void) data_modems_set_at_tx_handler(data_modems_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data); - -SPAN_DECLARE(data_modems_state_t *) data_modems_init(data_modems_state_t *s, - bool calling_party, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data, - data_modems_control_handler_t modem_control_handler, - void *modem_control_user_data, - put_msg_func_t put_msg, - get_msg_func_t get_msg, - void *user_data); - -SPAN_DECLARE(int) data_modems_release(data_modems_state_t *s); - -SPAN_DECLARE(int) data_modems_free(data_modems_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/dc_restore.h b/libs/spandsp/src/spandsp/dc_restore.h deleted file mode 100644 index 5579e0c57a..0000000000 --- a/libs/spandsp/src/spandsp/dc_restore.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dc_restore.h - General telephony routines to restore the zero D.C. - * level to audio which has a D.C. bias. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_DC_RESTORE_H_) -#define _SPANDSP_DC_RESTORE_H_ - -/*! \page dc_restore_page Removing DC bias from a signal - -\section dc_restore_page_sec_1 What does it do? - -Telecoms signals often contain considerable DC, but DC upsets a lot of signal -processing functions. Placing a zero DC restorer at the front of the processing -chain can often simplify the downstream processing. - -\section dc_restore_page_sec_2 How does it work? - -The DC restorer uses a leaky integrator to provide a long-ish term estimate of -the DC bias in the signal. A 32 bit estimate is used for the 16 bit audio, so -the noise introduced by the estimation can be keep in the lower bits, and the 16 -bit DC value, which is subtracted from the signal, is fairly clean. The -following code fragment shows the algorithm used. dc_bias is a 32 bit integer, -while the sample and the resulting clean_sample are 16 bit integers. - - dc_bias += ((((int32_t) sample << 15) - dc_bias) >> 14); - clean_sample = sample - (dc_bias >> 15); -*/ - -/*! - Zero DC restoration descriptor. This defines the working state for a single - instance of DC content filter. -*/ -typedef struct -{ - int32_t state; -} dc_restore_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ void dc_restore_init(dc_restore_state_t *dc) -{ - dc->state = 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t dc_restore(dc_restore_state_t *dc, int16_t sample) -{ - dc->state += ((((int32_t) sample << 15) - dc->state) >> 14); - return (int16_t) (sample - (dc->state >> 15)); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t dc_restore_estimate(dc_restore_state_t *dc) -{ - return (int16_t) (dc->state >> 15); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/dds.h b/libs/spandsp/src/spandsp/dds.h deleted file mode 100644 index 2364f7ce01..0000000000 --- a/libs/spandsp/src/spandsp/dds.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dds.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 */ - -#if !defined(_SPANDSP_DDS_H_) -#define _SPANDSP_DDS_H_ - -#define DDS_PHASE_RATE(frequency) (int32_t) ((frequency)*65536.0f*65536.0f/SAMPLE_RATE) -#define DDS_PHASE(angle) (int32_t) ((uint32_t) (((angle < 0.0f) ? (360.0f + angle) : angle)*65536.0f*65536.0f/360.0f)) - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Convert a 32 bit phase angle to an angle in radians, between 0 and 2*PI - \param phase The angle to convert. - \return The angle in radians. -*/ -SPAN_DECLARE(float) dds_phase_to_radians(uint32_t phase); - -/*! \brief Find the phase rate value to achieve a particular frequency. - \param frequency The desired frequency, in Hz. - \return The phase rate which while achieve the desired frequency. -*/ -SPAN_DECLARE(int32_t) dds_phase_rate(float frequency); - -/*! \brief Find the frequency, in Hz, equivalent to a phase rate. - \param phase_rate The phase rate. - \return The equivalent frequency, in Hz. -*/ -SPAN_DECLARE(float) dds_frequency(int32_t phase_rate); - -/*! \brief Find the scaling factor needed to achieve a specified level in dBm0. - \param level The desired signal level, in dBm0. - \return The scaling factor. -*/ -SPAN_DECLARE(int16_t) dds_scaling_dbm0(float level); - -/*! \brief Find the scaling factor needed to achieve a specified level in dBmov. - \param level The desired signal level, in dBmov. - \return The scaling factor. -*/ -SPAN_DECLARE(int16_t) dds_scaling_dbov(float level); - -/*! \brief Find the amplitude for a particular phase. - \param phase The desired phase 32 bit phase. - \return The signal amplitude. -*/ -SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase); - -/*! \brief Find the amplitude for a particular phase offset from an accumulated phase. - \param phase_acc The accumulated phase. - \param phase_offset The phase offset. - \return The signal amplitude. -*/ -SPAN_DECLARE(int16_t) dds_offset(uint32_t phase_acc, int32_t phase_offset); - -/*! \brief Advance the phase, without returning any new signal sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. -*/ -SPAN_DECLARE(void) dds_advance(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Generate an integer tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The signal amplitude, between -32767 and 32767. -*/ -SPAN_DECLARE(int16_t) dds(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Lookup the integer value of a specified phase. - \param phase The phase accumulator value to be looked up. - \return The signal amplitude, between -32767 and 32767. -*/ -SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase); - -/*! \brief Generate an integer tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The signal amplitude, between -32767 and 32767. -*/ -SPAN_DECLARE(int16_t) dds_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase); - -/*! \brief Lookup the complex integer value of a specified phase. - \param phase The phase accumulator value to be looked up. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi_t) dds_lookup_complexi(uint32_t phase); - -/*! \brief Generate a complex integer tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi_t) dds_complexi(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Generate a complex integer tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi_t) dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase); - -/*! \brief Generate a complex 16 bit integer tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi16_t) dds_lookup_complexi16(uint32_t phase); - -/*! \brief Generate a complex 16 bit integer tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi16_t) dds_complexi16(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Generate a complex 16bit integer tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi16_t) dds_complexi16_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase); - -/*! \brief Generate a complex 32 bit integer tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase); - -/*! \brief Generate a complex 32 bit integer tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi32_t) dds_lookup_complexi32(uint32_t phase); - -/*! \brief Generate a complex 32 bit integer tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi32_t) dds_complexi32(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Generate a complex 32 bit integer tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The complex signal amplitude, between (-32767, -32767) and (32767, 32767). -*/ -SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase); - -/*! \brief Find the phase rate equivalent to a frequency, in Hz. - \param frequency The frequency, in Hz. - \return The equivalent phase rate. -*/ -SPAN_DECLARE(int32_t) dds_phase_ratef(float frequency); - -/*! \brief Find the frequency, in Hz, equivalent to a phase rate. - \param phase_rate The phase rate. - \return The equivalent frequency, in Hz. -*/ -SPAN_DECLARE(float) dds_frequencyf(int32_t phase_rate); - -/*! \brief Find the scaling factor equivalent to a dBm0 value. - \param level The signal level in dBm0. - \return The equivalent scaling factor. -*/ -SPAN_DECLARE(float) dds_scaling_dbm0f(float level); - -/*! \brief Find the scaling factor equivalent to a dBmov value. - \param level The signal level in dBmov. - \return The equivalent scaling factor. -*/ -SPAN_DECLARE(float) dds_scaling_dbovf(float level); - -/*! \brief Advance the phase, without returning any new signal sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. -*/ -SPAN_DECLARE(void) dds_advancef(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Generate a floating point tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The signal amplitude, between -1.0 and 1.0. -*/ -SPAN_DECLARE(float) ddsf(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Lookup the floating point value of a specified phase. - \param phase The phase accumulator value to be looked up. - \return The signal amplitude, between -1.0 and 1.0. -*/ -SPAN_DECLARE(float) dds_lookupf(uint32_t phase); - -/*! \brief Lookup the floating point value of a particular phase offset from an accumulated phase. - \param phase_acc The accumulated phase. - \param phase_offset The phase offset. - \return The signal amplitude. -*/ -SPAN_DECLARE(float) dds_offsetf(uint32_t phase_acc, int32_t phase_offset); - -/*! \brief Generate a floating point tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The signal amplitude, between -1.0 and 1.0. -*/ -SPAN_DECLARE(float) dds_modf(uint32_t *phase_acc, int32_t phase_rate, float scale, int32_t phase); - -/*! \brief Generate a complex floating point tone sample. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \return The complex signal amplitude, between (-1.0, -1.0) and (1.0, 1.0). -*/ -SPAN_DECLARE(complexf_t) dds_complexf(uint32_t *phase_acc, int32_t phase_rate); - -/*! \brief Lookup the complex value of a specified phase. - \param phase The phase accumulator value to be looked up. - \return The complex signal amplitude, between (-1.0, -1.0) and (1.0, 1.0). -*/ -SPAN_DECLARE(complexf_t) dds_lookup_complexf(uint32_t phase_acc); - -/*! \brief Generate a complex floating point tone sample, with modulation. - \param phase_acc A pointer to a phase accumulator value. - \param phase_rate The phase increment to be applied. - \param scale The scaling factor. - \param phase The phase offset. - \return The complex signal amplitude, between (-1.0, -1.0) and (1.0, 1.0). -*/ -SPAN_DECLARE(complexf_t) dds_complex_modf(uint32_t *phase_acc, int32_t phase_rate, float scale, int32_t phase); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/dtmf.h b/libs/spandsp/src/spandsp/dtmf.h deleted file mode 100644 index 15915f75a6..0000000000 --- a/libs/spandsp/src/spandsp/dtmf.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dtmf.h - DTMF tone generation and detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 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_DTMF_H_) -#define _SPANDSP_DTMF_H_ - -/*! \page dtmf_rx_page DTMF receiver -\section dtmf_rx_page_sec_1 What does it do? -The DTMF receiver detects the standard DTMF digits. It is compliant with -ITU-T Q.23, ITU-T Q.24, and the local DTMF specifications of most administrations. -Its passes the test suites. It also scores *very* well on the standard -talk-off tests. - -The current design uses floating point extensively. It is not tolerant of DC. -It is expected that a DC restore stage will be placed before the DTMF detector. -Unless the dial tone filter is switched on, the detector has poor tolerance -of dial tone. Whether this matter depends on your application. If you are using -the detector in an IVR application you will need proper echo cancellation to -get good performance in the presence of speech prompts, so dial tone will not -exist. If you do need good dial tone tolerance, a dial tone filter can be -enabled in the detector. - -The DTMF receiver's design assumes the channel is free of any DC component. - -\section dtmf_rx_page_sec_2 How does it work? -Like most other DSP based DTMF detector's, this one uses the Goertzel algorithm -to look for the DTMF tones. What makes each detector design different is just how -that algorithm is used. - -Basic DTMF specs: - - Minimum tone on = 40ms - - Minimum tone off = 50ms - - Maximum digit rate = 10 per second - - Normal twist <= 8dB accepted - - Reverse twist <= 4dB accepted - - S/N >= 15dB will detect OK - - Attenuation <= 26dB will detect OK - - Frequency tolerance +- 1.5% will detect, +-3.5% will reject - -TODO: -*/ - -/*! \page dtmf_tx_page DTMF tone generation -\section dtmf_tx_page_sec_1 What does it do? - -The DTMF tone generation module provides for the generation of the -repertoire of 16 DTMF dual tones. - -\section dtmf_tx_page_sec_2 How does it work? -*/ - -#define MAX_DTMF_DIGITS 128 - -typedef void (*digits_rx_callback_t)(void *user_data, const char *digits, int len); -typedef void (*digits_tx_callback_t)(void *user_data); - -/*! - DTMF generator state descriptor. This defines the state of a single - working instance of a DTMF generator. -*/ -typedef struct dtmf_tx_state_s dtmf_tx_state_t; - -/*! - DTMF digit detector descriptor. -*/ -typedef struct dtmf_rx_state_s dtmf_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Generate a buffer of DTMF tones. - \param s The DTMF generator context. - \param amp The buffer for the generated signal. - \param max_samples The required number of generated samples. - \return The number of samples actually generated. This may be less than - max_samples if the input buffer empties. */ -SPAN_DECLARE(int) dtmf_tx(dtmf_tx_state_t *s, int16_t amp[], int max_samples); - -/*! \brief Put a string of digits in a DTMF generator's input buffer. - \param s The DTMF generator context. - \param digits The string of digits to be added. - \param len The length of the string of digits. If negative, the string is - assumed to be a NULL terminated string. - \return The number of digits actually added. This may be less than the - length of the digit string, if the buffer fills up. */ -SPAN_DECLARE(int) dtmf_tx_put(dtmf_tx_state_t *s, const char *digits, int len); - -/*! \brief Change the transmit level for a DTMF tone generator context. - \param s The DTMF generator context. - \param level The level of the low tone, in dBm0. - \param twist The twist, in dB. */ -SPAN_DECLARE(void) dtmf_tx_set_level(dtmf_tx_state_t *s, int level, int twist); - -/*! \brief Change the transmit on and off time for a DTMF tone generator context. - \param s The DTMF generator context. - \param on-time The on time, in ms. - \param off_time The off time, in ms. */ -SPAN_DECLARE(void) dtmf_tx_set_timing(dtmf_tx_state_t *s, int on_time, int off_time); - -/*! \brief Initialise a DTMF tone generator context. - \param s The DTMF generator context. - \param callback An optional callback routine, used to get more digits. - \param user_data An opaque pointer which is associated with the context, - and supplied in callbacks. - \return A pointer to the DTMF generator context. */ -SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s, - digits_tx_callback_t callback, - void *user_data); - -/*! \brief Release a DTMF tone generator context. - \param s The DTMF tone generator context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) dtmf_tx_release(dtmf_tx_state_t *s); - -/*! \brief Free a DTMF tone generator context. - \param s The DTMF tone generator context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) dtmf_tx_free(dtmf_tx_state_t *s); - -/*! Set a optional realtime callback for a DTMF receiver context. This function - is called immediately a confirmed state change occurs in the received DTMF. It - is called with the ASCII value for a DTMF tone pair, or zero to indicate no tone - is being received. - \brief Set a realtime callback for a DTMF receiver context. - \param s The DTMF receiver context. - \param callback Callback routine used to report the start and end of digits. - \param user_data An opaque pointer which is associated with the context, - and supplied in callbacks. */ -SPAN_DECLARE(void) dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s, - tone_report_func_t callback, - void *user_data); - -/*! \brief Adjust a DTMF receiver context. - \param s The DTMF receiver context. - \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. - \param threshold The minimum acceptable tone level for detection, in dBm0. - <= -99.0 to leave unchanged. */ -SPAN_DECLARE(void) dtmf_rx_parms(dtmf_rx_state_t *s, - int filter_dialtone, - float twist, - float reverse_twist, - float threshold); - -/*! Process a block of received DTMF audio samples. - \brief Process a block of received DTMF audio samples. - \param s The DTMF receiver context. - \param amp The audio sample buffer. - \param samples The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples); - -/*! Fake processing of a missing block of received DTMF audio samples. - (e.g due to packet loss). - \brief Fake processing of a missing block of received DTMF audio samples. - \param s The DTMF receiver context. - \param len The number of samples to fake. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) dtmf_rx_fillin(dtmf_rx_state_t *s, int samples); - -/*! Get the status of DTMF detection during processing of the last audio - chunk. - \brief Get the status of DTMF detection during processing of the last - audio chunk. - \param s The DTMF receiver context. - \return The current digit status. Either 'x' for a "maybe" condition, or the - digit being detected. */ -SPAN_DECLARE(int) dtmf_rx_status(dtmf_rx_state_t *s); - -/*! \brief Get a string of digits from a DTMF receiver's output buffer. - \param s The DTMF receiver context. - \param digits The buffer for the received digits. - \param max The maximum number of digits to be returned, - \return The number of digits actually returned. */ -SPAN_DECLARE(size_t) dtmf_rx_get(dtmf_rx_state_t *s, char *digits, int max); - -/*! \brief Get the logging context associated with a DTMF receiver context. - \param s The DTMF receiver context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) dtmf_rx_get_logging_state(dtmf_rx_state_t *s); - -/*! \brief Initialise a DTMF receiver context. - \param s The DTMF receiver context. - \param callback An optional callback routine, used to report received digits. If - no callback routine is set, digits may be collected, using the dtmf_rx_get() - function. - \param user_data An opaque pointer which is associated with the context, - and supplied in callbacks. - \return A pointer to the DTMF receiver context. */ -SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, - digits_rx_callback_t callback, - void *user_data); - -/*! \brief Release a DTMF receiver context. - \param s The DTMF receiver context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) dtmf_rx_release(dtmf_rx_state_t *s); - -/*! \brief Free a DTMF receiver context. - \param s The DTMF receiver context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) dtmf_rx_free(dtmf_rx_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/echo.h b/libs/spandsp/src/spandsp/echo.h deleted file mode 100644 index 14f856068f..0000000000 --- a/libs/spandsp/src/spandsp/echo.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * echo.h - An echo cancellor, suitable for electrical and acoustic - * cancellation. This code does not currently comply with - * any relevant standards (e.g. G.164/5/7/8). - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_ECHO_H_) -#define _SPANDSP_ECHO_H_ - -/*! \page echo_can_page Line echo cancellation for voice - -\section echo_can_page_sec_1 What does it do? -This module aims to provide G.168-2002 compliant echo cancellation, to remove -electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. - -\section echo_can_page_sec_2 How does it work? -The heart of the echo cancellor is FIR filter. This is adapted to match the echo -impulse response of the telephone line. It must be long enough to adequately cover -the duration of that impulse response. The signal transmitted to the telephone line -is passed through the FIR filter. Once the FIR is properly adapted, the resulting -output is an estimate of the echo signal received from the line. This is subtracted -from the received signal. The result is an estimate of the signal which originated -at the far end of the line, free from echos of our own transmitted signal. - -The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and was -introduced in 1960. It is the commonest form of filter adaption used in things -like modem line equalisers and line echo cancellers. There it works very well. -However, it only works well for signals of constant amplitude. It works very poorly -for things like speech echo cancellation, where the signal level varies widely. -This is quite easy to fix. If the signal level is normalised - similar to applying -AGC - LMS can work as well for a signal of varying amplitude as it does for a modem -signal. This normalised least mean squares (NLMS) algorithm is the commonest one used -for speech echo cancellation. Many other algorithms exist - e.g. RLS (essentially -the same as Kalman filtering), FAP, etc. Some perform significantly better than NLMS. -However, factors such as computational complexity and patents favour the use of NLMS. - -A simple refinement to NLMS can improve its performance with speech. NLMS tends -to adapt best to the strongest parts of a signal. If the signal is white noise, -the NLMS algorithm works very well. However, speech has more low frequency than -high frequency content. Pre-whitening (i.e. filtering the signal to flatten -its spectrum) the echo signal improves the adapt rate for speech, and ensures the -final residual signal is not heavily biased towards high frequencies. A very low -complexity filter is adequate for this, so pre-whitening adds little to the -compute requirements of the echo canceller. - -An FIR filter adapted using pre-whitened NLMS performs well, provided certain -conditions are met: - - - The transmitted signal has poor self-correlation. - - There is no signal being generated within the environment being cancelled. - -The difficulty is that neither of these can be guaranteed. - -If the adaption is performed while transmitting noise (or something fairly noise -like, such as voice) the adaption works very well. If the adaption is performed -while transmitting something highly correlative (typically narrow band energy -such as signalling tones or DTMF), the adaption can go seriously wrong. The reason -is there is only one solution for the adaption on a near random signal - the impulse -response of the line. For a repetitive signal, there are any number of solutions -which converge the adaption, and nothing guides the adaption to choose the generalised -one. Allowing an untrained canceller to converge on this kind of narrowband -energy probably a good thing, since at least it cancels the tones. Allowing a well -converged canceller to continue converging on such energy is just a way to ruin -its generalised adaption. A narrowband detector is needed, so adapation can be -suspended at appropriate times. - -The adaption process is based on trying to eliminate the received signal. When -there is any signal from within the environment being cancelled it may upset the -adaption process. Similarly, if the signal we are transmitting is small, noise -may dominate and disturb the adaption process. If we can ensure that the -adaption is only performed when we are transmitting a significant signal level, -and the environment is not, things will be OK. Clearly, it is easy to tell when -we are sending a significant signal. Telling, if the environment is generating a -significant signal, and doing it with sufficient speed that the adaption will -not have diverged too much more we stop it, is a little harder. - -The key problem in detecting when the environment is sourcing significant energy -is that we must do this very quickly. Given a reasonably long sample of the -received signal, there are a number of strategies which may be used to assess -whether that signal contains a strong far end component. However, by the time -that assessment is complete the far end signal will have already caused major -mis-convergence in the adaption process. An assessment algorithm is needed which -produces a fairly accurate result from a very short burst of far end energy. - -\section echo_can_page_sec_3 How do I use it? -The echo cancellor processes both the transmit and receive streams sample by -sample. The processing function is not declared inline. Unfortunately, -cancellation requires many operations per sample, so the call overhead is only a -minor burden. -*/ - -#include "fir.h" - -/* Mask bits for the adaption mode */ -enum -{ - ECHO_CAN_USE_ADAPTION = 0x01, - ECHO_CAN_USE_NLP = 0x02, - ECHO_CAN_USE_CNG = 0x04, - ECHO_CAN_USE_CLIP = 0x08, - ECHO_CAN_USE_SUPPRESSOR = 0x10, - ECHO_CAN_USE_TX_HPF = 0x20, - ECHO_CAN_USE_RX_HPF = 0x40, - ECHO_CAN_DISABLE = 0x80 -}; - -/*! - G.168 echo canceller descriptor. This defines the working state for a line - echo canceller. -*/ -typedef struct echo_can_state_s echo_can_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Create a voice echo canceller context. - \param len The length of the canceller, in samples. - \return The new canceller context, or NULL if the canceller could not be created. -*/ -SPAN_DECLARE(echo_can_state_t *) echo_can_init(int len, int adaption_mode); - -/*! Release a voice echo canceller context. - \param ec The echo canceller context. - \return 0 for OK, else -1. -*/ -SPAN_DECLARE(int) echo_can_release(echo_can_state_t *ec); - -/*! Free a voice echo canceller context. - \param ec The echo canceller context. - \return 0 for OK, else -1. -*/ -SPAN_DECLARE(int) echo_can_free(echo_can_state_t *ec); - -/*! Flush (reinitialise) a voice echo canceller context. - \param ec The echo canceller context. -*/ -SPAN_DECLARE(void) echo_can_flush(echo_can_state_t *ec); - -/*! Set the adaption mode of a voice echo canceller context. - \param ec The echo canceller context. - \param adaption_mode The mode. -*/ -SPAN_DECLARE(void) echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode); - -/*! Process a sample through a voice echo canceller. - \param ec The echo canceller context. - \param tx The transmitted audio sample. - \param rx The received audio sample. - \return The clean (echo cancelled) received sample. -*/ -SPAN_DECLARE(int16_t) echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx); - -/*! Process to high pass filter the tx signal. - \param ec The echo canceller context. - \param tx The transmitted auio sample. - \return The HP filtered transmit sample, send this to your D/A. -*/ -SPAN_DECLARE(int16_t) echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx); - -SPAN_DECLARE(void) echo_can_snapshot(echo_can_state_t *ec); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/expose.h b/libs/spandsp/src/spandsp/expose.h deleted file mode 100644 index d9811b4caa..0000000000 --- a/libs/spandsp/src/spandsp/expose.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * expose.h - Expose the internal structures of spandsp, for users who - * really need that. - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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 */ - -/* TRY TO ONLY INCLUDE THIS IF YOU REALLY REALLY HAVE TO */ - -#if !defined(_SPANDSP_EXPOSE_H_) -#define _SPANDSP_EXPOSE_H_ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/fast_convert.h b/libs/spandsp/src/spandsp/fast_convert.h deleted file mode 100644 index a1d8c026af..0000000000 --- a/libs/spandsp/src/spandsp/fast_convert.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fast_convert.h - Quick ways to convert floating point numbers to integers - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_FAST_CONVERT_H_) -#define _SPANDSP_FAST_CONVERT_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* The following code, to handle issues with lrint() and lrintf() on various - * platforms, is adapted from similar code in libsndfile, which is: - * - * Copyright (C) 2001-2004 Erik de Castro Lopo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * 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. - */ - -/* - * On Intel Pentium processors (especially PIII and probably P4), converting - * from float to int is very slow. To meet the C specs, the code produced by - * most C compilers targeting Pentium needs to change the FPU rounding mode - * before the float to int conversion is performed. - * - * Changing the FPU rounding mode causes the FPU pipeline to be flushed. It - * is this flushing of the pipeline which is so slow. - * - * Fortunately the ISO C99 specification defines the functions lrint, lrintf, - * llrint and llrintf which fix this problem as a side effect. - * - * On Unix-like systems, the configure process should have detected the - * presence of these functions. If they weren't found we have to replace them - * here with a standard C cast. - */ - -/* - * The C99 prototypes for these functions are as follows: - * - * int rintf(float x); - * int rint(double x); - * long int lrintf(float x); - * long int lrint(double x); - * long long int llrintf(float x); - * long long int llrint(double x); - * - * The presence of the required functions are detected during the configure - * process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in - * the config file. - */ - -#if defined(__CYGWIN__) -#if !defined(__cplusplus) && (__GNUC__ < 4) - /* - * CYGWIN versions prior to 1.7.1 have lrint and lrintf functions, but - * they are slow and buggy: - * http://sourceware.org/ml/cygwin/2005-06/msg00153.html - * http://sourceware.org/ml/cygwin/2005-09/msg00047.html - * These replacement functions (pulled from the Public Domain MinGW - * math.h header) replace the native versions. - */ - static __inline__ long int lrint(double x) - { - long int retval; - - __asm__ __volatile__ - ( - "fistpl %0" - : "=m" (retval) - : "t" (x) - : "st" - ); - - return retval; - } - - static __inline__ long int lrintf(float x) - { - long int retval; - - __asm__ __volatile__ - ( - "fistpl %0" - : "=m" (retval) - : "t" (x) - : "st" - ); - return retval; - } -#endif - - /* The fastest way to convert is the equivalent of lrint() */ - static __inline__ long int lfastrint(double x) - { - long int retval; - - __asm__ __volatile__ - ( - "fistpl %0" - : "=m" (retval) - : "t" (x) - : "st" - ); - - return retval; - } - - static __inline__ long int lfastrintf(float x) - { - long int retval; - - __asm__ __volatile__ - ( - "fistpl %0" - : "=m" (retval) - : "t" (x) - : "st" - ); - return retval; - } -#elif defined(__GNUC__) || (__SUNPRO_C >= 0x0590) - -#if defined(__i386__) - /* These routines are guaranteed fast on an i386 machine. Using the built in - lrint() and lrintf() should be similar, but they may not always be enabled. - Sometimes, especially with "-O0", you might get slow calls to routines. */ - static __inline__ long int lfastrint(double x) - { - long int retval; - - __asm__ __volatile__ - ( - "fistpl %0" - : "=m" (retval) - : "t" (x) - : "st" - ); - - return retval; - } - - static __inline__ long int lfastrintf(float x) - { - long int retval; - - __asm__ __volatile__ - ( - "fistpl %0" - : "=m" (retval) - : "t" (x) - : "st" - ); - return retval; - } -#elif defined(__x86_64__) - /* On an x86_64 machine, the fastest thing seems to be a pure assignment from a - double or float to an int. It looks like the design on the x86_64 took account - of the default behaviour specified for C. */ - static __inline__ long int lfastrint(double x) - { - return (long int) (x); - } - - static __inline__ long int lfastrintf(float x) - { - return (long int) (x); - } -#elif (defined(__ppc__) || defined(__powerpc__)) && !defined(__NO_FPRS__) - static __inline__ long int lfastrint(register double x) - { - int res[2]; - - __asm__ __volatile__ - ( - "fctiw %1, %1\n\t" - "stfd %1, %0" - : "=m" (res) /* Output */ - : "f" (x) /* Input */ - : "memory" - ); - - return res[1]; - } - - static __inline__ long int lfastrintf(register float x) - { - int res[2]; - - __asm__ __volatile__ - ( - "fctiw %1, %1\n\t" - "stfd %1, %0" - : "=m" (res) /* Output */ - : "f" (x) /* Input */ - : "memory" - ); - - return res[1]; - } -#else - /* Fallback routines, for unrecognised platforms */ - static __inline__ long int lfastrint(double x) - { - return (long int) x; - } - - static __inline__ long int lfastrintf(float x) - { - return (long int) x; - } -#endif - -#elif defined(_M_IX86) - /* Visual Studio i386 */ - /* - * Win32 doesn't seem to have the lrint() and lrintf() functions. - * Therefore implement inline versions of these functions here. - */ - -#if (_MSC_VER < 1800) - __inline long int lrint(double x) - { - long int i; - - _asm - { - fld x - fistp i - }; - return i; - } - - __inline long int lrintf(float x) - { - long int i; - - _asm - { - fld x - fistp i - }; - return i; - } - - __inline float rintf(float flt) - { - _asm - { - fld flt - frndint - } - } - - __inline double rint(double dbl) - { - _asm - { - fld dbl - frndint - } - } -#endif - - __inline long int lfastrint(double x) - { - long int i; - - _asm - { - fld x - fistp i - }; - return i; - } - - __inline long int lfastrintf(float x) - { - long int i; - - _asm - { - fld x - fistp i - }; - return i; - } -#elif defined(_M_X64) - /* Visual Studio x86_64 */ - /* 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)); - } - - __inline long int lrintf(float x) - { - return _mm_cvt_ss2si(_mm_load_ss((const float *) &x)); - } -#endif - - __inline long int lfastrint(double x) - { - return (long int) (x); - } - - __inline long int lfastrintf(float x) - { - return (long int) (x); - } -#elif defined(__MWERKS__) && defined(macintosh) - /* This MacOS 9 solution was provided by Stephane Letz */ - - long int __inline__ lfastrint(register double x) - { - long int res[2]; - - asm - { - fctiw x, x - stfd x, res - } - return res[1]; - } - - long int __inline__ lfastrintf(register float x) - { - long int res[2]; - - asm - { - fctiw x, x - stfd x, res - } - return res[1]; - } -#elif defined(__MACH__) && defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__)) - /* For Apple Mac OS/X - do recent versions still need this? */ - - static __inline__ long int lfastrint(register double x) - { - int res[2]; - - __asm__ __volatile__ - ( - "fctiw %1, %1\n\t" - "stfd %1, %0" - : "=m" (res) /* Output */ - : "f" (x) /* Input */ - : "memory" - ); - - return res[1]; - } - - static __inline__ long int lfastrintf(register float x) - { - int res[2]; - - __asm__ __volatile__ - ( - "fctiw %1, %1\n\t" - "stfd %1, %0" - : "=m" (res) /* Output */ - : "f" (x) /* Input */ - : "memory" - ); - - return res[1]; - } -#else - /* There is nothing else to do, but use a simple casting operation, instead of a real - rint() type function. Since we are only trying to use rint() to speed up conversions, - the accuracy issues related to changing the rounding scheme are of little concern - to us. */ - - #if !defined(__sgi) && !defined(__sunos) && !defined(__solaris) && !defined(__sun) - #warning "No usable lrint() and lrintf() functions available." - #warning "Replacing these functions with a simple C cast." - #endif - - static __inline__ long int lrint(double x) - { - return (long int) (x); - } - - static __inline__ long int lrintf(float x) - { - return (long int) (x); - } - - static __inline__ long int lfastrint(double x) - { - return (long int) (x); - } - - static __inline__ long int lfastrintf(float x) - { - return (long int) (x); - } -#endif - -#if defined(__cplusplus) -} -#endif - -#endif - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/fax.h b/libs/spandsp/src/spandsp/fax.h deleted file mode 100644 index de6d52da0e..0000000000 --- a/libs/spandsp/src/spandsp/fax.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax.h - definitions for analogue line ITU T.30 fax processing - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_FAX_H_) -#define _SPANDSP_FAX_H_ - -/*! \page fax_page FAX over analogue modem handling - -\section fax_page_sec_1 What does it do? - -\section fax_page_sec_2 How does it work? -*/ - -typedef struct fax_state_s fax_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Apply T.30 receive processing to a block of audio samples. - \brief Apply T.30 receive processing to a block of audio samples. - \param s The FAX context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. This should only be non-zero if - the software has reached the end of the FAX call. -*/ -SPAN_DECLARE(int) fax_rx(fax_state_t *s, int16_t *amp, int len); - -/*! Apply fake T.30 receive processing when a block of audio samples is missing (e.g due - to packet loss). - \brief Apply fake T.30 receive processing. - \param s The FAX context. - \param len The number of samples to fake. - \return The number of samples unprocessed. This should only be non-zero if - the software has reached the end of the FAX call. -*/ -SPAN_DECLARE(int) fax_rx_fillin(fax_state_t *s, int len); - -/*! Apply T.30 transmit processing to generate a block of audio samples. - \brief Apply T.30 transmit processing to generate a block of audio samples. - \param s The FAX context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. This will be zero when - there is nothing to send. -*/ -SPAN_DECLARE(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. -*/ -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. -*/ -SPAN_DECLARE(void) fax_set_tep_mode(fax_state_t *s, int use_tep); - -/*! Get a pointer to the T.30 engine associated with a FAX context. - \brief Get a pointer to the T.30 engine associated with a FAX context. - \param s The FAX context. - \return A pointer to the T.30 context, or NULL. -*/ -SPAN_DECLARE(t30_state_t *) fax_get_t30_state(fax_state_t *s); - -/*! Get a pointer to the logging context associated with a FAX context. - \brief Get a pointer to the logging context associated with a FAX context. - \param s The FAX context. - \return A pointer to the logging context, or NULL. -*/ -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 - context is for an answering party. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) fax_restart(fax_state_t *s, bool 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 - context is for an answering party. - \return A pointer to the FAX context, or NULL if there was a problem. -*/ -SPAN_DECLARE(fax_state_t *) fax_init(fax_state_t *s, bool calling_party); - -/*! Release a FAX context. - \brief Release a FAX context. - \param s The FAX context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) fax_release(fax_state_t *s); - -/*! Free a FAX context. - \brief Free a FAX context. - \param s The FAX context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) fax_free(fax_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/fax_modems.h b/libs/spandsp/src/spandsp/fax_modems.h deleted file mode 100644 index 15cc802474..0000000000 --- a/libs/spandsp/src/spandsp/fax_modems.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_modems.h - definitions for the analogue modem set for fax processing - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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_FAX_MODEMS_H_) -#define _SPANDSP_FAX_MODEMS_H_ - -enum -{ - FAX_MODEM_NONE = -1, - FAX_MODEM_FLUSH = 0, - FAX_MODEM_SILENCE_TX, - FAX_MODEM_SILENCE_RX, - FAX_MODEM_CED_TONE_TX, - FAX_MODEM_CNG_TONE_TX, - FAX_MODEM_NOCNG_TONE_TX, - FAX_MODEM_CED_TONE_RX, - FAX_MODEM_CNG_TONE_RX, - FAX_MODEM_V21_TX, - FAX_MODEM_V17_TX, - FAX_MODEM_V27TER_TX, - FAX_MODEM_V29_TX, - FAX_MODEM_V21_RX, - FAX_MODEM_V17_RX, - FAX_MODEM_V27TER_RX, - FAX_MODEM_V29_RX, -#if defined(SPANDSP_SUPPORT_V34) - FAX_MODEM_V34_TX, - FAX_MODEM_V34_RX -#endif -}; - -/*! - The set of modems needed for FAX, plus the auxilliary stuff, like tone generation. -*/ -typedef struct fax_modems_state_s fax_modems_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* TEMPORARY FUDGE */ -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(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len); -SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len); -SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len); -SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len); -SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len); -SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len); - -SPAN_DECLARE(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len); - -SPAN_DECLARE(void) fax_modems_hdlc_tx_flags(fax_modems_state_t *s, int flags); - -SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, int bit_rate, int short_train, int hdlc_mode); - -SPAN_DECLARE(void) fax_modems_start_slow_modem(fax_modems_state_t *s, int which); - -SPAN_DECLARE(void) fax_modems_set_tep_mode(fax_modems_state_t *s, int use_tep); - -SPAN_DECLARE(void) fax_modems_set_put_bit(fax_modems_state_t *s, put_bit_func_t put_bit, void *user_data); - -SPAN_DECLARE(void) fax_modems_set_get_bit(fax_modems_state_t *s, get_bit_func_t get_bit, void *user_data); - -SPAN_DECLARE(void) fax_modems_set_rx_handler(fax_modems_state_t *s, - span_rx_handler_t rx_handler, - void *rx_user_data, - span_rx_fillin_handler_t rx_fillin_handler, - void *rx_fillin_user_data); - -SPAN_DECLARE(void) fax_modems_set_rx_active(fax_modems_state_t *s, int active); - -SPAN_DECLARE(void) fax_modems_set_tx_handler(fax_modems_state_t *s, span_tx_handler_t handler, void *user_data); - -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. - \brief Get a pointer to the logging context associated with a FAX modems context. - \param s The FAX modems context. - \return A pointer to the logging context, or NULL. -*/ -SPAN_DECLARE(logging_state_t *) fax_modems_get_logging_state(fax_modems_state_t *s); - -SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, - int use_tep, - hdlc_frame_handler_t hdlc_accept, - hdlc_underflow_handler_t hdlc_tx_underflow, - put_bit_func_t non_ecm_put_bit, - get_bit_func_t non_ecm_get_bit, - tone_report_func_t tone_callback, - void *user_data); - -SPAN_DECLARE(int) fax_modems_release(fax_modems_state_t *s); - -SPAN_DECLARE(int) fax_modems_free(fax_modems_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/fir.h b/libs/spandsp/src/spandsp/fir.h deleted file mode 100644 index 85be5d2a6f..0000000000 --- a/libs/spandsp/src/spandsp/fir.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fir.h - General telephony FIR routines - * - * Written by Steve Underwood - * - * Copyright (C) 2002 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. - */ - -/*! \page fir_page FIR filtering -\section fir_page_sec_1 What does it do? -???. - -\section fir_page_sec_2 How does it work? -???. -*/ - -#if !defined(_SPANDSP_FIR_H_) -#define _SPANDSP_FIR_H_ - -#if defined(USE_MMX) || defined(USE_SSE2) -#include "mmx.h" -#endif - -/*! - 16 bit integer FIR descriptor. This defines the working state for a single - instance of an FIR filter using 16 bit integer coefficients. -*/ -typedef struct -{ - int taps; - int curr_pos; - const int16_t *coeffs; - int16_t *history; -} fir16_state_t; - -/*! - 32 bit integer FIR descriptor. This defines the working state for a single - instance of an FIR filter using 32 bit integer coefficients, and filtering - 16 bit integer data. -*/ -typedef struct -{ - int taps; - int curr_pos; - const int32_t *coeffs; - int16_t *history; -} fir32_state_t; - -/*! - Floating point FIR descriptor. This defines the working state for a single - instance of an FIR filter using floating point coefficients and data. -*/ -typedef struct -{ - int taps; - int curr_pos; - const float *coeffs; - float *history; -} fir_float_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ const int16_t *fir16_create(fir16_state_t *fir, - const int16_t *coeffs, - int taps) -{ - fir->taps = taps; - fir->curr_pos = taps - 1; - fir->coeffs = coeffs; -#if defined(USE_MMX) || defined(USE_SSE2) - if ((fir->history = span_alloc(2*taps*sizeof(int16_t)))) - memset(fir->history, 0, 2*taps*sizeof(int16_t)); -#else - if ((fir->history = (int16_t *) span_alloc(taps*sizeof(int16_t)))) - memset(fir->history, 0, taps*sizeof(int16_t)); -#endif - return fir->history; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void fir16_flush(fir16_state_t *fir) -{ -#if defined(USE_MMX) || defined(USE_SSE2) - memset(fir->history, 0, 2*fir->taps*sizeof(int16_t)); -#else - memset(fir->history, 0, fir->taps*sizeof(int16_t)); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void fir16_free(fir16_state_t *fir) -{ - span_free(fir->history); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t fir16(fir16_state_t *fir, int16_t sample) -{ - int i; - int32_t y; -#if defined(USE_MMX) - mmx_t *mmx_coeffs; - mmx_t *mmx_hist; - - fir->history[fir->curr_pos] = sample; - fir->history[fir->curr_pos + fir->taps] = sample; - - mmx_coeffs = (mmx_t *) fir->coeffs; - mmx_hist = (mmx_t *) &fir->history[fir->curr_pos]; - i = fir->taps; - pxor_r2r(mm4, mm4); - /* 8 samples per iteration, so the filter must be a multiple of 8 long. */ - while (i > 0) - { - movq_m2r(mmx_coeffs[0], mm0); - movq_m2r(mmx_coeffs[1], mm2); - movq_m2r(mmx_hist[0], mm1); - movq_m2r(mmx_hist[1], mm3); - mmx_coeffs += 2; - mmx_hist += 2; - pmaddwd_r2r(mm1, mm0); - pmaddwd_r2r(mm3, mm2); - paddd_r2r(mm0, mm4); - paddd_r2r(mm2, mm4); - i -= 8; - } - movq_r2r(mm4, mm0); - psrlq_i2r(32, mm0); - paddd_r2r(mm0, mm4); - movd_r2m(mm4, y); - emms(); -#elif defined(USE_SSE2) - xmm_t *xmm_coeffs; - xmm_t *xmm_hist; - - fir->history[fir->curr_pos] = sample; - fir->history[fir->curr_pos + fir->taps] = sample; - - xmm_coeffs = (xmm_t *) fir->coeffs; - xmm_hist = (xmm_t *) &fir->history[fir->curr_pos]; - i = fir->taps; - pxor_r2r(xmm4, xmm4); - /* 16 samples per iteration, so the filter must be a multiple of 16 long. */ - while (i > 0) - { - movdqu_m2r(xmm_coeffs[0], xmm0); - movdqu_m2r(xmm_coeffs[1], xmm2); - movdqu_m2r(xmm_hist[0], xmm1); - movdqu_m2r(xmm_hist[1], xmm3); - xmm_coeffs += 2; - xmm_hist += 2; - pmaddwd_r2r(xmm1, xmm0); - pmaddwd_r2r(xmm3, xmm2); - paddd_r2r(xmm0, xmm4); - paddd_r2r(xmm2, xmm4); - i -= 16; - } - movdqa_r2r(xmm4, xmm0); - psrldq_i2r(8, xmm0); - paddd_r2r(xmm0, xmm4); - movdqa_r2r(xmm4, xmm0); - psrldq_i2r(4, xmm0); - paddd_r2r(xmm0, xmm4); - movd_r2m(xmm4, y); -#else - int offset1; - int offset2; - - fir->history[fir->curr_pos] = sample; - - offset2 = fir->curr_pos; - offset1 = fir->taps - offset2; - y = 0; - for (i = fir->taps - 1; i >= offset1; i--) - y += fir->coeffs[i]*fir->history[i - offset1]; - for ( ; i >= 0; i--) - y += fir->coeffs[i]*fir->history[i + offset2]; -#endif - if (fir->curr_pos <= 0) - fir->curr_pos = fir->taps; - fir->curr_pos--; - return (int16_t) (y >> 15); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ const int16_t *fir32_create(fir32_state_t *fir, - const int32_t *coeffs, - int taps) -{ - fir->taps = taps; - fir->curr_pos = taps - 1; - fir->coeffs = coeffs; - fir->history = (int16_t *) span_alloc(taps*sizeof(int16_t)); - if (fir->history) - memset(fir->history, '\0', taps*sizeof(int16_t)); - return fir->history; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void fir32_flush(fir32_state_t *fir) -{ - memset(fir->history, 0, fir->taps*sizeof(int16_t)); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void fir32_free(fir32_state_t *fir) -{ - span_free(fir->history); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t fir32(fir32_state_t *fir, int16_t sample) -{ - int i; - int32_t y; - int offset1; - int offset2; - - fir->history[fir->curr_pos] = sample; - offset2 = fir->curr_pos; - offset1 = fir->taps - offset2; - y = 0; - for (i = fir->taps - 1; i >= offset1; i--) - y += fir->coeffs[i]*fir->history[i - offset1]; - for ( ; i >= 0; i--) - y += fir->coeffs[i]*fir->history[i + offset2]; - if (fir->curr_pos <= 0) - fir->curr_pos = fir->taps; - fir->curr_pos--; - return (int16_t) (y >> 15); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ const float *fir_float_create(fir_float_state_t *fir, - const float *coeffs, - int taps) -{ - fir->taps = taps; - fir->curr_pos = taps - 1; - fir->coeffs = coeffs; - fir->history = (float *) span_alloc(taps*sizeof(float)); - if (fir->history) - memset(fir->history, '\0', taps*sizeof(float)); - return fir->history; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void fir_float_free(fir_float_state_t *fir) -{ - span_free(fir->history); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t fir_float(fir_float_state_t *fir, int16_t sample) -{ - int i; - float y; - int offset1; - int offset2; - - fir->history[fir->curr_pos] = sample; - - offset2 = fir->curr_pos; - offset1 = fir->taps - offset2; - y = 0; - for (i = fir->taps - 1; i >= offset1; i--) - y += fir->coeffs[i]*fir->history[i - offset1]; - for ( ; i >= 0; i--) - y += fir->coeffs[i]*fir->history[i + offset2]; - if (fir->curr_pos <= 0) - fir->curr_pos = fir->taps; - fir->curr_pos--; - return (int16_t) y; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/fsk.h b/libs/spandsp/src/spandsp/fsk.h deleted file mode 100644 index c016eca8a5..0000000000 --- a/libs/spandsp/src/spandsp/fsk.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fsk.h - FSK modem transmit and receive parts - * - * 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 */ - -/*! \page fsk_page FSK modems -\section fsk_page_sec_1 What does it do? -Most of the oldest telephony modems use incoherent FSK modulation. This module can -be used to implement both the transmit and receive sides of a number of these -modems. There are integrated definitions for: - - - V.21 - - V.23 - - Bell 103 - - Bell 202 - - Weitbrecht (Used for TDD - Telecoms Device for the Deaf) - -The audio output or input is a stream of 16 bit samples, at 8000 samples/second. -The transmit and receive sides can be used independantly. - -\section fsk_page_sec_2 The transmitter - -The FSK transmitter uses a DDS generator to synthesise the waveform. This -naturally produces phase coherent transitions, as the phase update rate is -switched, producing a clean spectrum. The symbols are not generally an integer -number of samples long. However, the symbol time for the fastest data rate -generally used (1200bps) is more than 7 samples long. The jitter resulting from -switching at the nearest sample is, therefore, acceptable. No interpolation is -used. - -\section fsk_page_sec_3 The receiver - -The FSK receiver uses a quadrature correlation technique to demodulate the -signal. Two DDS quadrature oscillators are used. The incoming signal is -correlated with the oscillator signals over a period of one symbol. The -oscillator giving the highest net correlation from its I and Q outputs is the -one that matches the frequency being transmitted during the correlation -interval. Because the transmission is totally asynchronous, the demodulation -process must run sample by sample to find the symbol transitions. The -correlation is performed on a sliding window basis, so the computational load of -demodulating sample by sample is not great. - -Two modes of symbol synchronisation are provided: - - - In synchronous mode, symbol transitions are smoothed, to track their true - position in the prescence of high timing jitter. This provides the most - reliable symbol recovery in poor signal to noise conditions. However, it - takes a little time to settle, so it not really suitable for data streams - which must start up instantaneously (e.g. the TDD systems used by hearing - impaired people). - - - In asynchronous mode each transition is taken at face value, with no temporal - smoothing. There is no settling time for this mode, but when the signal to - noise ratio is very poor it does not perform as well as the synchronous mode. -*/ - -#if !defined(_SPANDSP_FSK_H_) -#define _SPANDSP_FSK_H_ - -/*! - FSK modem specification. This defines the frequencies, signal levels and - baud rate (== bit rate for simple FSK) for a single channel of an FSK modem. -*/ -typedef struct -{ - /*! Short text name for the modem. */ - const char *name; - /*! The frequency of the zero bit state, in Hz */ - int freq_zero; - /*! The frequency of the one bit state, in Hz */ - int freq_one; - /*! The transmit power level, in dBm0 */ - int tx_level; - /*! The minimum acceptable receive power level, in dBm0 */ - int min_level; - /*! The bit rate of the modem, in units of 1/100th bps */ - int baud_rate; -} fsk_spec_t; - -/* Predefined FSK modem channels */ -enum -{ - FSK_V21CH1 = 0, - FSK_V21CH2, - FSK_V23CH1, - FSK_V23CH2, - FSK_BELL103CH1, - FSK_BELL103CH2, - FSK_BELL202, - 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 -{ - FSK_FRAME_MODE_ASYNC = 0, - FSK_FRAME_MODE_SYNC = 1, - FSK_FRAME_MODE_5N1_FRAMES = 7, /* 5 bits of data + start bit + stop bit */ - FSK_FRAME_MODE_7N1_FRAMES = 9, /* 7 bits of data + start bit + stop bit */ - FSK_FRAME_MODE_7E1_FRAMES = 10, /* 7 bits of data + even parity + start bit + stop bit */ - FSK_FRAME_MODE_7E2_FRAMES = 11 /* 7 bits of data + even parity + start bit + 2 stop bits */ -}; - -SPAN_DECLARE_DATA extern const fsk_spec_t preset_fsk_specs[]; - -/*! - FSK modem transmit descriptor. This defines the state of a single working - instance of an FSK modem transmitter. -*/ -typedef struct fsk_tx_state_s fsk_tx_state_t; - -/* The longest window will probably be 106 for 75 baud */ -#define FSK_MAX_WINDOW_LEN 128 - -/*! - FSK modem receive descriptor. This defines the state of a single working - instance of an FSK modem receiver. -*/ -typedef struct fsk_rx_state_s fsk_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an FSK modem transmit context. - \brief Initialise an FSK modem transmit context. - \param s The modem context. - \param spec The specification of the modem tones and rate. - \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(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s, - const fsk_spec_t *spec, - get_bit_func_t get_bit, - void *user_data); - -SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec); - -SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s); - -SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s); - -/*! Adjust an FSK modem transmit context's power output. - \brief Adjust an FSK modem transmit context's power output. - \param s The modem context. - \param power The power level, in dBm0 */ -SPAN_DECLARE(void) fsk_tx_power(fsk_tx_state_t *s, float power); - -SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, void *user_data); - -/*! Change the modem status report function associated with an FSK modem transmit context. - \brief Change the modem status report function associated with an FSK modem transmit context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Generate a block of FSK modem audio samples. - \brief Generate a block of FSK modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len); - -/*! Get the current received signal power. - \param s The modem context. - \return The signal power, in dBm0. */ -SPAN_DECLARE(float) fsk_rx_signal_power(fsk_rx_state_t *s); - -/*! Adjust an FSK modem receive context's carrier detect power threshold. - \brief Adjust an FSK modem receive context's carrier detect power threshold. - \param s The modem context. - \param cutoff The power level, in dBm0 */ -SPAN_DECLARE(void) fsk_rx_signal_cutoff(fsk_rx_state_t *s, float cutoff); - -/*! Initialise an FSK modem receive context. - \brief Initialise an FSK modem receive context. - \param s The modem context. - \param spec The specification of the modem tones and rate. - \param framing_mode 0 for fully asynchronous mode. 1 for synchronous mode. >1 for - this many bits per asynchronous character frame. - \param put_bit The callback routine used to put the received data. - \param user_data An opaque pointer. - \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, - const fsk_spec_t *spec, - int framing_mode, - put_bit_func_t put_bit, - void *user_data); - -SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode); - -SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s); - -SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s); - -/*! Process a block of received FSK modem audio samples. - \brief Process a block of received FSK modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len); - -/*! Fake processing of a missing block of received FSK modem audio samples - (e.g due to packet loss). - \brief Fake processing of a missing block of received FSK modem audio samples. - \param s The modem context. - \param len The number of samples to fake. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len); - -SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data); - -/*! Change the modem status report function associated with an FSK modem receive context. - \brief Change the modem status report function associated with an FSK modem receive context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_status_func_t handler, void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/g168models.h b/libs/spandsp/src/spandsp/g168models.h deleted file mode 100644 index 686925c369..0000000000 --- a/libs/spandsp/src/spandsp/g168models.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g168models.h - line models for echo cancellation tests against the G.168 - * spec. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_G168MODELS_H_) -#define _SPANDSP_G168MODELS_H_ - -/*! \page g168_test_data_page The test data from the G.168 specification -*/ - -/*! - The line model from section D.2 of G.168. - - These are the coefficients for the line simulation model defined in - section D.2 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d2_coeffs[] = -{ - -436, -829, -2797, -4208, -17968, -11215, 46150, 34480, - -10427, 9049, -1309, -6320, 390, -8191, -1751, -6051, - -3796, -4055, -3948, -2557, -3372, -1808, -2259, -1300, - -1098, -618, -340, -61, 323, 419, 745, 716, - 946, 880, 1014, 976, 1033, 1091, 1053, 1042, - 794, 831, 899, 716, 390, 313, 304, 304, - 73, -119, -109, -176, -359, -407, -512, -580, - -704, -618, -685, -791, -772, -820, -839, -724 -}; -#define LINE_MODEL_D2_GAIN 1.39E-5f - -/*! - The line model from section D.3 of G.168. - - These are the coefficients for the line simulation model defined in - section D.3 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d3_coeffs[] = -{ - -381, 658, 1730, -51, -3511, -1418, 7660, 8861, - -8106, -21370, -5307, 23064, 24020, 1020, -12374, -16296, - -19524, -7480, 13509, 17115, 13952, 13952, 97, -9326, - -9046, -15208, -9853, -3858, -1979, 6029, 5616, 7214, - 6820, 3935, 3919, 921, 1316, -693, -759, -1517, - -2176, -2028, -2654, -1814, -2077, -1468, -1221, -842, - -463, -298, -68, 64, 493, 723, 789, 954, - 756, 839, 872, 1020, 789, 822, 558, 658, - 476, 377, 377, 262, 97, -68, -183, -232, - -331, -347, -430, -314, -430, -463, -463, -414, - -381, -479, -479, -512, -479, -397, -430, -397, - -298, -265, -249, -216, -249, -265, -166, -232 -}; -#define LINE_MODEL_D3_GAIN 1.44E-5f - -/*! - The line model from section D.4 of G.168. - - These are the coefficients for the line simulation model defined in - section D.4 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d4_coeffs[] = -{ - -448, -436, 2230, 2448, -4178, -7050, 5846, 18581, - 2322, -26261, -16249, 21637, 25649, -2267, -10311, -4693, - -12690, -7428, 14164, 13467, 4438, 8627, 456, -11879, - -6352, -5104, -7496, 3271, 6566, 4277, 11131, 7562, - 1475, 3728, -3525, -7301, -3101, -9269, -6146, -2553, - -6272, 811, 124, 788, 5147, 2172, 5387, 4598, - 3535, 4004, 2311, 2150, 1017, 330, -139, -573, - -1100, -1157, -1180, -1455, -1123, -1386, -1123, -1066, - -1020, -1100, -1008, -1077, -1088, -917, -917, -963, - -814, -871, -734, -642, -562, -356, -379, -345, - -230, -233, -333, -356, -390, -310, -265, -368, - -310, -310, -390, -482, -459, -482, -551, -573 -}; -#define LINE_MODEL_D4_GAIN 1.52E-5f - -/*! - The line model from section D.5 of G.168. - - These are the coefficients for the line simulation model defined in - section D.5 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d5_coeffs[] = -{ - 160, 312, -241, -415, 897, 908, -1326, -1499, - 2405, 3347, -3624, -7733, 4041, 14484, -1477, -21739, - -4470, 25356, 11458, -19696, -11800, 5766, 789, 6633, - 14624, -6975, -17156, -187, 149, 1515, 14907, 4345, - -7128, -2757, -10185, -7083, 6850, 3944, 6969, 8694, - -4068, -3852, -5793, -9371, 453, 1060, 3965, 9463, - 2393, 2784, -892, -7366, -3376, -5847, -2399, 3011, - 1537, 6623, 4205, 1602, 1592, -4752, -3646, -5207, - -5577, -501, -1174, 4041, 5647, 4628, 7252, 2123, - 2654, -881, -4113, -3244, -7289, -3830, -4600, -2508, - 431, -144, 4184, 2372, 4617, 3576, 2382, 2839, - -404, 539, -1803, -1401, -1705, -2269, -783, -1608, - -220, -306, 257, 615, 225, 561, 8, 344, - 127, -57, 182, 41, 203, -111, 95, -79, - 30, 84, -13, -68, -241, -68, -24, 19, - -57, -24, 30, -68, 84, -155, -68, 19 -}; -#define LINE_MODEL_D5_GAIN 1.77E-5f - -/*! - The line model from section D.6 of G.168. - - These are the coefficients for the line simulation model defined in - section D.6 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d6_coeffs[] = -{ - 293, 268, 475, 460, 517, 704, 581, 879, - 573, 896, 604, 787, 561, 538, 440, 97, - 265, -385, 20, -938, -523, -1438, -1134, -1887, - -1727, -1698, -4266, -22548, -43424, 2743, 25897, 7380, - 21499, 11983, 10400, 11667, 3889, 7241, 925, 2018, - -821, -2068, -2236, -4283, -3406, -5022, -4039, -4842, - -4104, -4089, -3582, -2978, -2734, -1805, -1608, -645, - -495, 279, 471, 947, 1186, 1438, 1669, 1640, - 1901, 1687, 1803, 1543, 1566, 1342, 1163, 963, - 733, 665, 323, 221, -14, -107, -279, -379, - -468, -513, -473, -588, -612, -652, -616, -566, - -515, -485, -404, -344, -290, -202, -180, -123 -}; -#define LINE_MODEL_D6_GAIN 9.33E-6f - -/*! - The line model from section D.7 of G.168. - - These are the coefficients for the line simulation model defined in - section D.8 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d7_coeffs[] = -{ - 29, 109, -83, 198, -294, -135, -415, -202, - -444, -337, -313, -450, -105, -503, 145, -490, - 267, -231, 340, 77, 343, 783, 158, 1341, - 195, 1798, 344, 1845, 629, 1604, 1182, 940, - 5163, 19522, 8421, -50953, -9043, 18046, -13553, 13336, - -3471, -107, 1788, -7409, 2469, -7994, 490, -3860, - -837, 490, -636, 3682, 1141, 5019, 2635, 5025, - 3946, 4414, 4026, 3005, 3380, 1616, 2007, 158, - 388, -1198, -1117, -2134, -2547, -2589, -3310, -2778, - -3427, -2779, -3116, -2502, -2399, -1956, -1539, -1239, - -570, -377, 251, 331, 964, 1177, 1449, 1564, - 1724, 1871, 1767, 1802, 1630, 1632, 1379, 1271, - 1063, 856, 711, 482, 289, 54, -137, -321, - -490, -638, -764, -836, -800, -859, -838, -837, - -834, -740, -673, -581, -493, -436, -327, -201 -}; -#define LINE_MODEL_D7_GAIN 1.51E-5f - -/*! - The line model from section D.8 of G.168. - - These are the coefficients for the line simulation model defined in - section D.8 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d8_coeffs[] = -{ - 258, -111, 337, -319, 347, -434, 192, -450, - -108, -343, -596, -177, -1187, -52, -1781, -147, - -1959, -326, -1601, -1389, -13620, -720, 33818, -10683, - -6742, 12489, -9862, 8950, -1574, 758, 3526, -3118, - 2421, -8966, -4901, 11385, 18072, -14410, -7473, 19836, - -16854, -3115, 9483, -17799, 7399, -4342, -7415, 7929, - -10726, 6239, -2526, -1317, 5345, -4565, 6868, -2195, - 3425, 1969, -109, 3963, -1275, 3087, -892, 1239, - 2, -427, 596, -1184, 551, -1244, 141, -743, - -415, -372, -769, -183, -785, -270, -659, -377, - -523, -325, -245, -255, -60, 35, 218, 149, - 340, 233, 365, 303, 251, 230, 209, 179 -}; -#define LINE_MODEL_D8_GAIN 2.33E-5f - -/*! - The line model from section D.9 of G.168. - - These are the coefficients for the line simulation model defined in - section D.9 of G.168. It may be used with the fir32_xxx - routines to build a line simulator. -*/ -const int32_t line_model_d9_coeffs[] = -{ - 80, 31, 4, 42, 42, -61, -81, -64, - -121, -102, -26, 1002, -9250, -22562, 39321, 35681, - -35289, 25312, -1457, -229, 15659, -6786, 16791, 3860, - 2239, -28730, -11885, 33871, -176, -16421, 18173, -9669, - -10163, 9941, -19365, 3592, -5907, -10257, 5336, -12933, - 4348, -4802, -1791, 3035, -4433, 5553, -2596, 3992, - 1255, 1450, 4079, 324, 4340, 1059, 3083, 1917, - 1756, 2478, 1027, 1871, 845, 1284, 813, 806, - 869, 471, 646, 438, 449, 432, 473, 394, - 452, 538, 717, 723, 850, 756, 753, 899, - 555, 669, 619, 500, 650, 615, 516, 492, - 427, 291, 356, 147, 107, -50, -88, -59, - -238, -165, -183 -}; -#define LINE_MODEL_D9_GAIN 1.33E-5f - -/*! - The filter coefficients for the bandpass filter specified for level measurements - in section 6.4.1.2.1 of G.168. -*/ -const float level_measurement_bp_coeffs[] = -{ - 0.0000, 0.0006, 0.0005, 0.0004, 0.0011, - 0.0000, 0.0015, -0.0003, 0.0012, -0.0002, - 0.0000, 0.0002, -0.0020, 0.0005, -0.0040, - 0.0000, -0.0047, -0.0019, -0.0033, -0.0047, - 0.0000, -0.0068, 0.0036, -0.0057, 0.0054, - 0.0000, 0.0044, 0.0095, 0.0017, 0.0188, - 0.0000, 0.0225, 0.0024, 0.0163, 0.0092, - 0.0000, 0.0164, -0.0210, 0.0161, -0.0375, - 0.0000, -0.0406, -0.0357, -0.0267, -0.0871, - 0.0000, -0.1420, 0.0289, -0.1843, 0.0475, - 0.8006, 0.0475, -0.1843, 0.0289, -0.1420, - 0.0000, -0.0871, -0.0267, -0.0357, -0.0406, - 0.0000, -0.0375, 0.0161, -0.0210, 0.0164, - 0.0000, 0.0092, 0.0163, 0.0024, 0.0225, - 0.0000, 0.0188, 0.0017, 0.0095, 0.0044, - 0.0000, 0.0054, -0.0057, 0.0036, -0.0068, - 0.0000, -0.0047, -0.0033, -0.0019, -0.0047, - 0.0000, -0.0040, 0.0005, -0.0020, 0.0002, - 0.0000, -0.0002, 0.0012, -0.0003, 0.0015, - 0.0000, 0.0011, 0.0004, 0.0005, 0.0006, - 0.0000 -}; - -/*! - The composite source signal "voiced" section from table C.1 of G.168. -*/ -const int css_c1[] = -{ - -155, 276, 517, 578, 491, 302, 86, -103, - -207, -198, 60, 190, 543, 948, 1362, 1741, - 2043, 2276, 2422, 2500, 2552, 2595, 2655, 2758, - 2896, 3060, 3224, 3370, 3500, 3569, 3603, 3603, - 3595, 3586, 3595, 3638, 3724, 3819, 3922, 4000, - 4043, 4034, 3974, 3862, 3724, 3577, 3439, 3336, - 3267, 3224, 3198, 3172, 3129, 3043, 2914, 2750, - 2560, 2353, 2155, 1991, 1853, 1750, 1672, 1603, - 1534, 1440, 1310, 1146, 965, 776, 603, 448, - 345, 276, 250, 250, 267, 267, 241, 190, - 103, -9, -138, -267, -388, -491, -569, -638, - -698, -759, -813, -888, -957, -1034, -1103, -1146, - -1181, -1190, -1198, -1215, -1259, -1327, -1457, -1629, - -1853, -2121, -2414, -2707, -3017, -3319, -3612, -3913, - -4224, -4560, -4922, -5301, -5715, -6137, -6560, -6948, - -7301, -7568, -7732, -7758, -7620, -7310, -6810, -6155, - -5344, -4439, -3474, -2508, -1595, -802 -}; - -/*! - The composite source signal "voiced" section from table C.3 of G.168. -*/ -const int css_c3[] = -{ - -198, -112, -9, 103, 233, 388, 543, 724, - 896, 1060, 1233, 1388, 1517, 1638, 1747, 1810, - 1845, 1845, 1802, 1707, 1569, 1379, 1146, 871, - 560, 233, -121, -491, -871, -1250, -1638, -2043, - -2465, -2896, -3345, -3819, -4310, -4810, -5319, -5836, - -6353, -6853, -7353, -7836, -8292, -8715, -9077, -9370, - -9542, -9542, -9361, -8956, -8327, -7465, -6396, -5163, - -3827, -2448, -1103, 155, 1293, 2241, 3034, 3655, - 4138, 4517, 4827, 5094, 5344, 5594, 5827, 6043, - 6215, 6344, 6413, 6422, 6379, 6310, 6215, 6120, - 6051, 6000, 5991, 5991, 6000, 6008, 5991, 5939, - 5853, 5715, 5560, 5387, 5215, 5043, 4879, 4732, - 4586, 4439, 4276, 4086, 3870, 3629, 3370, 3086, - 2801, 2534, 2267, 2034, 1819, 1612, 1422, 1224, - 1026, 819, 603, 388, 181, 9, -181, -328, - -448, -543, -629, -707, -784, -871, -948, -1026, - -1112, -1181, -1241, -1276, -1293, -1302, -1293, -1267, - -1250, -1233, -1224, -1224, -1224, -1224, -1215, -1198, - -1172, -1129, -1077, -1026, -974, -922, -888, -871, - -845, -828, -810, -793, -767, -741, -698, -672, - -638, -603, -595, -586, -595, -603, -621, -629, - -938, -638, -638, -638, -638, -638, -647, -664, - -690, -724, -767, -793, -819, -845, -853, -871, - -879, -888, -896, -922, -948, -974, -1009, -1026, - -1052, -1069, -1077, -1069, -1060, -1060, -1052, -1043, - -1043, -1052, -1060, -1060, -1060, -1052, -1034, -1017, - -991, -957, -931, -905, -888, -862, -845, -819, - -793, -767, -724, -672, -621, -560, -509, -457, - -397, -345, -276, -207, -112 -}; - -/*! - From section 6.4.2.7 of G.168 - Test No. 6 Non-divergence on narrow-band signals. - These tones and tone pairs are each applied for 5 seconds. -*/ -const int tones_6_4_2_7[][2] = -{ - { 697, 0}, - { 941, 0}, - {1336, 0}, - {1633, 0}, - { 697, 1209}, - { 770, 1336}, - { 852, 1477}, - { 941, 1633}, - { 0, 0} -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/g711.h b/libs/spandsp/src/spandsp/g711.h deleted file mode 100644 index fa670c5de7..0000000000 --- a/libs/spandsp/src/spandsp/g711.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g711.h - In line A-law and u-law conversion routines - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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 */ - -/*! \page g711_page A-law and mu-law handling -Lookup tables for A-law and u-law look attractive, until you consider the impact -on the CPU cache. If it causes a substantial area of your processor cache to get -hit too often, cache sloshing will severely slow things down. The main reason -these routines are slow in C, is the lack of direct access to the CPU's "find -the first 1" instruction. A little in-line assembler fixes that, and the -conversion routines can be faster than lookup tables, in most real world usage. -A "find the first 1" instruction is available on most modern CPUs, and is a -much underused feature. - -If an assembly language method of bit searching is not available, these routines -revert to a method that can be a little slow, so the cache thrashing might not -seem so bad :( - -Feel free to submit patches to add fast "find the first 1" support for your own -favourite processor. - -Look up tables are used for transcoding between A-law and u-law, since it is -difficult to achieve the precise transcoding procedure laid down in the G.711 -specification by other means. -*/ - -#if !defined(_SPANDSP_G711_H_) -#define _SPANDSP_G711_H_ - -/*! The A-law alternate mark inversion mask */ -#define G711_ALAW_AMI_MASK 0x55 - -/* The usual values to use on idle channels, to emulate silence */ -/*! Idle value for A-law channels */ -#define G711_ALAW_IDLE_OCTET (0x80 ^ G711_ALAW_AMI_MASK) -/*! Idle value for u-law channels */ -#define G711_ULAW_IDLE_OCTET 0xFF - -enum -{ - G711_ALAW = 0, - G711_ULAW -}; - -/*! - G.711 state - */ -typedef struct g711_state_s g711_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* N.B. It is tempting to use look-up tables for A-law and u-law conversion. - * However, you should consider the cache footprint. - * - * A 64K byte table for linear to x-law and a 512 byte table for x-law to - * linear sound like peanuts these days, and shouldn't an array lookup be - * real fast? No! When the cache sloshes as badly as this one will, a tight - * calculation may be better. The messiest part is normally finding the - * segment, but a little inline assembly can fix that on an i386, x86_64 and - * many other modern processors. - */ - -/* - * Mu-law is basically as follows: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ - -/* Enable the trap as per the MIL-STD */ -//#define G711_ULAW_ZEROTRAP -/*! Bias for u-law encoding from linear. */ -#define G711_ULAW_BIAS 0x84 - -/*! \brief Encode a linear sample to u-law - \param linear The sample to encode. - \return The u-law value. -*/ -static __inline__ uint8_t linear_to_ulaw(int linear) -{ - uint8_t u_val; - int mask; - int seg; - - /* Get the sign and the magnitude of the value. */ - if (linear >= 0) - { - linear = G711_ULAW_BIAS + linear; - mask = 0xFF; - } - else - { - linear = G711_ULAW_BIAS - linear; - mask = 0x7F; - } - - seg = top_bit(linear | 0xFF) - 7; - if (seg >= 8) - { - u_val = (uint8_t) (0x7F ^ mask); - } - else - { - /* Combine the sign, segment, quantization bits, and complement the code word. */ - u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask); - } -#if defined(G711_ULAW_ZEROTRAP) - /* Optional ITU trap */ - if (u_val == 0) - u_val = 0x02; -#endif - return u_val; -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Decode an u-law sample to a linear value. - \param ulaw The u-law sample to decode. - \return The linear value. -*/ -static __inline__ int16_t ulaw_to_linear(uint8_t ulaw) -{ - int t; - - /* Complement to obtain normal u-law value. */ - ulaw = ~ulaw; - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = (((ulaw & 0x0F) << 3) + G711_ULAW_BIAS) << (((int) ulaw & 0x70) >> 4); - return (int16_t) ((ulaw & 0x80) ? (G711_ULAW_BIAS - t) : (t - G711_ULAW_BIAS)); -} -/*- End of function --------------------------------------------------------*/ - -/* - * A-law is basically as follows: - * - * Linear Input Code Compressed Code - * ----------------- --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ - -/*! \brief Encode a linear sample to A-law - \param linear The sample to encode. - \return The A-law value. -*/ -static __inline__ uint8_t linear_to_alaw(int linear) -{ - uint8_t a_val; - int mask; - int seg; - - if (linear >= 0) - { - /* Sign (bit 7) bit = 1 */ - mask = 0x80 | G711_ALAW_AMI_MASK; - } - else - { - /* Sign (bit 7) bit = 0 */ - mask = G711_ALAW_AMI_MASK; - linear = -linear - 1; - } - - /* Convert the scaled magnitude to segment number. */ - seg = top_bit(linear | 0xFF) - 7; - if (seg >= 8) - { - a_val = (uint8_t) (0x7F ^ mask); - } - else - { - /* Combine the sign, segment, and quantization bits. */ - a_val = (uint8_t) (((seg << 4) | ((linear >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask); - } - return a_val; -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Decode an A-law sample to a linear value. - \param alaw The A-law sample to decode. - \return The linear value. -*/ -static __inline__ int16_t alaw_to_linear(uint8_t alaw) -{ - int i; - int seg; - - alaw ^= G711_ALAW_AMI_MASK; - i = ((alaw & 0x0F) << 4); - seg = (((int) alaw & 0x70) >> 4); - if (seg) - i = (i + 0x108) << (seg - 1); - else - i += 8; - return (int16_t) ((alaw & 0x80) ? i : -i); -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711. - \param alaw The A-law sample to transcode. - \return The best matching u-law value. -*/ -SPAN_DECLARE(uint8_t) alaw_to_ulaw(uint8_t alaw); - -/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711. - \param ulaw The u-law sample to transcode. - \return The best matching A-law value. -*/ -SPAN_DECLARE(uint8_t) ulaw_to_alaw(uint8_t ulaw); - -/*! \brief Decode from u-law or A-law to linear. - \param s The G.711 context. - \param amp The linear audio buffer. - \param g711_data The G.711 data. - \param g711_bytes The number of G.711 samples to decode. - \return The number of samples of linear audio produced. -*/ -SPAN_DECLARE(int) g711_decode(g711_state_t *s, - int16_t amp[], - const uint8_t g711_data[], - int g711_bytes); - -/*! \brief Encode from linear to u-law or A-law. - \param s The G.711 context. - \param g711_data The G.711 data. - \param amp The linear audio buffer. - \param len The number of samples to encode. - \return The number of G.711 samples produced. -*/ -SPAN_DECLARE(int) g711_encode(g711_state_t *s, - uint8_t g711_data[], - const int16_t amp[], - int len); - -/*! \brief Transcode between u-law and A-law. - \param s The G.711 context. - \param g711_out The resulting G.711 data. - \param g711_in The original G.711 data. - \param g711_bytes The number of G.711 samples to transcode. - \return The number of G.711 samples produced. -*/ -SPAN_DECLARE(int) g711_transcode(g711_state_t *s, - uint8_t g711_out[], - const uint8_t g711_in[], - int g711_bytes); - -/*! Initialise a G.711 encode or decode context. - \param s The G.711 context. - \param mode The G.711 mode. - \return A pointer to the G.711 context, or NULL for error. */ -SPAN_DECLARE(g711_state_t *) g711_init(g711_state_t *s, int mode); - -/*! Release a G.711 encode or decode context. - \param s The G.711 context. - \return 0 for OK. */ -SPAN_DECLARE(int) g711_release(g711_state_t *s); - -/*! Free a G.711 encode or decode context. - \param s The G.711 context. - \return 0 for OK. */ -SPAN_DECLARE(int) g711_free(g711_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/g722.h b/libs/spandsp/src/spandsp/g722.h deleted file mode 100644 index ee36c456ca..0000000000 --- a/libs/spandsp/src/spandsp/g722.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g722.h - The ITU G.722 codec. - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_G722_H_) -#define _SPANDSP_G722_H_ - -/*! \page g722_page G.722 encoding and decoding -\section g722_page_sec_1 What does it do? -The G.722 module is a bit exact implementation of the ITU G.722 specification for all three -specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests. - -To allow fast and flexible interworking with narrow band telephony, the encoder and decoder -support an option for the linear audio to be an 8k samples/second stream. In this mode the -codec is considerably faster, and still fully compatible with wideband terminals using G.722. - -\section g722_page_sec_2 How does it work? -???. -*/ - -enum -{ - G722_SAMPLE_RATE_8000 = 0x0001, - G722_PACKED = 0x0002 -}; - -/*! - G.722 encode state - */ -typedef struct g722_encode_state_s g722_encode_state_t; - -/*! - G.722 decode state - */ -typedef struct g722_decode_state_s g722_decode_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an G.722 encode context. - \param s The G.722 encode context. - \param rate The required bit rate for the G.722 data. - The valid rates are 64000, 56000 and 48000. - \param options - \return A pointer to the G.722 encode context, or NULL for error. */ -SPAN_DECLARE(g722_encode_state_t *) g722_encode_init(g722_encode_state_t *s, int rate, int options); - -/*! Release a G.722 encode context. - \param s The G.722 encode context. - \return 0 for OK. */ -SPAN_DECLARE(int) g722_encode_release(g722_encode_state_t *s); - -/*! Free a G.722 encode context. - \param s The G.722 encode context. - \return 0 for OK. */ -SPAN_DECLARE(int) g722_encode_free(g722_encode_state_t *s); - -/*! Encode a buffer of linear PCM data to G.722 - \param s The G.722 context. - \param g722_data The G.722 data produced. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of bytes of G.722 data produced. */ -SPAN_DECLARE(int) g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len); - -/*! Initialise an G.722 decode context. - \param s The G.722 decode context. - \param rate The bit rate of the G.722 data. - The valid rates are 64000, 56000 and 48000. - \param options - \return A pointer to the G.722 decode context, or NULL for error. */ -SPAN_DECLARE(g722_decode_state_t *) g722_decode_init(g722_decode_state_t *s, int rate, int options); - -/*! Release a G.722 decode context. - \param s The G.722 decode context. - \return 0 for OK. */ -SPAN_DECLARE(int) g722_decode_release(g722_decode_state_t *s); - -/*! Free a G.722 decode context. - \param s The G.722 decode context. - \return 0 for OK. */ -SPAN_DECLARE(int) g722_decode_free(g722_decode_state_t *s); - -/*! Decode a buffer of G.722 data to linear PCM. - \param s The G.722 context. - \param amp The audio sample buffer. - \param g722_data - \param len - \return The number of samples returned. */ -SPAN_DECLARE(int) g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len); - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/libs/spandsp/src/spandsp/g726.h b/libs/spandsp/src/spandsp/g726.h deleted file mode 100644 index f7c6fd60bf..0000000000 --- a/libs/spandsp/src/spandsp/g726.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g726.h - ITU G.726 codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_G726_H_) -#define _SPANDSP_G726_H_ - -/*! \page g726_page G.726 encoding and decoding -\section g726_page_sec_1 What does it do? - -The G.726 module is a bit exact implementation of the full ITU G.726 specification. -It supports: - - 16 kbps, 24kbps, 32kbps, and 40kbps operation. - - Tandem adjustment, for interworking with A-law and u-law. - - Annex A support, for use in environments not using A-law or u-law. - -It passes the ITU tests. - -\section g726_page_sec_2 How does it work? -???. -*/ - -enum -{ - G726_ENCODING_LINEAR = 0, /* Interworking with 16 bit signed linear */ - G726_ENCODING_ULAW, /* Interworking with u-law */ - G726_ENCODING_ALAW /* Interworking with A-law */ -}; - -enum -{ - G726_PACKING_NONE = 0, - G726_PACKING_LEFT = 1, - G726_PACKING_RIGHT = 2 -}; - -/*! - G.726 state - */ -typedef struct g726_state_s g726_state_t; - -typedef int16_t (*g726_decoder_func_t)(g726_state_t *s, uint8_t code); - -typedef uint8_t (*g726_encoder_func_t)(g726_state_t *s, int16_t amp); - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise a G.726 encode or decode context. - \param s The G.726 context. - \param bit_rate The required bit rate for the ADPCM data. - The valid rates are 16000, 24000, 32000 and 40000. - \param ext_coding The coding used outside G.726. - \param packing One of the G.726_PACKING_xxx options. - \return A pointer to the G.726 context, or NULL for error. */ -SPAN_DECLARE(g726_state_t *) g726_init(g726_state_t *s, int bit_rate, int ext_coding, int packing); - -/*! Release a G.726 encode or decode context. - \param s The G.726 context. - \return 0 for OK. */ -SPAN_DECLARE(int) g726_release(g726_state_t *s); - -/*! Free a G.726 encode or decode context. - \param s The G.726 context. - \return 0 for OK. */ -SPAN_DECLARE(int) g726_free(g726_state_t *s); - -/*! Decode a buffer of G.726 ADPCM data to linear PCM, a-law or u-law. - \param s The G.726 context. - \param amp The audio sample buffer. - \param g726_data - \param g726_bytes - \return The number of samples returned. */ -SPAN_DECLARE(int) g726_decode(g726_state_t *s, - int16_t amp[], - const uint8_t g726_data[], - int g726_bytes); - -/*! Encode a buffer of linear PCM data to G.726 ADPCM. - \param s The G.726 context. - \param g726_data The G.726 data produced. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of bytes of G.726 data produced. */ -SPAN_DECLARE(int) g726_encode(g726_state_t *s, - uint8_t g726_data[], - const int16_t amp[], - int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/gsm0610.h b/libs/spandsp/src/spandsp/gsm0610.h deleted file mode 100644 index e65c7efe26..0000000000 --- a/libs/spandsp/src/spandsp/gsm0610.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610.h - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_GSM0610_H_) -#define _SPANDSP_GSM0610_H_ - -/*! \page gsm0610_page GSM 06.10 encoding and decoding -\section gsm0610_page_sec_1 What does it do? - -The GSM 06.10 module is an version of the widely used GSM FR codec software -available from http://kbs.cs.tu-berlin.de/~jutta/toast.html. This version -was produced since some versions of this codec are not bit exact, or not -very efficient on modern processors. This implementation can use MMX instructions -on Pentium class processors, or alternative methods on other processors. It -passes all the ETSI test vectors. That is, it is a tested bit exact implementation. - -This implementation supports encoded data in one of three packing formats: - - Unpacked, with the 76 parameters of a GSM 06.10 code frame each occupying a - separate byte. (note that none of the parameters exceed 8 bits). - - Packed the the 33 byte per frame, used for VoIP, where 4 bits per frame are wasted. - - Packed in WAV49 format, where 2 frames are packed into 65 bytes. - -\section gsm0610_page_sec_2 How does it work? -???. -*/ - -enum -{ - GSM0610_PACKING_NONE, - GSM0610_PACKING_WAV49, - GSM0610_PACKING_VOIP -}; - -/*! - GSM 06.10 FR codec unpacked frame. -*/ -typedef struct -{ - int16_t LARc[8]; - int16_t Nc[4]; - int16_t bc[4]; - int16_t Mc[4]; - int16_t xmaxc[4]; - int16_t xMc[4][13]; -} gsm0610_frame_t; - -/*! - GSM 06.10 FR codec state descriptor. This defines the state of - a single working instance of the GSM 06.10 FR encoder or decoder. -*/ -typedef struct gsm0610_state_s gsm0610_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise a GSM 06.10 encode or decode context. - \param s The GSM 06.10 context - \param packing One of the GSM0610_PACKING_xxx options. - \return A pointer to the GSM 06.10 context, or NULL for error. */ -SPAN_DECLARE(gsm0610_state_t *) gsm0610_init(gsm0610_state_t *s, int packing); - -/*! Release a GSM 06.10 encode or decode context. - \param s The GSM 06.10 context - \return 0 for success, else -1. */ -SPAN_DECLARE(int) gsm0610_release(gsm0610_state_t *s); - -/*! Free a GSM 06.10 encode or decode context. - \param s The GSM 06.10 context - \return 0 for success, else -1. */ -SPAN_DECLARE(int) gsm0610_free(gsm0610_state_t *s); - -/*! Set the packing format for a GSM 06.10 encode or decode context. - \param s The GSM 06.10 context - \param packing One of the GSM0610_PACKING_xxx options. - \return 0 for success, else -1. */ -SPAN_DECLARE(int) gsm0610_set_packing(gsm0610_state_t *s, int packing); - -/*! Encode a buffer of linear PCM data to GSM 06.10. - \param s The GSM 06.10 context. - \param code The GSM 06.10 data produced. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of bytes of GSM 06.10 data produced. */ -SPAN_DECLARE(int) gsm0610_encode(gsm0610_state_t *s, uint8_t code[], const int16_t amp[], int len); - -/*! Decode a buffer of GSM 06.10 data to linear PCM. - \param s The GSM 06.10 context. - \param amp The audio sample buffer. - \param code The GSM 06.10 data. - \param len The number of bytes of GSM 06.10 data to be decoded. - \return The number of samples returned. */ -SPAN_DECLARE(int) gsm0610_decode(gsm0610_state_t *s, int16_t amp[], const uint8_t code[], int len); - -SPAN_DECLARE(int) gsm0610_pack_none(uint8_t c[], const gsm0610_frame_t *s); - -/*! Pack a pair of GSM 06.10 frames in the format used for wave files (wave type 49). - \param c The buffer for the packed data. This must be at least 65 bytes long. - \param s A pointer to the frames to be packed. - \return The number of bytes generated. */ -SPAN_DECLARE(int) gsm0610_pack_wav49(uint8_t c[], const gsm0610_frame_t *s); - -/*! Pack a GSM 06.10 frames in the format used for VoIP. - \param c The buffer for the packed data. This must be at least 33 bytes long. - \param s A pointer to the frame to be packed. - \return The number of bytes generated. */ -SPAN_DECLARE(int) gsm0610_pack_voip(uint8_t c[], const gsm0610_frame_t *s); - -SPAN_DECLARE(int) gsm0610_unpack_none(gsm0610_frame_t *s, const uint8_t c[]); - -/*! Unpack a pair of GSM 06.10 frames from the format used for wave files (wave type 49). - \param s A pointer to a buffer into which the frames will be packed. - \param c The buffer containing the data to be unpacked. This must be at least 65 bytes long. - \return The number of bytes absorbed. */ -SPAN_DECLARE(int) gsm0610_unpack_wav49(gsm0610_frame_t *s, const uint8_t c[]); - -/*! Unpack a GSM 06.10 frame from the format used for VoIP. - \param s A pointer to a buffer into which the frame will be packed. - \param c The buffer containing the data to be unpacked. This must be at least 33 bytes long. - \return The number of bytes absorbed. */ -SPAN_DECLARE(int) gsm0610_unpack_voip(gsm0610_frame_t *s, const uint8_t c[]); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of include ---------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h deleted file mode 100644 index 1349a57a04..0000000000 --- a/libs/spandsp/src/spandsp/hdlc.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * hdlc.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 */ - -/*! \page hdlc_page HDLC - -\section hdlc_page_sec_1 What does it do? -The HDLC module provides bit stuffing, destuffing, framing and deframing, -according to the HDLC protocol. It also provides 16 and 32 bit CRC generation -and checking services for HDLC frames. - -HDLC may not be a DSP function, but is needed to accompany several DSP components. - -\section hdlc_page_sec_2 How does it work? -*/ - -#if !defined(_SPANDSP_HDLC_H_) -#define _SPANDSP_HDLC_H_ - -/*! - HDLC_MAXFRAME_LEN is the maximum length of a stuffed HDLC frame, excluding the CRC. -*/ -#define HDLC_MAXFRAME_LEN 400 - -typedef void (*hdlc_frame_handler_t)(void *user_data, const uint8_t *pkt, int len, int ok); -typedef void (*hdlc_underflow_handler_t)(void *user_data); - -/*! - HDLC receive descriptor. This contains all the state information for an HDLC receiver. - */ -typedef struct hdlc_rx_state_s hdlc_rx_state_t; - -/*! - HDLC received data statistics. - */ -typedef struct -{ - /*! \brief The number of bytes of good frames received (CRC not included). */ - unsigned long int bytes; - /*! \brief The number of good frames received. */ - unsigned long int good_frames; - /*! \brief The number of frames with CRC errors received. */ - unsigned long int crc_errors; - /*! \brief The number of too short and too long frames received. */ - unsigned long int length_errors; - /*! \brief The number of HDLC aborts received. */ - unsigned long int aborts; -} hdlc_rx_stats_t; - -/*! - HDLC transmit descriptor. This contains all the state information for an - HDLC transmitter. - */ -typedef struct hdlc_tx_state_s hdlc_tx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an HDLC receiver context. - \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 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. - \param handler The function to be called when a good HDLC frame is received. - \param user_data An opaque parameter for the callback routine. - \return A pointer to the HDLC receiver context. -*/ -SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s, - bool crc32, - bool report_bad_frames, - int framing_ok_threshold, - hdlc_frame_handler_t handler, - void *user_data); - -/*! Re-initialise an HDLC receiver context. This does not reset the usage statistics. - \brief Re-initialise an HDLC receiver context. - \param s A pointer to an HDLC receiver context. - \return 0 for success. -*/ -SPAN_DECLARE(int) hdlc_rx_restart(hdlc_rx_state_t *s); - -/*! Change the put_bit function associated with an HDLC receiver context. - \brief Change the put_bit function associated with an HDLC receiver context. - \param s A pointer to an HDLC receiver context. - \param handler The function to be called when a good HDLC frame is received. - \param user_data An opaque parameter for the callback routine. -*/ -SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_handler_t handler, void *user_data); - -/*! Change the status report function associated with an HDLC receiver context. - \brief Change the status report function associated with an HDLC receiver context. - \param s A pointer to an HDLC receiver context. - \param handler The callback routine used to report status changes. - \param user_data An opaque parameter for the callback routine. -*/ -SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Release an HDLC receiver context. - \brief Release an HDLC receiver context. - \param s A pointer to an HDLC receiver context. - \return 0 for OK */ -SPAN_DECLARE(int) hdlc_rx_release(hdlc_rx_state_t *s); - -/*! Free an HDLC receiver context. - \brief Free an HDLC receiver context. - \param s A pointer to an HDLC receiver context. - \return 0 for OK */ -SPAN_DECLARE(int) hdlc_rx_free(hdlc_rx_state_t *s); - -/*! \brief Set the maximum frame length for an HDLC receiver context. - \param s A pointer to an HDLC receiver context. - \param max_len The maximum permitted length of a frame. -*/ -SPAN_DECLARE(void) hdlc_rx_set_max_frame_len(hdlc_rx_state_t *s, size_t max_len); - -/*! \brief Set the octet counting report interval. - \param s A pointer to an HDLC receiver context. - \param interval The interval, in octets. -*/ -SPAN_DECLARE(void) hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s, - int interval); - -/*! \brief Get the current receive statistics. - \param s A pointer to an HDLC receiver context. - \param t A pointer to the buffer for the statistics. - \return 0 for OK, else -1. -*/ -SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s, - hdlc_rx_stats_t *t); - -/*! \brief Put a single bit of data to an HDLC receiver. - \param s A pointer to an HDLC receiver context. - \param new_bit The bit. -*/ -SPAN_DECLARE(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit); - -/*! \brief Put a byte of data to an HDLC receiver. - \param s A pointer to an HDLC receiver context. - \param new_byte The byte of data. -*/ -SPAN_DECLARE(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte); - -/*! \brief Put a series of bytes of data to an HDLC receiver. - \param s A pointer to an HDLC receiver context. - \param buf The buffer of data. - \param len The length of the data in the buffer. -*/ -SPAN_DECLARE(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len); - -/*! Initialise an HDLC transmitter context. - \brief Initialise an HDLC transmitter context. - \param s A pointer to an HDLC transmitter context. - \param crc32 True to use ITU CRC32. False to use ITU CRC16. - \param inter_frame_flags The minimum flag octets to insert between frames (usually one). - \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, - bool crc32, - int inter_frame_flags, - bool progressive, - hdlc_underflow_handler_t handler, - void *user_data); - -/*! Re-initialise an HDLC transmitter context. - \brief Re-initialise an HDLC transmitter context. - \param s A pointer to an HDLC transmitter context. - \return 0 for success. -*/ -SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s); - -/*! Release an HDLC transmitter context. - \brief Release an HDLC transmitter context. - \param s A pointer to an HDLC transmitter context. - \return 0 for OK */ -SPAN_DECLARE(int) hdlc_tx_release(hdlc_tx_state_t *s); - -/*! Free an HDLC transmitter context. - \brief Free an HDLC transmitter context. - \param s A pointer to an HDLC transmitter context. - \return 0 for OK */ -SPAN_DECLARE(int) hdlc_tx_free(hdlc_tx_state_t *s); - -/*! \brief Set the maximum frame length for an HDLC transmitter context. - \param s A pointer to an HDLC transmitter context. - \param max_len The maximum length. -*/ -SPAN_DECLARE(void) hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len); - -/*! \brief Transmit a frame. - \param s A pointer to an HDLC transmitter context. - \param frame A pointer to the frame to be transmitted. - \param len The length of the frame to be transmitted. - \return 0 if the frame was accepted for transmission, else -1. -*/ -SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t len); - -/*! \brief Corrupt the frame currently being transmitted, by giving it the wrong CRC. - \param s A pointer to an HDLC transmitter context. - \return 0 if the frame was corrupted, else -1. -*/ -SPAN_DECLARE(int) hdlc_tx_corrupt_frame(hdlc_tx_state_t *s); - -/*! \brief Transmit a specified quantity of flag octets, typically as a preamble. - \param s A pointer to an HDLC transmitter context. - \param len The length of the required period of flags, in flag octets. If len is zero this - requests that HDLC transmission be terminated when the buffers have fully - drained. - \return 0 if the flags were accepted for transmission, else -1. -*/ -SPAN_DECLARE(int) hdlc_tx_flags(hdlc_tx_state_t *s, int len); - -/*! \brief Send an abort. - \param s A pointer to an HDLC transmitter context. - \return 0 if the frame was aborted, else -1. -*/ -SPAN_DECLARE(int) hdlc_tx_abort(hdlc_tx_state_t *s); - -/*! \brief Get the next bit for transmission. - \param s A pointer to an HDLC transmitter context. - \return The next bit for transmission. -*/ -SPAN_DECLARE(int) hdlc_tx_get_bit(hdlc_tx_state_t *s); - -/*! \brief Get the next byte for transmission. - \param s A pointer to an HDLC transmitter context. - \return The next byte for transmission. -*/ -SPAN_DECLARE(int) hdlc_tx_get_byte(hdlc_tx_state_t *s); - -/*! \brief Get the next sequence of bytes for transmission. - \param s A pointer to an HDLC transmitter context. - \param buf The buffer for the data. - \param max_len The number of bytes to get. - \return The number of bytes actually got. -*/ -SPAN_DECLARE(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/ima_adpcm.h b/libs/spandsp/src/spandsp/ima_adpcm.h deleted file mode 100644 index 2942efa859..0000000000 --- a/libs/spandsp/src/spandsp/ima_adpcm.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * ima_adpcm.h - Conversion routines between linear 16 bit PCM data and - * IMA/DVI/Intel ADPCM format. - * - * 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. - * - * Based on a bit from here, a bit from there, eye of toad, - * ear of bat, etc - plus, of course, my own 2 cents. - */ - -/*! \file */ - -#if !defined(_SPANDSP_IMA_ADPCM_H_) -#define _SPANDSP_IMA_ADPCM_H_ - -/*! \page ima_adpcm_page IMA/DVI/Intel ADPCM encoding and decoding -\section ima_adpcm_page_sec_1 What does it do? -IMA ADPCM offers a good balance of simplicity and quality at a rate of -32kbps. - -\section ima_adpcm_page_sec_2 How does it work? - -\section ima_adpcm_page_sec_3 How do I use it? -*/ - -enum -{ - /*! IMA4 is the original IMA ADPCM variant */ - IMA_ADPCM_IMA4 = 0, - /*! DVI4 is the IMA ADPCM variant defined in RFC3551 */ - IMA_ADPCM_DVI4 = 1, - /*! VDVI is the variable bit rate IMA ADPCM variant defined in RFC3551 */ - IMA_ADPCM_VDVI = 2 -}; - -/*! - IMA (DVI/Intel) ADPCM conversion state descriptor. This defines the state of - a single working instance of the IMA ADPCM converter. This is used for - either linear to ADPCM or ADPCM to linear conversion. -*/ -typedef struct ima_adpcm_state_s ima_adpcm_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an IMA ADPCM encode or decode context. - \param s The IMA ADPCM context. - \param variant IMA_ADPCM_IMA4, IMA_ADPCM_DVI4, or IMA_ADPCM_VDVI. - \param chunk_size The size of a chunk, in samples. A chunk size of - zero sample samples means treat each encode or decode operation - as a chunk. - \return A pointer to the IMA ADPCM context, or NULL for error. */ -SPAN_DECLARE(ima_adpcm_state_t *) ima_adpcm_init(ima_adpcm_state_t *s, - int variant, - int chunk_size); - -/*! Release an IMA ADPCM encode or decode context. - \param s The IMA ADPCM context. - \return 0 for OK. */ -SPAN_DECLARE(int) ima_adpcm_release(ima_adpcm_state_t *s); - -/*! Free an IMA ADPCM encode or decode context. - \param s The IMA ADPCM context. - \return 0 for OK. */ -SPAN_DECLARE(int) ima_adpcm_free(ima_adpcm_state_t *s); - -/*! Encode a buffer of linear PCM data to IMA ADPCM. - \param s The IMA ADPCM context. - \param ima_data The IMA ADPCM data produced. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of bytes of IMA ADPCM data produced. */ -SPAN_DECLARE(int) ima_adpcm_encode(ima_adpcm_state_t *s, - uint8_t ima_data[], - const int16_t amp[], - int len); - -/*! Decode a buffer of IMA ADPCM data to linear PCM. - \param s The IMA ADPCM context. - \param amp The audio sample buffer. - \param ima_data The IMA ADPCM data - \param ima_bytes The number of bytes of IMA ADPCM data - \return The number of samples returned. */ -SPAN_DECLARE(int) ima_adpcm_decode(ima_adpcm_state_t *s, - int16_t amp[], - const uint8_t ima_data[], - int ima_bytes); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/image_translate.h b/libs/spandsp/src/spandsp/image_translate.h deleted file mode 100644 index 087ef3f583..0000000000 --- a/libs/spandsp/src/spandsp/image_translate.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * image_translate.h - Image translation routines for reworking colour - * and gray scale images to be colour, gray scale or - * bi-level images of an appropriate size to be FAX - * compatible. - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_IMAGE_TRANSLATE_H_) -#define _SPANDSP_IMAGE_TRANSLATE_H_ - -/*! \page image_translate_page Image translation -\section image_translate_page_sec_1 What does it do? - -The image translate functions allow an image to be translated and resized between -various colour an monochrome formats. It also allows a colour or gray-scale image -to be reduced to a bi-level monochrome image. This is useful for preparing images -to be sent as traditional bi-level FAX pages. - -\section image_translate_page_sec_2 How does it work? - -\section image_translate_page_sec_3 How do I use it? -*/ - -typedef struct image_translate_state_s image_translate_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Get the next row of a translated image. - \param s The image translation context. - \return the length of the row buffer, in bytes */ -SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], size_t len); - -/*! \brief Get the width of the image being produced by an image translation context. - \param s The image translation context. - \return The width of the output image, in pixel. */ -SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s); - -/*! \brief Get the length of the image being produced by an image translation context. - \param s The image translation context. - \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 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 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 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); - -/*! \brief Release the resources associated with an image translation context. - \param s The image translation context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s); - -/*! \brief Free the resources associated with an image translation context. - \param s The image translation context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/logging.h b/libs/spandsp/src/spandsp/logging.h deleted file mode 100644 index cd0d73355c..0000000000 --- a/libs/spandsp/src/spandsp/logging.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * logging.h - definitions for error and debug logging. - * - * 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. - */ - -/*! \file */ - -/*! \page logging_page Logging -\section logging_page_sec_1 What does it do? -???. -*/ - -#if !defined(_SPANDSP_LOGGING_H_) -#define _SPANDSP_LOGGING_H_ - -/*! Logging function for spandsp logging. */ -typedef void (*message_handler_func_t)(void *user_data, int level, const char *text); - -/* Logging elements */ -enum -{ - SPAN_LOG_SEVERITY_MASK = 0x00FF, - SPAN_LOG_SHOW_DATE = 0x0100, - SPAN_LOG_SHOW_SAMPLE_TIME = 0x0200, - SPAN_LOG_SHOW_SEVERITY = 0x0400, - SPAN_LOG_SHOW_PROTOCOL = 0x0800, - SPAN_LOG_SHOW_VARIANT = 0x1000, - SPAN_LOG_SHOW_TAG = 0x2000, - SPAN_LOG_SUPPRESS_LABELLING = 0x8000 -}; - -/* Logging severity levels */ -enum -{ - SPAN_LOG_NONE = 0, - SPAN_LOG_ERROR = 1, - SPAN_LOG_WARNING = 2, - SPAN_LOG_PROTOCOL_ERROR = 3, - SPAN_LOG_PROTOCOL_WARNING = 4, - SPAN_LOG_FLOW = 5, - SPAN_LOG_FLOW_2 = 6, - SPAN_LOG_FLOW_3 = 7, - SPAN_LOG_DEBUG = 8, - SPAN_LOG_DEBUG_2 = 9, - SPAN_LOG_DEBUG_3 = 10 -}; - -/*! - Logging descriptor. This defines the working state for a single instance of - the logging facility for spandsp. -*/ -typedef struct logging_state_s logging_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Test if logging of a specified severity level is enabled. - \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. -*/ -SPAN_DECLARE(bool) span_log_test(logging_state_t *s, int level); - -/*! Generate a log entry. - \brief Generate a log entry. - \param s The logging context. - \param level The severity level of the entry. - \param format ??? - \return 0 if no output generated, else 1. -*/ -SPAN_DECLARE(int) span_log(logging_state_t *s, int level, const char *format, ...); - -/*! Generate a log entry displaying the contents of a buffer. - \brief Generate a log entry displaying the contents of a buffer - \param s The logging context. - \param level The severity level of the entry. - \param tag A label for the log entry. - \param buf The buffer to be dumped to the log. - \param len The length of buf. - \return 0 if no output generated, else 1. -*/ -SPAN_DECLARE(int) span_log_buf(logging_state_t *s, int level, const char *tag, const uint8_t *buf, int len); - -SPAN_DECLARE(int) span_log_get_level(logging_state_t *s); - -SPAN_DECLARE(int) span_log_set_level(logging_state_t *s, int level); - -SPAN_DECLARE(const char *) span_log_get_tag(logging_state_t *s); - -SPAN_DECLARE(int) span_log_set_tag(logging_state_t *s, const char *tag); - -SPAN_DECLARE(const char *) span_log_get_protocol(logging_state_t *s); - -SPAN_DECLARE(int) span_log_set_protocol(logging_state_t *s, const char *protocol); - -SPAN_DECLARE(int) span_log_set_sample_rate(logging_state_t *s, int samples_per_second); - -SPAN_DECLARE(int) span_log_bump_samples(logging_state_t *s, int samples); - -SPAN_DECLARE(void) span_log_set_message_handler(logging_state_t *s, message_handler_func_t func, void *user_data); - -SPAN_DECLARE(void) span_set_message_handler(message_handler_func_t func, void *user_data); - -SPAN_DECLARE(logging_state_t *) span_log_init(logging_state_t *s, int level, const char *tag); - -SPAN_DECLARE(int) span_log_release(logging_state_t *s); - -SPAN_DECLARE(int) span_log_free(logging_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/lpc10.h b/libs/spandsp/src/spandsp/lpc10.h deleted file mode 100644 index b3202cc1cb..0000000000 --- a/libs/spandsp/src/spandsp/lpc10.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10.h - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_LPC10_H_) -#define _SPANDSP_LPC10_H_ - -/*! \page lpc10_page LPC10 encoding and decoding -\section lpc10_page_sec_1 What does it do? -The LPC10 module implements the US Department of Defense LPC10 -codec. This codec produces compressed data at 2400bps. At such -a low rate high fidelity cannot be expected. However, the speech -clarity is quite good, and this codec is unencumbered by patent -or other restrictions. - -\section lpc10_page_sec_2 How does it work? -???. -*/ - -#define LPC10_SAMPLES_PER_FRAME 180 -#define LPC10_BITS_IN_COMPRESSED_FRAME 54 - -/*! - LPC10 codec unpacked frame. -*/ -typedef struct -{ - /*! Pitch */ - int32_t ipitch; - /*! Energy */ - int32_t irms; - /*! Reflection coefficients */ - int32_t irc[10]; -} lpc10_frame_t; - -/*! - LPC10 codec encoder state descriptor. This defines the state of - a single working instance of the LPC10 encoder. -*/ -typedef struct lpc10_encode_state_s lpc10_encode_state_t; - -/*! - LPC10 codec decoder state descriptor. This defines the state of - a single working instance of the LPC10 decoder. -*/ -typedef struct lpc10_decode_state_s lpc10_decode_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an LPC10e encode context. - \param s The LPC10e context - \param error_correction ??? - \return A pointer to the LPC10e context, or NULL for error. */ -SPAN_DECLARE(lpc10_encode_state_t *) lpc10_encode_init(lpc10_encode_state_t *s, int error_correction); - -SPAN_DECLARE(int) lpc10_encode_release(lpc10_encode_state_t *s); - -SPAN_DECLARE(int) lpc10_encode_free(lpc10_encode_state_t *s); - -/*! Encode a buffer of linear PCM data to LPC10e. - \param s The LPC10e context. - \param ima_data The LPC10e data produced. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. This must be a multiple of 180, as - this is the number of samples on a frame. - \return The number of bytes of LPC10e data produced. */ -SPAN_DECLARE(int) lpc10_encode(lpc10_encode_state_t *s, uint8_t code[], const int16_t amp[], int len); - -/*! Initialise an LPC10e decode context. - \param s The LPC10e context - \param error_correction ??? - \return A pointer to the LPC10e context, or NULL for error. */ -SPAN_DECLARE(lpc10_decode_state_t *) lpc10_decode_init(lpc10_decode_state_t *st, int error_correction); - -SPAN_DECLARE(int) lpc10_decode_release(lpc10_decode_state_t *s); - -SPAN_DECLARE(int) lpc10_decode_free(lpc10_decode_state_t *s); - -/*! Decode a buffer of LPC10e data to linear PCM. - \param s The LPC10e context. - \param amp The audio sample buffer. - \param code The LPC10e data. - \param len The number of bytes of LPC10e data to be decoded. This must be a multiple of 7, - as each frame is packed into 7 bytes. - \return The number of samples returned. */ -SPAN_DECLARE(int) lpc10_decode(lpc10_decode_state_t *s, int16_t amp[], const uint8_t code[], int len); - - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of include ---------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/math_fixed.h b/libs/spandsp/src/spandsp/math_fixed.h deleted file mode 100644 index 5bc94382ed..0000000000 --- a/libs/spandsp/src/spandsp/math_fixed.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * math_fixed.h - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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(_MATH_FIXED_H_) -#define _MATH_FIXED_H_ - -/*! \page math_fixed_page Fixed point math functions - -\section math_fixed_page_sec_1 What does it do? - -\section math_fixed_page_sec_2 How does it work? -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(uint16_t) sqrtu32_u16(uint32_t x); -#endif - -SPAN_DECLARE(uint16_t) fixed_reciprocal16(uint16_t x, int *shift); - -SPAN_DECLARE(uint16_t) fixed_divide16(uint16_t y, uint16_t x); - -SPAN_DECLARE(uint16_t) fixed_divide32(uint32_t y, uint16_t x); - -SPAN_DECLARE(int16_t) fixed_log10_16(uint16_t x); - -SPAN_DECLARE(int32_t) fixed_log10_32(uint32_t x); - -SPAN_DECLARE(uint16_t) fixed_sqrt16(uint16_t x); - -SPAN_DECLARE(uint16_t) fixed_sqrt32(uint32_t x); - -/*! Evaluate an approximate 16 bit fixed point sine. - \brief Evaluate an approximate 16 bit fixed point sine. - \param x A 16 bit unsigned angle, in 360/65536 degree steps. - \return sin(x)*32767. */ -SPAN_DECLARE(int16_t) fixed_sin(uint16_t x); - -/*! Evaluate an approximate 16 bit fixed point cosine. - \brief Evaluate an approximate 16 bit fixed point cosine. - \param x A 16 bit unsigned angle, in 360/65536 degree steps. - \return cos(x)*32767. */ -SPAN_DECLARE(int16_t) fixed_cos(uint16_t x); - -/*! Evaluate an approximate 16 bit fixed point sine. - \brief Evaluate an approximate 16 bit fixed point sine. - \param y . - \param x . - \return The 16 bit unsigned angle, in 360/65536 degree steps. */ -SPAN_DECLARE(uint16_t) fixed_atan2(int16_t y, int16_t x); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/modem_connect_tones.h b/libs/spandsp/src/spandsp/modem_connect_tones.h deleted file mode 100644 index bbfc6f3b97..0000000000 --- a/libs/spandsp/src/spandsp/modem_connect_tones.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_connect_tones.c - Generation and detection of tones - * associated with modems calling and - * answering calls. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_MODEM_CONNECT_TONES_H_) -#define _SPANDSP_MODEM_CONNECT_TONES_H_ - -/*! \page modem_connect_tones_page Modem connect tone detection - -\section modem_connect_tones_page_sec_1 What does it do? -Some telephony terminal equipment, such as modems, require a channel which is as -clear as possible. They use their own echo cancellation. If the network is also -performing echo cancellation the two cancellors can end up squabbling about the -nature of the channel, with bad results. A special tone is defined which should -cause the network to disable any echo cancellation processes. This is the echo -canceller disable tone. - -The tone detector's design assumes the channel is free of any DC component. - -\section modem_connect_tones_page_sec_2 How does it work? -A sharp notch filter is implemented as a single bi-quad section. The presence of -the 2100Hz disable tone is detected by comparing the notched filtered energy -with the unfiltered energy. If the notch filtered energy is much lower than the -unfiltered energy, then a large proportion of the energy must be at the notch -frequency. This type of detector may seem less intuitive than using a narrow -bandpass filter to isolate the energy at the notch freqency. However, a sharp -bandpass implemented as an IIR filter rings badly. The reciprocal notch filter -is very well behaved for our purpose. -*/ - -enum -{ - /*! \brief This is reported when a tone stops. */ - MODEM_CONNECT_TONES_NONE = 0, - /*! \brief CNG tone is a pure 1100Hz tone, in 0.5s bursts, with 3s silences in between. The - bursts repeat for as long as is required. */ - MODEM_CONNECT_TONES_FAX_CNG = 1, - /*! \brief ANS tone is a pure continuous 2100Hz+-15Hz tone for 3.3s+-0.7s. */ - MODEM_CONNECT_TONES_ANS = 2, - /*! \brief ANS with phase reversals tone is a 2100Hz+-15Hz tone for 3.3s+-0.7s, with a 180 degree - phase jump every 450ms+-25ms. */ - MODEM_CONNECT_TONES_ANS_PR = 3, - /*! \brief The ANSam tone is a version of ANS with 20% of 15Hz+-0.1Hz AM modulation, as per V.8 */ - MODEM_CONNECT_TONES_ANSAM = 4, - /*! \brief The ANSam with phase reversals tone is a version of ANS_PR with 20% of 15Hz+-0.1Hz AM - modulation, as per V.8 */ - MODEM_CONNECT_TONES_ANSAM_PR = 5, - /*! \brief FAX preamble in a string of V.21 HDLC flag octets. */ - MODEM_CONNECT_TONES_FAX_PREAMBLE = 6, - /*! \brief CED tone is the same as ANS tone. FAX preamble in a string of V.21 HDLC flag octets. - This is only valid as a tone type to receive. It is never reported as a detected tone - type. The report will either be for FAX preamble or CED/ANS tone. */ - MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE = 7, - /*! \brief Bell ANS tone is a pure continuous 2225Hz+-15Hz tone for 3.3s+-0.7s. */ - MODEM_CONNECT_TONES_BELL_ANS = 8, - /*! \brief Calling tone is a pure 1300Hz tone, in 0.6s bursts, with 2s silences in between. The - bursts repeat for as long as is required. */ - MODEM_CONNECT_TONES_CALLING_TONE = 9 -}; - -/*! \brief FAX CED tone is the same as ANS tone. */ -#define MODEM_CONNECT_TONES_FAX_CED MODEM_CONNECT_TONES_ANS - -/*! - Modem connect tones generator descriptor. This defines the state - of a single working instance of the tone generator. -*/ -typedef struct modem_connect_tones_tx_state_s modem_connect_tones_tx_state_t; - -/*! - Modem connect tones receiver descriptor. This defines the state - of a single working instance of the tone detector. -*/ -typedef struct modem_connect_tones_rx_state_s modem_connect_tones_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Initialise an instance of the modem connect tones generator. - \param s The context. -*/ -SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem_connect_tones_tx_state_t *s, - int tone_type); - -/*! \brief Release an instance of the modem connect tones generator. - \param s The context. - \return 0 for OK, else -1. -*/ -SPAN_DECLARE(int) modem_connect_tones_tx_release(modem_connect_tones_tx_state_t *s); - -/*! \brief Free an instance of the modem connect tones generator. - \param s The context. - \return 0 for OK, else -1. -*/ -SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s); - -/*! \brief Generate a block of modem connect tones samples. - \param s The context. - \param amp An array of signal samples. - \param len The number of samples to generate. - \return The number of samples generated. -*/ -SPAN_DECLARE(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s, - int16_t amp[], - int len); - -/*! \brief Process a block of samples through an instance of the modem connect - tones detector. - \param s The context. - \param amp An array of signal samples. - \param len The number of samples in the array. - \return The number of unprocessed samples. -*/ -SPAN_DECLARE(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s, - const int16_t amp[], - int len); - -/*! Fake processing of a missing block of received modem connect tone samples - (e.g due to packet loss). - \brief Fake processing of a missing block of received modem connect tone samples. - \param s The context. - \param len The number of samples to fake. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len); - -/*! \brief Test if a modem_connect tone has been detected. - \param s The context. - \return The code for the detected tone. -*/ -SPAN_DECLARE(int) modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s); - -/*! \brief Initialise an instance of the modem connect tones detector. - \param s The context. - \param tone_type The type of connect tone being tested for. - \param tone_callback An optional callback routine, used to report tones - \param user_data An opaque pointer passed to the callback routine, - \return A pointer to the context. -*/ -SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem_connect_tones_rx_state_t *s, - int tone_type, - tone_report_func_t tone_callback, - void *user_data); - -/*! \brief Release an instance of the modem connect tones detector. - \param s The context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) modem_connect_tones_rx_release(modem_connect_tones_rx_state_t *s); - -/*! \brief Free an instance of the modem connect tones detector. - \param s The context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) modem_connect_tones_rx_free(modem_connect_tones_rx_state_t *s); - -SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/modem_echo.h b/libs/spandsp/src/spandsp/modem_echo.h deleted file mode 100644 index 2f19f0bd18..0000000000 --- a/libs/spandsp/src/spandsp/modem_echo.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_echo.h - An echo cancellor, suitable for electrical echos in GSTN modems - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 2004 Steve Underwood - * - * Based on a bit from here, a bit from there, eye of toad, - * ear of bat, etc - plus, of course, my own 2 cents. - * - * 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_MODEM_ECHO_H_) -#define _SPANDSP_MODEM_ECHO_H_ - -/*! \page modem_echo_can_page Line echo cancellation for modems - -\section modem_echo_can_page_sec_1 What does it do? -This module aims to cancel electrical echoes (e.g. from 2-4 wire hybrids) -in modem applications. It is not very suitable for speech applications, which -require additional refinements for satisfactory performance. It is, however, more -efficient and better suited to modem applications. - -\section modem_echo_can_page_sec_2 How does it work? -The heart of the echo cancellor is an adaptive FIR filter. This is adapted to -match the impulse response of the environment being cancelled. It must be long -enough to adequately cover the duration of that impulse response. The signal -being transmitted into the environment being cancelled is passed through the -FIR filter. The resulting output is an estimate of the echo signal. This is -then subtracted from the received signal, and the result should be an estimate -of the signal which originates within the environment being cancelled (people -talking in the room, or the signal from the far end of a telephone line) free -from the echos of our own transmitted signal. - -The FIR filter is adapted using the least mean squares (LMS) algorithm. This -algorithm is attributed to Widrow and Hoff, and was introduced in 1960. It is -the commonest form of filter adaption used in things like modem line equalisers -and line echo cancellers. It works very well if the signal level is constant, -which is true for a modem signal. To ensure good performa certain conditions must -be met: - - - The transmitted signal has weak self-correlation. - - There is no signal being generated within the environment being cancelled. - -The difficulty is that neither of these can be guaranteed. If the adaption is -performed while transmitting noise (or something fairly noise like, such as -voice) the adaption works very well. If the adaption is performed while -transmitting something highly correlative (e.g. tones, like DTMF), the adaption -can go seriously wrong. The reason is there is only one solution for the -adaption on a near random signal. For a repetitive signal, there are a number of -solutions which converge the adaption, and nothing guides the adaption to choose -the correct one. - -\section modem_echo_can_page_sec_3 How do I use it? -The echo cancellor processes both the transmit and receive streams sample by -sample. The processing function is not declared inline. Unfortunately, -cancellation requires many operations per sample, so the call overhead is only a -minor burden. -*/ - -#include "fir.h" - -/*! - Modem line echo canceller descriptor. This defines the working state for a line - echo canceller. -*/ -typedef struct modem_echo_can_state_s modem_echo_can_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Create a modem echo canceller context. - \param len The length of the canceller, in samples. - eturn The new canceller context, or NULL if the canceller could not be created. -*/ -SPAN_DECLARE(modem_echo_can_state_t *) modem_echo_can_init(int len); - -/*! Free a modem echo canceller context. - \param ec The echo canceller context. -*/ -SPAN_DECLARE(void) modem_echo_can_free(modem_echo_can_state_t *ec); - -/*! Flush (reinitialise) a modem echo canceller context. - \param ec The echo canceller context. -*/ -SPAN_DECLARE(void) modem_echo_can_flush(modem_echo_can_state_t *ec); - -/*! Set the adaption mode of a modem echo canceller context. - \param ec The echo canceller context. - \param adapt The mode. -*/ -SPAN_DECLARE(void) modem_echo_can_adaption_mode(modem_echo_can_state_t *ec, int adapt); - -/*! Process a sample through a modem echo canceller. - \param ec The echo canceller context. - \param tx The transmitted audio sample. - \param rx The received audio sample. - eturn The clean (echo cancelled) received sample. -*/ -SPAN_DECLARE(int16_t) modem_echo_can_update(modem_echo_can_state_t *ec, int16_t tx, int16_t rx); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/noise.h b/libs/spandsp/src/spandsp/noise.h deleted file mode 100644 index ef867e3f02..0000000000 --- a/libs/spandsp/src/spandsp/noise.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * noise.h - A low complexity audio noise generator, suitable for - * real time generation (current just approx AWGN) - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_NOISE_H_) -#define _SPANDSP_NOISE_H_ - -/*! \page noise_page Noise generation - -\section noise_page_sec_1 What does it do? -It generates audio noise. Currently it only generates reasonable quality -AWGN. It is designed to be of sufficiently low complexity to generate large -volumes of reasonable quality noise, in real time. - -Hoth noise is used to model indoor ambient noise when evaluating communications -systems such as telephones. It is named after D.F. Hoth, who made the first -systematic study of this. The official definition of Hoth noise is IEEE -standard 269-2001 (revised from 269-1992), "Draft Standard Methods for Measuring -Transmission Performance of Analog and Digital Telephone Sets, Handsets and Headsets." - -The table below gives the spectral density of Hoth noise, adjusted in level to produce -a reading of 50 dBA. - -Freq (Hz) Spectral Bandwidth Total power in - density 10 log_f each 1/3 octave band - (dB SPL/Hz) (dB) (dB SPL) - 100 32.4 13.5 45.9 - 125 30.9 14.7 45.5 - 160 29.1 15.7 44.9 - 200 27.6 16.5 44.1 - 250 26.0 17.6 43.6 - 315 24.4 18.7 43.1 - 400 22.7 19.7 42.3 - 500 21.1 20.6 41.7 - 630 19.5 21.7 41.2 - 800 17.8 22.7 40.4 -1000 16.2 23.5 39.7 -1250 14.6 24.7 39.3 -1600 12.9 25.7 38.7 -2000 11.3 26.5 37.8 -2500 9.6 27.6 37.2 -3150 7.8 28.7 36.5 -4000 5.4 29.7 34.8 -5000 2.6 30.6 33.2 -6300 -1.3 31.7 30.4 -8000 -6.6 32.7 26.0 - -The tolerance for each 1/3rd octave band is ¡Ó3dB. - -\section awgn_page_sec_2 How does it work? -The central limit theorem says if you add a few random numbers together, -the result starts to look Gaussian. In this case we sum 8 random numbers. -The result is fast, and perfectly good as a noise source for many purposes. -It should not be trusted as a high quality AWGN generator, for elaborate -modelling purposes. -*/ - -enum -{ - NOISE_CLASS_AWGN = 1, - NOISE_CLASS_HOTH -}; - -/*! - Noise generator descriptor. This contains all the state information for an instance - of the noise generator. - */ -typedef struct noise_state_s noise_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an audio noise generator. - \brief Initialise an audio noise generator. - \param s The noise generator context. - \param seed A seed for the underlying random number generator. - \param level The noise power level in dBmO. - \param class_of_noise The class of noise (e.g. AWGN). - \param quality A parameter which permits speed and accuracy of the noise - generation to be adjusted. - \return A pointer to the noise generator context. -*/ -SPAN_DECLARE(noise_state_t *) noise_init_dbm0(noise_state_t *s, int seed, float level, int class_of_noise, int quality); - -SPAN_DECLARE(noise_state_t *) noise_init_dbov(noise_state_t *s, int seed, float level, int class_of_noise, int quality); - -SPAN_DECLARE(int) noise_release(noise_state_t *s); - -SPAN_DECLARE(int) noise_free(noise_state_t *s); - -/*! Generate a sample of audio noise. - \brief Generate a sample of audio noise. - \param s The noise generator context. - \return The generated sample. -*/ -SPAN_DECLARE(int16_t) noise(noise_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/oki_adpcm.h b/libs/spandsp/src/spandsp/oki_adpcm.h deleted file mode 100644 index 4b99a93358..0000000000 --- a/libs/spandsp/src/spandsp/oki_adpcm.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * oki_adpcm.h - Conversion routines between linear 16 bit PCM data and - * OKI (Dialogic) ADPCM format. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_OKI_ADPCM_H_) -#define _SPANDSP_OKI_ADPCM_H_ - -/*! \page okiadpcm_page OKI (Dialogic) ADPCM encoding and decoding -\section okiadpcm_page_sec_1 What does it do? -OKI ADPCM is widely used in the CTI industry because it is the principal format -supported by Dialogic. As the market leader, they tend to define "common -practice". It offers a good balance of simplicity and quality at rates of -24kbps or 32kbps. 32kbps is obtained by ADPCM compressing 8k samples/second linear -PCM. 24kbps is obtained by resampling to 6k samples/second and using the same ADPCM -compression algorithm on the slower samples. - -The algorithms for this ADPCM codec can be found in "PC Telephony - The complete guide -to designing, building and programming systems using Dialogic and Related Hardware" -by Bob Edgar. pg 272-276. */ - -/*! - Oki (Dialogic) ADPCM conversion state descriptor. This defines the state of - a single working instance of the Oki ADPCM converter. This is used for - either linear to ADPCM or ADPCM to linear conversion. -*/ -typedef struct oki_adpcm_state_s oki_adpcm_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise an Oki ADPCM encode or decode context. - \param s The Oki ADPCM context. - \param bit_rate The required bit rate for the ADPCM data. - The valid rates are 24000 and 32000. - \return A pointer to the Oki ADPCM context, or NULL for error. */ -SPAN_DECLARE(oki_adpcm_state_t *) oki_adpcm_init(oki_adpcm_state_t *s, - int bit_rate); - -/*! Release an Oki ADPCM encode or decode context. - \param s The Oki ADPCM context. - \return 0 for OK. */ -SPAN_DECLARE(int) oki_adpcm_release(oki_adpcm_state_t *s); - -/*! Free an Oki ADPCM encode or decode context. - \param s The Oki ADPCM context. - \return 0 for OK. */ -SPAN_DECLARE(int) oki_adpcm_free(oki_adpcm_state_t *s); - -/*! Decode a buffer of Oki ADPCM data to linear PCM. - \param s The Oki ADPCM context. - \param amp The audio sample buffer. - \param oki_data - \param oki_bytes - \return The number of samples returned. */ -SPAN_DECLARE(int) oki_adpcm_decode(oki_adpcm_state_t *s, - int16_t amp[], - const uint8_t oki_data[], - int oki_bytes); - -/*! Encode a buffer of linear PCM data to Oki ADPCM. - \param s The Oki ADPCM context. - \param oki_data The Oki ADPCM data produced - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of bytes of Oki ADPCM data produced. */ -SPAN_DECLARE(int) oki_adpcm_encode(oki_adpcm_state_t *s, - uint8_t oki_data[], - const int16_t amp[], - int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/playout.h b/libs/spandsp/src/spandsp/playout.h deleted file mode 100644 index 8e038086df..0000000000 --- a/libs/spandsp/src/spandsp/playout.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * 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_PLAYOUT_H_) -#define _SPANDSP_PLAYOUT_H_ - -/*! \page playout_page Play-out (jitter buffering) -\section playout_page_sec_1 What does it do? -The play-out module provides a static or dynamic length buffer for received frames of -audio or video data. It's goal is to maximise the receiver's tolerance of jitter in the -timing of the received frames. - -Dynamic buffers are generally good for speech, since they adapt to provide the smallest delay -consistent with a low rate of packets arriving too late to be used. For things like FoIP and -MoIP, a static length of buffer is normally necessary. Any attempt to elastically change the -buffer length would wreck a modem's data flow. -*/ - -/* Return codes */ -enum -{ - PLAYOUT_OK = 0, - PLAYOUT_ERROR, - PLAYOUT_EMPTY, - PLAYOUT_NOFRAME, - PLAYOUT_FILLIN, - PLAYOUT_DROP -}; - -/* Frame types */ -#define PLAYOUT_TYPE_CONTROL 0 -#define PLAYOUT_TYPE_SILENCE 1 -#define PLAYOUT_TYPE_SPEECH 2 - -typedef int timestamp_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 playout_state_s playout_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Queue a frame - \param s The play-out context. - \param data The frame data. - \param sender_len Length of frame (for voice) in timestamp units. - \param sender_stamp Sending end's time stamp. - \param receiver_stamp Local time at which packet was received, in timestamp units. - \return One of - PLAYOUT_OK: Frame queued OK. - PLAYOUT_ERROR: Some problem occured - e.g. out of memory. */ -SPAN_DECLARE(int) playout_put(playout_state_t *s, void *data, int type, timestamp_t sender_len, timestamp_t sender_stamp, timestamp_t receiver_stamp); - -/*! Get the next frame. - \param s The play-out context. - \param frame The frame. - \param sender_stamp The sender's timestamp. - \return One of - PLAYOUT_OK: Suitable frame found. - PLAYOUT_DROP: A frame which should be dropped was found (e.g. it arrived too late). - The caller should request the same time again when this occurs. - PLAYOUT_NOFRAME: There's no frame scheduled for this time. - PLAYOUT_FILLIN: Synthetic signal must be generated, as no real data is available for - this time (either we need to grow, or there was a lost frame). - PLAYOUT_EMPTY: The buffer is empty. - */ -SPAN_DECLARE(int) playout_get(playout_state_t *s, playout_frame_t *frame, timestamp_t sender_stamp); - -/*! Unconditionally get the first buffered frame. This may be used to clear out the queue, and free - all its contents, before the context is freed. - \param s The play-out context. - \return The frame, or NULL is the queue is empty. */ -SPAN_DECLARE(playout_frame_t *) playout_get_unconditional(playout_state_t *s); - -/*! Find the current length of the buffer. - \param s The play-out context. - \return The length of the buffer. */ -SPAN_DECLARE(timestamp_t) playout_current_length(playout_state_t *s); - -/*! Find the time at which the next queued frame is due to play. - Note: This value may change backwards as freshly received out of order frames are - added to the buffer. - \param s The play-out context. - \return The next timestamp. */ -SPAN_DECLARE(timestamp_t) playout_next_due(playout_state_t *s); - -/*! Reset an instance of play-out buffering. - NOTE: The buffer should be empty before you call this function, otherwise - you will leak queued frames, and some internal structures - \param s The play-out context. - \param min_length Minimum length of the buffer, in samples. - \param max_length Maximum length of the buffer, in samples. If this equals min_length, static - length buffering is used. */ -SPAN_DECLARE(void) playout_restart(playout_state_t *s, int min_length, int max_length); - -/*! Create a new instance of play-out buffering. - \param min_length Minimum length of the buffer, in samples. - \param max_length Maximum length of the buffer, in samples. If this equals min_length, static - length buffering is used. - \return The new context */ -SPAN_DECLARE(playout_state_t *) playout_init(int min_length, int max_length); - -/*! Release an instance of play-out buffering. - \param s The play-out context to be releaased - \return 0 if OK, else -1 */ -SPAN_DECLARE(int) playout_release(playout_state_t *s); - -/*! Free an instance of play-out buffering. - \param s The play-out context to be destroyed - \return 0 if OK, else -1 */ -SPAN_DECLARE(int) playout_free(playout_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/plc.h b/libs/spandsp/src/spandsp/plc.h deleted file mode 100644 index 2c2f7ca3fa..0000000000 --- a/libs/spandsp/src/spandsp/plc.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * 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_PLC_H_) -#define _SPANDSP_PLC_H_ - -/*! \page plc_page Packet loss concealment -\section plc_page_sec_1 What does it do? -The packet loss concealment module provides a synthetic fill-in signal, to minimise -the audible effect of lost packets in VoIP applications. It is not tied to any -particular codec, and could be used with almost any codec which does not -specify its own procedure for packet loss concealment. - -Where a codec specific concealment procedure exists, that algorithm is usually built -around knowledge of the characteristics of the particular codec. It will, therefore, -generally give better results for that particular codec than this generic concealer will. - -The PLC code implements an algorithm similar to the one described in Appendix 1 of G.711. -However, the G.711 algorithm is optimised for 10ms packets. Few people use such small -packets. 20ms is a much more common value, and longer packets are also quite common. The -algorithm has been adjusted with this in mind. Also, the G.711 approach causes an -algorithmic delay, and requires significant buffer manipulation when there is no packet -loss. The algorithm used here avoids this. It causes no delay, and achieves comparable -quality with normal speech. - -Note that both this algorithm, and the one in G.711 are optimised for speech. For most kinds -of music a much slower decay on bursts of lost packets give better results. - -\section plc_page_sec_2 How does it work? -While good packets are being received, the plc_rx() routine keeps a record of the trailing -section of the known speech signal. If a packet is missed, plc_fillin() is called to produce -a synthetic replacement for the real speech signal. The average mean difference function -(AMDF) is applied to the last known good signal, to determine its effective pitch. -Based on this, the last pitch period of signal is saved. Essentially, this cycle of speech -will be repeated over and over until the real speech resumes. However, several refinements -are needed to obtain smooth pleasant sounding results. - -- The two ends of the stored cycle of speech will not always fit together smoothly. This can - cause roughness, or even clicks, at the joins between cycles. To soften this, the - 1/4 pitch period of real speech preceeding the cycle to be repeated is blended with the last - 1/4 pitch period of the cycle to be repeated, using an overlap-add (OLA) technique (i.e. - in total, the last 5/4 pitch periods of real speech are used). - -- The start of the synthetic speech will not always fit together smoothly with the tail of - real speech passed on before the erasure was identified. Ideally, we would like to modify - the last 1/4 pitch period of the real speech, to blend it into the synthetic speech. However, - it is too late for that. We could have delayed the real speech a little, but that would - require more buffer manipulation, and hurt the efficiency of the no-lost-packets case - (which we hope is the dominant case). Instead we use a degenerate form of OLA to modify - the start of the synthetic data. The last 1/4 pitch period of real speech is time reversed, - and OLA is used to blend it with the first 1/4 pitch period of synthetic speech. The result - seems quite acceptable. - -- As we progress into the erasure, the chances of the synthetic signal being anything like - correct steadily fall. Therefore, the volume of the synthesized signal is made to decay - linearly, such that after 50ms of missing audio it is reduced to silence. - -- When real speech resumes, an extra 1/4 pitch period of synthetic speech is blended with the - start of the real speech. If the erasure is small, this smoothes the transition. If the erasure - is long, and the synthetic signal has faded to zero, the blending softens the start up of the - real signal, avoiding a kind of "click" or "pop" effect that might occur with a sudden onset. - -\section plc_page_sec_3 How do I use it? -Before audio is processed, call plc_init() to create an instance of the packet loss -concealer. For each received audio packet that is acceptable (i.e. not including those being -dropped for being too late) call plc_rx() to record the content of the packet. Note this may -modify the packet a little after a period of packet loss, to blend real synthetic data smoothly. -When a real packet is not available in time, call plc_fillin() to create a sythetic substitute. -That's it! -*/ - -/*! 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. -*/ -typedef struct plc_state_s plc_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Process a block of received audio samples for PLC. - \brief Process a block of received audio samples for PLC. - \param s The packet loss concealer context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples in the buffer. */ -SPAN_DECLARE(int) plc_rx(plc_state_t *s, int16_t amp[], int len); - -/*! Fill-in a block of missing audio samples. - \brief Fill-in a block of missing audio samples. - \param s The packet loss concealer context. - \param amp The audio sample buffer. - \param len The number of samples to be synthesised. - \return The number of samples synthesized. */ -SPAN_DECLARE(int) plc_fillin(plc_state_t *s, int16_t amp[], int len); - -/*! Initialise a packet loss concealer context. - \brief Initialise a PLC context. - \param s The packet loss concealer context. - \return A pointer to the the packet loss concealer context. */ -SPAN_DECLARE(plc_state_t *) plc_init(plc_state_t *s); - -/*! Release a packet loss concealer context. - \param s The packet loss concealer context. - \return 0 for OK. */ -SPAN_DECLARE(int) plc_release(plc_state_t *s); - -/*! Free a packet loss concealer context. - \param s The packet loss concealer context. - \return 0 for OK. */ -SPAN_DECLARE(int) plc_free(plc_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/power_meter.h b/libs/spandsp/src/spandsp/power_meter.h deleted file mode 100644 index e949858607..0000000000 --- a/libs/spandsp/src/spandsp/power_meter.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * 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_POWER_METER_H_) -#define _SPANDSP_POWER_METER_H_ - -/*! \page power_meter_page Power metering - -\section power_meter_page_sec_1 What does it do? -The power metering module implements a simple IIR type running power meter. The damping -factor of the IIR is selectable when the meter instance is created. - -Note that the definition of dBOv is quite vague in most places - is it peak since wave, -peak square wave, etc.? This code is based on the well defined wording in RFC3389: - -"For example, in the case of a u-law system, the reference would be a square wave with -values +/-8031, and this square wave represents 0dBov. This translates into 6.18dBm0". - -\section power_meter_page_sec_2 How does it work? -*/ - -/*! - Power meter descriptor. This defines the working state for a - single instance of a power measurement device. -*/ -typedef struct power_meter_s power_meter_t; - -typedef struct power_surge_detector_state_s power_surge_detector_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise a power meter context. - \brief Initialise a power meter context. - \param s The power meter context. - \param shift The shift to be used by the IIR filter. - \return The power meter context. */ -SPAN_DECLARE(power_meter_t *) power_meter_init(power_meter_t *s, int shift); - -SPAN_DECLARE(int) power_meter_release(power_meter_t *s); - -SPAN_DECLARE(int) power_meter_free(power_meter_t *s); - -/*! Change the damping factor of a power meter context. - \brief Change the damping factor of a power meter context. - \param s The power meter context. - \param shift The new shift to be used by the IIR filter. - \return The power meter context. */ -SPAN_DECLARE(power_meter_t *) power_meter_damping(power_meter_t *s, int shift); - -/*! Update a power meter. - \brief Update a power meter. - \param s The power meter context. - \param amp The amplitude of the new audio sample. - \return The current power meter reading. */ -SPAN_DECLARE(int32_t) power_meter_update(power_meter_t *s, int16_t amp); - -/*! Get the current power meter reading. - \brief Get the current power meter reading. - \param s The power meter context. - \return The current power meter reading. */ -SPAN_DECLARE(int32_t) power_meter_current(power_meter_t *s); - -/*! Get the current power meter reading, in dBm0. - \brief Get the current power meter reading, in dBm0. - \param s The power meter context. - \return The current power meter reading, in dBm0. */ -SPAN_DECLARE(float) power_meter_current_dbm0(power_meter_t *s); - -/*! Get the current power meter reading, in dBOv. - \brief Get the current power meter reading, in dBOv. - \param s The power meter context. - \return The current power meter reading, in dBOv. */ -SPAN_DECLARE(float) power_meter_current_dbov(power_meter_t *s); - -/*! Get the power meter reading which represents a specified power level in dBm0. - \brief Get the current power meter reading, in dBm0. - \param level A power level, in dB0m. - \return The equivalent power meter reading. */ -SPAN_DECLARE(int32_t) power_meter_level_dbm0(float level); - -/*! Get the power meter reading which represents a specified power level in dBOv. - \brief Get the current power meter reading, in dBOv. - \param level A power level, in dBOv. - \return The equivalent power meter reading. */ -SPAN_DECLARE(int32_t) power_meter_level_dbov(float level); - -SPAN_DECLARE(int32_t) power_surge_detector(power_surge_detector_state_t *s, int16_t amp); - -/*! Get the current surge detector short term meter reading, in dBm0. - \brief Get the current surge detector meter reading, in dBm0. - \param s The power surge detector context. - \return The current power surge detector power reading, in dBm0. */ -SPAN_DECLARE(float) power_surge_detector_current_dbm0(power_surge_detector_state_t *s); - -/*! Get the current surge detector short term meter reading, in dBOv. - \brief Get the current surge detector meter reading, in dBOv. - \param s The power surge detector context. - \return The current power surge detector power reading, in dBOv. */ -SPAN_DECLARE(float) power_surge_detector_current_dbov(power_surge_detector_state_t *s); - -SPAN_DECLARE(power_surge_detector_state_t *) power_surge_detector_init(power_surge_detector_state_t *s, float min, float surge); - -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 defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/README b/libs/spandsp/src/spandsp/private/README deleted file mode 100644 index 41a6b03594..0000000000 --- a/libs/spandsp/src/spandsp/private/README +++ /dev/null @@ -1,3 +0,0 @@ -The header files in this directory should only be used by code tightly integrating itself with the -spandsp library to maximise performance. To maximise compatibility with futures revisions of spandsp, -most users should avoid using these headers, or probing into the spandsp data structures in other ways. \ No newline at end of file diff --git a/libs/spandsp/src/spandsp/private/ademco_contactid.h b/libs/spandsp/src/spandsp/private/ademco_contactid.h deleted file mode 100644 index f38b50a4b3..0000000000 --- a/libs/spandsp/src/spandsp/private/ademco_contactid.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/ademco_contactid.h - Ademco ContactID alarm protocol - * - * 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 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_ADEMCO_CONTACTID_H_) -#define _SPANDSP_PRIVATE_ADEMCO_CONTACTID_H_ - -struct ademco_contactid_receiver_state_s -{ - ademco_contactid_report_func_t callback; - void *callback_user_data; - - int step; - int remaining_samples; - uint32_t tone_phase; - int32_t tone_phase_rate; - int16_t tone_level; - dtmf_rx_state_t dtmf; - - char rx_digits[16 + 1]; - int rx_digits_len; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -struct ademco_contactid_sender_state_s -{ - tone_report_func_t callback; - void *callback_user_data; - - int step; - int remaining_samples; - - dtmf_tx_state_t dtmf; -#if defined(SPANDSP_USE_FIXED_POINT) - /*! Minimum acceptable tone level for detection. */ - int32_t threshold; - /*! The accumlating total energy on the same period over which the Goertzels work. */ - int32_t energy; -#else - /*! Minimum acceptable tone level for detection. */ - float threshold; - /*! The accumlating total energy on the same period over which the Goertzels work. */ - float energy; -#endif - goertzel_state_t tone_1400; - goertzel_state_t tone_2300; - /*! The current sample number within a processing block. */ - int current_sample; - - /*! \brief A buffer to save the sent message, in case we need to retry. */ - char tx_digits[16 + 1]; - int tx_digits_len; - /*! \brief The number of consecutive retries. */ - int tries; - - int tone_state; - int duration; - int last_hit; - int in_tone; - int clear_to_send; - int timer; - - int busy; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/adsi.h b/libs/spandsp/src/spandsp/private/adsi.h deleted file mode 100644 index f1d3d06a27..0000000000 --- a/libs/spandsp/src/spandsp/private/adsi.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/adsi.h - Analogue display services interface and other call ID related handling. - * - * 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 */ - -#if !defined(_SPANDSP_PRIVATE_ADSI_H_) -#define _SPANDSP_PRIVATE_ADSI_H_ - -/*! - ADSI transmitter descriptor. This contains all the state information for an ADSI - (caller ID, CLASS, CLIP, ACLIP) transmit channel. - */ -struct adsi_tx_state_s -{ - /*! */ - int standard; - - /*! */ - 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; - - /*! */ - int tx_signal_on; - - /*! */ - int byte_no; - /*! */ - int bit_pos; - /*! */ - int bit_no; - /*! */ - uint8_t msg[256]; - /*! */ - int msg_len; - /*! */ - int preamble_len; - /*! */ - int preamble_ones_len; - /*! */ - int postamble_ones_len; - /*! */ - int stop_bits; - /*! */ - int baudot_shift; - - /*! */ - logging_state_t logging; -}; - -/*! - ADSI receiver descriptor. This contains all the state information for an ADSI - (caller ID, CLASS, CLIP, ACLIP, JCLIP) receive channel. - */ -struct adsi_rx_state_s -{ - /*! */ - int standard; - /*! */ - put_msg_func_t put_msg; - /*! */ - void *user_data; - - /*! */ - fsk_rx_state_t fskrx; - /*! */ - dtmf_rx_state_t dtmfrx; - - /*! */ - int consecutive_ones; - /*! */ - int bit_pos; - /*! */ - int in_progress; - /*! */ - uint8_t msg[256]; - /*! */ - int msg_len; - /*! */ - int baudot_shift; - - /*! A count of the framing errors. */ - int framing_errors; - - /*! */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/async.h b/libs/spandsp/src/spandsp/private/async.h deleted file mode 100644 index 1c9c926595..0000000000 --- a/libs/spandsp/src/spandsp/private/async.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/async.h - Asynchronous serial bit stream encoding and decoding - * - * 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_ASYNC_H_) -#define _SPANDSP_PRIVATE_ASYNC_H_ - -/*! - Asynchronous data transmit descriptor. This defines the state of a single - working instance of a byte to asynchronous serial converter, for use - in FSK modems. -*/ -struct async_tx_state_s -{ - /*! \brief The number of data bits per character. */ - int data_bits; - /*! \brief The type of parity. */ - int parity; - /*! \brief The number of stop bits per character. */ - int stop_bits; - /*! \brief Total number of bits per character, including the parity and stop bits. */ - int total_bits; - /*! \brief A pointer to the callback routine used to get characters to be transmitted. */ - get_byte_func_t get_byte; - /*! \brief An opaque pointer passed when calling get_byte. */ - void *user_data; - /*! \brief The minimum number of stop bits to send before character transmission begins. */ - int presend_bits; - - /*! \brief A current, partially transmitted, character. */ - int32_t byte_in_progress; - /*! \brief The current bit position within a partially transmitted character. */ - int bitpos; - /*! \brief Parity bit. */ - int parity_bit; -}; - -/*! - Asynchronous data receive descriptor. This defines the state of a single - working instance of an asynchronous serial to byte converter, for use - in FSK modems. -*/ -struct async_rx_state_s -{ - /*! \brief The number of data bits per character. */ - int data_bits; - /*! \brief The type of parity. */ - int parity; - /*! \brief The number of stop bits per character. */ - int stop_bits; - /*! \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. */ - void *user_data; - - /*! \brief A current, partially complete, character. */ - int32_t byte_in_progress; - /*! \brief The current bit position within a partially complete character. */ - int bitpos; - /*! \brief Parity bit. */ - int parity_bit; - - /*! A count of the number of parity errors seen. */ - int parity_errors; - /*! A count of the number of character framing errors seen. */ - int framing_errors; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/at_interpreter.h b/libs/spandsp/src/spandsp/private/at_interpreter.h deleted file mode 100644 index 764b90bd00..0000000000 --- a/libs/spandsp/src/spandsp/private/at_interpreter.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/at_interpreter.h - AT command interpreter to V.251, V.252, V.253, T.31 and the 3GPP specs. - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 2005, 2006 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_AT_INTERPRETER_H_) -#define _SPANDSP_PRIVATE_AT_INTERPRETER_H_ - -typedef struct at_call_id_s at_call_id_t; - -struct at_call_id_s -{ - char *id; - char *value; - at_call_id_t *next; -}; - -/*! - AT descriptor. This defines the working state for a single instance of - the AT interpreter. -*/ -struct at_state_s -{ - at_profile_t p; - /*! Value set by +GCI */ - int country_of_installation; - /*! Value set by +FIT */ - int dte_inactivity_timeout; - /*! Value set by +FIT */ - int dte_inactivity_action; - /*! Value set by L */ - int speaker_volume; - /*! Value set by M */ - int speaker_mode; - /*! This is no real DTE rate. This variable is for compatibility this serially - connected modems. */ - /*! Value set by +IPR/+FPR */ - int dte_rate; - /*! Value set by +ICF */ - int dte_char_format; - /*! Value set by +ICF */ - int dte_parity; - /*! Value set by &C */ - int rlsd_behaviour; - /*! Value set by &D */ - int dtr_behaviour; - /*! Value set by +FCL */ - int carrier_loss_timeout; - /*! Value set by X */ - int result_code_mode; - /*! Value set by +IDSR */ - int dsr_option; - /*! Value set by +ILSD */ - int long_space_disconnect_option; - /*! Value set by +ICLOK */ - int sync_tx_clock_source; - /*! Value set by +EWIND */ - int rx_window; - /*! Value set by +EWIND */ - int tx_window; - - int v8bis_signal; - int v8bis_1st_message; - int v8bis_2nd_message; - int v8bis_sig_en; - int v8bis_msg_en; - int v8bis_supp_delay; - - uint8_t rx_data[256]; - int rx_data_bytes; - - int dte_dce_flow_control; - int dce_dte_flow_control; - int display_call_info; - int call_info_displayed; - at_call_id_t *call_id; - char *local_id; - /*! The currently select FAX modem class. 0 = data modem mode. */ - int fclass_mode; - int at_rx_mode; - int rings_indicated; - int do_hangup; - int silent_dial; - int command_dial; - int ok_is_pending; - int dte_is_waiting; - /*! \brief True if a carrier is present. */ - bool rx_signal_present; - /*! \brief True if a modem has trained, */ - bool rx_trained; - int transmit; - - char line[256]; - int line_ptr; - - at_modem_control_handler_t modem_control_handler; - void *modem_control_user_data; - at_tx_handler_t at_tx_handler; - void *at_tx_user_data; - at_class1_handler_t class1_handler; - void *class1_user_data; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/awgn.h b/libs/spandsp/src/spandsp/private/awgn.h deleted file mode 100644 index dbca521131..0000000000 --- a/libs/spandsp/src/spandsp/private/awgn.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/awgn.h - An additive Gaussian white noise generator - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_AWGN_H_) -#define _SPANDSP_PRIVATE_AWGN_H_ - -/*! - AWGN generator descriptor. This contains all the state information for an AWGN generator. - */ -struct awgn_state_s -{ - /* Scaling factor */ - double rms; - /* Working data for the Gaussian generator */ - bool odd; - double amp2; - /* Working data for the random number generator */ - int32_t ix1; - int32_t ix2; - int32_t ix3; - double r[97]; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/bell_r2_mf.h b/libs/spandsp/src/spandsp/private/bell_r2_mf.h deleted file mode 100644 index c694b9e2fa..0000000000 --- a/libs/spandsp/src/spandsp/private/bell_r2_mf.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bell_r2_mf.h - Bell MF and MFC/R2 tone generation and detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_BELL_R2_MF_H_) -#define _SPANDSP_PRIVATE_BELL_R2_MF_H_ - -/*! - Bell MF generator state descriptor. This defines the state of a single - working instance of a Bell MF generator. -*/ -struct bell_mf_tx_state_s -{ - /*! The tone generator. */ - tone_gen_state_t tones; - int current_sample; - union - { - queue_state_t queue; - uint8_t buf[QUEUE_STATE_T_SIZE(MAX_BELL_MF_DIGITS)]; - } queue; -}; - -/*! - Bell MF digit detector descriptor. -*/ -struct bell_mf_rx_state_s -{ - /*! Optional callback funcion to deliver received digits. */ - digits_rx_callback_t digits_callback; - /*! An opaque pointer passed to the callback function. */ - void *digits_callback_data; - /*! Tone detector working states */ - goertzel_state_t out[6]; - /*! Short term history of results from the tone detection, using in persistence checking */ - uint8_t hits[5]; - /*! The current sample number within a processing block. */ - int current_sample; - - /*! The number of digits which have been lost due to buffer overflows. */ - int lost_digits; - /*! The number of digits currently in the digit buffer. */ - int current_digits; - /*! The received digits buffer. This is a NULL terminated string. */ - char digits[MAX_BELL_MF_DIGITS + 1]; -}; - -/*! - MFC/R2 tone detector descriptor. -*/ -struct r2_mf_tx_state_s -{ - /*! The tone generator. */ - tone_gen_state_t tone; - /*! True if generating forward tones, otherwise generating reverse tones. */ - bool fwd; - /*! The current digit being generated. */ - int digit; -}; - -/*! - MFC/R2 tone detector descriptor. -*/ -struct r2_mf_rx_state_s -{ - /*! Optional callback funcion to deliver received digits. */ - tone_report_func_t callback; - /*! An opaque pointer passed to the callback function. */ - void *callback_data; - /*! True if 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. */ - int current_sample; - /*! The currently detected digit. */ - int current_digit; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/bert.h b/libs/spandsp/src/spandsp/private/bert.h deleted file mode 100644 index f58bc70943..0000000000 --- a/libs/spandsp/src/spandsp/private/bert.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/bert.h - Bit error rate tests. - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_BERT_H_) -#define _SPANDSP_PRIVATE_BERT_H_ - -typedef struct -{ - uint32_t reg; - int step; - int step_bit; - int bits; - int zeros; -} bert_tx_state_t; - -typedef struct -{ - uint32_t reg; - uint32_t ref_reg; - uint32_t master_reg; - int step; - int step_bit; - int resync; - int bits; - int zeros; - int resync_len; - int resync_percent; - int resync_bad_bits; - int resync_cnt; - int report_countdown; - int measurement_step; -} bert_rx_state_t; - -/*! - Bit error rate tester (BERT) descriptor. This defines the working state for a - single instance of the BERT. -*/ -struct bert_state_s -{ - int pattern; - int pattern_class; - bert_report_func_t reporter; - void *user_data; - int report_frequency; - int limit; - - uint32_t mask; - int shift; - int shift2; - int max_zeros; - int invert; - int resync_time; - - int decade_ptr[9]; - int decade_bad[9][10]; - int error_rate; - - bert_tx_state_t tx; - bert_rx_state_t rx; - - bert_results_t results; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/bitstream.h b/libs/spandsp/src/spandsp/private/bitstream.h deleted file mode 100644 index e957eabd61..0000000000 --- a/libs/spandsp/src/spandsp/private/bitstream.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/bitstream.h - Bitstream composition and decomposition routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_BITSTREAM_H_) -#define _SPANDSP_PRIVATE_BITSTREAM_H_ - -/*! Bitstream handler state */ -struct bitstream_state_s -{ - /*! The bit stream. */ - uint32_t bitstream; - /*! The residual bits in bitstream. */ - int residue; - /*! True if the stream is LSB first, else MSB first */ - bool lsb_first; -}; - - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/data_modems.h b/libs/spandsp/src/spandsp/private/data_modems.h deleted file mode 100644 index f47f8f259a..0000000000 --- a/libs/spandsp/src/spandsp/private/data_modems.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/data_modems.h - definitions for the analogue modem set for data 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_PRIVATE_DATA_MODEMS_H_) -#define _SPANDSP_PRIVATE_DATA_MODEMS_H_ - -/*! - The set of modems needed for data, plus the auxilliary stuff, like tone generation. -*/ -struct data_modems_state_s -{ - bool calling_party; - /*! True is talker echo protection should be sent for the modems which support this */ - bool use_tep; - - /*! 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. */ - bool transmit_on_idle; - - at_state_t at_state; - data_modems_control_handler_t modem_control_handler; - void *modem_control_user_data; - get_bit_func_t get_bit; - void *get_user_data; - put_bit_func_t put_bit; - void *put_user_data; - - void *user_data; - - put_msg_func_t put_msg; - get_msg_func_t get_msg; - - v42_state_t v42; - v42bis_state_t v42bis; - - int use_v14; - async_tx_state_t async_tx; - async_rx_state_t async_rx; - - /*! \brief Samples elapsed in the current call */ - int64_t call_samples; - - union - { - v8_state_t v8; - struct - { - /*! \brief Tone generator */ - modem_connect_tones_tx_state_t tx; - /*! \brief Tone detector */ - modem_connect_tones_rx_state_t rx; - } tones; - struct - { - /*! \brief FSK transmit modem context used for 103, V.21 and V.23. */ - fsk_tx_state_t tx; - /*! \brief FSK receive modem context used for 103, V.21 and V.23. */ - fsk_rx_state_t rx; - } fsk; - /*! \brief V.22bis modem context */ - v22bis_state_t v22bis; -#if defined(SPANDSP_SUPPORT_V32BIS) - /*! \brief V.32bis modem context */ - v32bis_state_t v32bis; -#endif -#if defined(SPANDSP_SUPPORT_V34) - /*! \brief V.22bis modem context */ - v34_state_t v34; -#endif - /*! \brief Used to insert timed silences. */ - silence_gen_state_t silence_gen; - } modems; - /*! \brief */ - dc_restore_state_t dc_restore; - - int current_modem; - int queued_modem; - int queued_baud_rate; - int queued_bit_rate; - - /*! \brief The currently select receiver type */ - int current_rx_type; - /*! \brief The currently select transmitter type */ - int current_tx_type; - - /*! \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; - - /*! The current receive signal handler */ - span_rx_handler_t rx_handler; - /*! The current receive missing signal fill-in handler */ - span_rx_fillin_handler_t rx_fillin_handler; - void *rx_user_data; - - /*! The current transmit signal handler */ - span_tx_handler_t tx_handler; - void *tx_user_data; - - /*! \brief Audio logging file handle for received audio. */ - int audio_rx_log; - /*! \brief Audio logging file handle for transmitted audio. */ - int audio_tx_log; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/dtmf.h b/libs/spandsp/src/spandsp/private/dtmf.h deleted file mode 100644 index 37450fdba5..0000000000 --- a/libs/spandsp/src/spandsp/private/dtmf.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/dtmf.h - DTMF tone generation and detection - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 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_DTMF_H_) -#define _SPANDSP_PRIVATE_DTMF_H_ - -/*! - DTMF generator state descriptor. This defines the state of a single - working instance of a DTMF generator. -*/ -struct dtmf_tx_state_s -{ - /*! Optional callback funcion to get more digits. */ - digits_tx_callback_t callback; - /*! An opaque pointer passed to the callback function. */ - void *callback_data; - tone_gen_state_t tones; - float low_level; - float high_level; - int on_time; - int off_time; - union - { - queue_state_t queue; - uint8_t buf[QUEUE_STATE_T_SIZE(MAX_DTMF_DIGITS)]; - } queue; -}; - -/*! - DTMF digit detector descriptor. -*/ -struct dtmf_rx_state_s -{ - /*! Optional callback funcion to deliver received digits. */ - digits_rx_callback_t digits_callback; - /*! An opaque pointer passed to the callback function. */ - void *digits_callback_data; - /*! Optional callback funcion to deliver real time digit state changes. */ - 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 */ - bool filter_dialtone; -#if defined(SPANDSP_USE_FIXED_POINT) - /*! 350Hz filter state for the optional dialtone filter. */ - float z350[2]; - /*! 440Hz filter state for the optional dialtone filter. */ - float z440[2]; - /*! Maximum acceptable "normal" (lower bigger than higher) twist ratio. */ - float normal_twist; - /*! Maximum acceptable "reverse" (higher bigger than lower) twist ratio. */ - float reverse_twist; - /*! Minimum acceptable tone level for detection. */ - int32_t threshold; - /*! The accumlating total energy on the same period over which the Goertzels work. */ - int32_t energy; -#else - /*! 350Hz filter state for the optional dialtone filter. */ - float z350[2]; - /*! 440Hz filter state for the optional dialtone filter. */ - float z440[2]; - /*! Maximum acceptable "normal" (lower bigger than higher) twist ratio. */ - float normal_twist; - /*! Maximum acceptable "reverse" (higher bigger than lower) twist ratio. */ - float reverse_twist; - /*! Minimum acceptable tone level for detection. */ - float threshold; - /*! The accumlating total energy on the same period over which the Goertzels work. */ - float energy; -#endif - /*! Tone detector working states for the row tones. */ - goertzel_state_t row_out[4]; - /*! Tone detector working states for the column tones. */ - goertzel_state_t col_out[4]; - /*! The result of the last tone analysis. */ - uint8_t last_hit; - /*! The confirmed digit we are currently receiving */ - uint8_t in_digit; - /*! The current sample number within a processing block. */ - int current_sample; - - /*! Tone state duration */ - int duration; - - /*! The number of digits which have been lost due to buffer overflows. */ - int lost_digits; - /*! The number of digits currently in the digit buffer. */ - int current_digits; - /*! The received digits buffer. This is a NULL terminated string. */ - char digits[MAX_DTMF_DIGITS + 1]; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/echo.h b/libs/spandsp/src/spandsp/private/echo.h deleted file mode 100644 index f280284232..0000000000 --- a/libs/spandsp/src/spandsp/private/echo.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/echo.h - An echo cancellor, suitable for electrical and acoustic - * cancellation. This code does not currently comply with - * any relevant standards (e.g. G.164/5/7/8). - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_ECHO_H_) -#define _SPANDSP_PRIVATE_ECHO_H_ - -/*! - G.168 echo canceller descriptor. This defines the working state for a line - echo canceller. -*/ -struct echo_can_state_s -{ - int tx_power[4]; - int rx_power[3]; - int clean_rx_power; - - int rx_power_threshold; - int nonupdate_dwell; - - int curr_pos; - - int taps; - int tap_mask; - int adaption_mode; - - int32_t supp_test1; - int32_t supp_test2; - int32_t supp1; - int32_t supp2; - int vad; - int cng; - - int16_t geigel_max; - int geigel_lag; - int dtd_onset; - int tap_set; - int tap_rotate_counter; - - int32_t latest_correction; /* Indication of the magnitude of the latest - adaption, or a code to indicate why adaption - was skipped, for test purposes */ - int32_t last_acf[28]; - int narrowband_count; - int narrowband_score; - - fir16_state_t fir_state; - /*! Echo FIR taps (16 bit version) */ - int16_t *fir_taps16[4]; - /*! Echo FIR taps (32 bit version) */ - int32_t *fir_taps32; - - /* DC and near DC blocking filter states */ - int32_t tx_hpf[2]; - int32_t rx_hpf[2]; - - /* Parameters for the optional Hoth noise generator */ - int cng_level; - int cng_rndnum; - int cng_filter; - - /* Snapshot sample of coeffs used for development */ - int16_t *snapshot; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/fax.h b/libs/spandsp/src/spandsp/private/fax.h deleted file mode 100644 index 9e99a10751..0000000000 --- a/libs/spandsp/src/spandsp/private/fax.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/fax.h - private definitions for analogue line ITU T.30 fax processing - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_PRIVATE_FAX_H_) -#define _SPANDSP_PRIVATE_FAX_H_ - -/*! - Analogue line T.30 FAX channel descriptor. This defines the state of a single working - instance of an analogue line soft-FAX machine. -*/ -struct fax_state_s -{ - /*! \brief The T.30 back-end */ - t30_state_t t30; - - /*! \brief The analogue modem front-end */ - fax_modems_state_t modems; - /*! \brief V.8 */ - v8_state_t v8; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/fax_modems.h b/libs/spandsp/src/spandsp/private/fax_modems.h deleted file mode 100644 index d11397793b..0000000000 --- a/libs/spandsp/src/spandsp/private/fax_modems.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/fax_modems.h - definitions for the analogue modem set for fax processing - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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_FAX_MODEMS_H_) -#define _SPANDSP_PRIVATE_FAX_MODEMS_H_ - -/*! - The set of modems needed for FAX, plus the auxilliary stuff, like tone generation. -*/ -struct fax_modems_state_s -{ - /*! 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 - 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. */ - int transmit_on_idle; - - /*! \brief An HDLC context used when transmitting HDLC messages. */ - hdlc_tx_state_t hdlc_tx; - /*! \brief An HDLC context used when receiving HDLC messages. */ - hdlc_rx_state_t hdlc_rx; - /*! \brief A V.21 FSK modem context used when transmitting HDLC over V.21 - messages. */ - fsk_tx_state_t v21_tx; - /*! \brief A V.21 FSK modem context used when receiving HDLC over V.21 - messages. */ - fsk_rx_state_t v21_rx; - union - { - /*! \brief A V.17 modem context used when sending FAXes at 7200bps, 9600bps - 12000bps or 14400bps */ - v17_tx_state_t v17_tx; - /*! \brief A V.29 modem context used when receiving FAXes at 7200bps, 9600bps - 12000bps or 14400bps */ - v17_rx_state_t v17_rx; - /*! \brief A V.27ter modem context used when sending FAXes at 2400bps or - 4800bps */ - v27ter_tx_state_t v27ter_tx; - /*! \brief A V.27ter modem context used when receiving FAXes at 2400bps or - 4800bps */ - v27ter_rx_state_t v27ter_rx; - /*! \brief A V.29 modem context used when sending FAXes at 7200bps or - 9600bps */ - v29_tx_state_t v29_tx; - /*! \brief A V.29 modem context used when receiving FAXes at 7200bps or - 9600bps */ - v29_rx_state_t v29_rx; -#if defined(SPANDSP_SUPPORT_V34) - /*! \brief A V.34 modem context used when sending or receiving Super-G3 FAXes */ - v34_state_t v34; -#endif - } fast_modems; - /*! \brief Used to insert timed silences. */ - silence_gen_state_t silence_gen; - /*! \brief CED or CNG generator */ - modem_connect_tones_tx_state_t connect_tx; - /*! \brief CED or CNG detector */ - modem_connect_tones_rx_state_t connect_rx; - /*! \brief */ - dc_restore_state_t dc_restore; - - /*! \brief The fast modem type currently in use */ - int fast_modem; - - /*! \brief The currently selected receiver type */ - int current_rx_type; - /*! \brief The currently selected transmitter type */ - int current_tx_type; - - int bit_rate; - int short_train; - - /*! \brief The callback function used to put each bit received. */ - put_bit_func_t put_bit; - /*! \brief A user specified opaque pointer passed to the put_bit routine. */ - void *put_bit_user_data; - - /*! \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 function. */ - void *get_bit_user_data; - - hdlc_frame_handler_t hdlc_accept; - void *hdlc_accept_user_data; - - /*! \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 */ - span_rx_handler_t rx_handler; - /*! \brief The current receive signal handler. Actual receiving hops between this - and a dummy receive routine. */ - span_rx_handler_t base_rx_handler; - void *rx_user_data; - /*! \brief The current receive missing signal fill-in handler */ - span_rx_fillin_handler_t rx_fillin_handler; - /*! \brief The current receive signal fillin handler. Actual receiving hops between this - and a dummy receive routine. */ - span_rx_fillin_handler_t base_rx_fillin_handler; - void *rx_fillin_user_data; - - /*! \brief The current transmit signal handler */ - span_tx_handler_t tx_handler; - void *tx_user_data; - - /*! \brief The next transmit signal handler, for two stage transmit operations. - E.g. a short silence followed by a modem signal. */ - span_tx_handler_t next_tx_handler; - void *next_tx_user_data; - - /*! \brief The current bit rate of the transmitter. */ - int tx_bit_rate; - /*! \brief The current bit rate of the receiver. */ - int rx_bit_rate; - - /*! \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. */ - int audio_tx_log; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/fsk.h b/libs/spandsp/src/spandsp/private/fsk.h deleted file mode 100644 index 3d3a5333b1..0000000000 --- a/libs/spandsp/src/spandsp/private/fsk.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/fsk.h - FSK modem transmit and receive parts - * - * 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_FSK_H_) -#define _SPANDSP_PRIVATE_FSK_H_ - -/*! - FSK modem transmit descriptor. This defines the state of a single working - instance of an FSK modem transmitter. -*/ -struct fsk_tx_state_s -{ - int baud_rate; - /*! \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 function. */ - void *get_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - int32_t phase_rates[2]; - int16_t scaling; - int32_t current_phase_rate; - uint32_t phase_acc; - int baud_frac; - int shutdown; -}; - -/*! - FSK modem receive descriptor. This defines the state of a single working - instance of an FSK modem receiver. -*/ -struct fsk_rx_state_s -{ - int baud_rate; - /*! \brief Synchronous/asynchronous framing control */ - int framing_mode; - /*! \brief The callback function used to put each bit received. */ - put_bit_func_t put_bit; - /*! \brief A user specified opaque pointer passed to the put_bit routine. */ - void *put_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - int32_t carrier_on_power; - int32_t carrier_off_power; - power_meter_t power; - /*! \brief The value of the last signal sample, using the a simple HPF for signal power estimation. */ - int16_t last_sample; - /*! \brief >0 if a signal above the minimum is present. It may or may not be a V.29 signal. */ - int signal_present; - - int32_t phase_rate[2]; - uint32_t phase_acc[2]; - - int correlation_span; - - complexi32_t window[2][FSK_MAX_WINDOW_LEN]; - complexi32_t dot[2]; - int buf_ptr; - - int frame_state; - unsigned int frame_bits; - int baud_phase; - int last_bit; - int scaling_shift; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/g711.h b/libs/spandsp/src/spandsp/private/g711.h deleted file mode 100644 index 5ebc17100d..0000000000 --- a/libs/spandsp/src/spandsp/private/g711.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/g711.h - In line A-law and u-law conversion routines - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_G711_H_) -#define _SPANDSP_PRIVATE_G711_H_ - -/*! - G.711 state - */ -struct g711_state_s -{ - /*! One of the G.711_xxx options */ - int mode; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/g722.h b/libs/spandsp/src/spandsp/private/g722.h deleted file mode 100644 index 34d0fcba81..0000000000 --- a/libs/spandsp/src/spandsp/private/g722.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/g722.h - The ITU G.722 codec. - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_PRIVATE_G722_H_) -#define _SPANDSP_PRIVATE_G722_H_ - -/*! The per band parameters for both encoding and decoding G.722 */ -typedef struct -{ - int16_t nb; - int16_t det; - int16_t s; - int16_t sz; - int16_t r; - int16_t p[2]; - int16_t a[2]; - int16_t b[6]; - int16_t d[7]; -} g722_band_t; - -/*! - G.722 encode state - */ -struct g722_encode_state_s -{ - /*! True if operating in the special ITU test mode, with the band split filters - disabled. */ - bool itu_test_mode; - /*! True if the G.722 data is packed */ - bool packed; - /*! True if encoding from 8k samples/second */ - bool eight_k; - /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */ - int bits_per_sample; - - /*! Signal history for the QMF */ - int16_t x[12]; - int16_t y[12]; - int ptr; - - g722_band_t band[2]; - - uint32_t out_buffer; - int out_bits; -}; - -/*! - G.722 decode state - */ -struct g722_decode_state_s -{ - /*! True if operating in the special ITU test mode, with the band split filters - disabled. */ - bool itu_test_mode; - /*! True if the G.722 data is packed */ - bool packed; - /*! True if decoding to 8k samples/second */ - bool eight_k; - /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */ - int bits_per_sample; - - /*! Signal history for the QMF */ - int16_t x[12]; - int16_t y[12]; - int ptr; - - g722_band_t band[2]; - - uint32_t in_buffer; - int in_bits; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/g726.h b/libs/spandsp/src/spandsp/private/g726.h deleted file mode 100644 index 48b4454858..0000000000 --- a/libs/spandsp/src/spandsp/private/g726.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/g726.h - ITU G.726 codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_G726_H_) -#define _SPANDSP_PRIVATE_G726_H_ - -/*! - * The following is the definition of the state structure - * used by the G.726 encoder and decoder to preserve their internal - * state between successive calls. The meanings of the majority - * of the state structure fields are explained in detail in the - * ITU Recommendation G.726. The field names are essentially indentical - * to variable names in the bit level description of the coding algorithm - * included in this recommendation. - */ -struct g726_state_s -{ - /*! The bit rate */ - int rate; - /*! The external coding, for tandem operation */ - int ext_coding; - /*! The number of bits per sample */ - int bits_per_sample; - /*! One of the G.726_PACKING_xxx options */ - int packing; - - /*! Locked or steady state step size multiplier. */ - int32_t yl; - /*! Unlocked or non-steady state step size multiplier. */ - int16_t yu; - /*! int16_t term energy estimate. */ - int16_t dms; - /*! Long term energy estimate. */ - int16_t dml; - /*! Linear weighting coefficient of 'yl' and 'yu'. */ - int16_t ap; - - /*! Coefficients of pole portion of prediction filter. */ - int16_t a[2]; - /*! Coefficients of zero portion of prediction filter. */ - int16_t b[6]; - /*! Signs of previous two samples of a partially reconstructed signal. */ - int16_t pk[2]; - /*! Previous 6 samples of the quantized difference signal represented in - an internal floating point format. */ - int16_t dq[6]; - /*! Previous 2 samples of the quantized difference signal represented in an - internal floating point format. */ - int16_t sr[2]; - /*! Delayed tone detect */ - int td; - - /*! \brief The bit stream processing context. */ - bitstream_state_t bs; - - /*! \brief The current encoder function. */ - g726_encoder_func_t enc_func; - /*! \brief The current decoder function. */ - g726_decoder_func_t dec_func; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/gsm0610.h b/libs/spandsp/src/spandsp/private/gsm0610.h deleted file mode 100644 index 466be71207..0000000000 --- a/libs/spandsp/src/spandsp/private/gsm0610.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/gsm0610.h - GSM 06.10 full rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_GSM0610_H_) -#define _SPANDSP_PRIVATE_GSM0610_H_ - -/*! - GSM 06.10 FR codec state descriptor. This defines the state of - a single working instance of the GSM 06.10 FR encoder or decoder. -*/ -struct gsm0610_state_s -{ - /*! \brief One of the packing modes */ - int packing; - - int16_t dp0[280]; - - /*! Preprocessing */ - int16_t z1; - int32_t L_z2; - /*! Pre-emphasis */ - int16_t mp; - - /*! Short term delay filter */ - int16_t u[8]; - int16_t LARpp[2][8]; - int16_t j; - - /*! Long term synthesis */ - int16_t nrp; - /*! Short term synthesis */ - int16_t v[9]; - /*! Decoder postprocessing */ - int16_t msr; - - /*! Encoder data */ - int16_t e[50]; -}; - -#endif -/*- End of include ---------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/hdlc.h b/libs/spandsp/src/spandsp/private/hdlc.h deleted file mode 100644 index 6390a52f08..0000000000 --- a/libs/spandsp/src/spandsp/private/hdlc.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/hdlc.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_HDLC_H_) -#define _SPANDSP_PRIVATE_HDLC_H_ - -/*! - HDLC receive descriptor. This contains all the state information for an HDLC receiver. - */ -struct hdlc_rx_state_s -{ - /*! 2 for CRC-16, 4 for CRC-32 */ - int crc_bytes; - /*! \brief Maximum permitted frame length. */ - size_t max_frame_len; - /*! \brief The callback routine called to process each good received frame. */ - hdlc_frame_handler_t frame_handler; - /*! \brief An opaque parameter passed to the frame callback routine. */ - void *frame_user_data; - /*! \brief The callback routine called to report status changes. */ - 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. */ - 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. */ - bool framing_ok_announced; - /*! \brief Number of consecutive flags seen so far. */ - int flags_seen; - - /*! \brief The raw (stuffed) bit stream buffer. */ - uint32_t raw_bit_stream; - /*! \brief The destuffed bit stream buffer. */ - 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). */ - bool octet_counting_mode; - /*! \brief Octet count, to achieve the functionality needed for things - like MTP. */ - int octet_count; - /*! \brief The number of octets to be allowed between octet count reports. */ - int octet_count_report_interval; - - /*! \brief Buffer for a frame in progress. */ - uint8_t buffer[HDLC_MAXFRAME_LEN + 4]; - /*! \brief Length of a frame in progress. */ - size_t len; - - /*! \brief The number of bytes of good frames received (CRC not included). */ - unsigned long int rx_bytes; - /*! \brief The number of good frames received. */ - unsigned long int rx_frames; - /*! \brief The number of frames with CRC errors received. */ - unsigned long int rx_crc_errors; - /*! \brief The number of too short and too long frames received. */ - unsigned long int rx_length_errors; - /*! \brief The number of HDLC aborts received. */ - unsigned long int rx_aborts; -}; - -/*! - HDLC transmit descriptor. This contains all the state information for an - HDLC transmitter. - */ -struct hdlc_tx_state_s -{ - /*! 2 for CRC-16, 4 for CRC-32 */ - int crc_bytes; - /*! \brief The callback routine called to indicate transmit underflow. */ - hdlc_underflow_handler_t underflow_handler; - /*! \brief An opaque parameter passed to the callback routine. */ - 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. */ - bool progressive; - /*! \brief Maximum permitted frame length. */ - size_t max_frame_len; - - /*! \brief The stuffed bit stream being created. */ - uint32_t octets_in_progress; - /*! \brief The number of bits currently in octets_in_progress. */ - int num_bits; - /*! \brief The currently rotated state of the flag octet. */ - int idle_octet; - /*! \brief The number of flag octets to send for a timed burst of flags. */ - 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 */ - bool report_flag_underflow; - - /*! \brief The current message being transmitted, with its CRC attached. */ - uint8_t buffer[HDLC_MAXFRAME_LEN + 4]; - /*! \brief The length of the message in the buffer. */ - size_t len; - /*! \brief The current send position within the buffer. */ - size_t pos; - /*! \brief The running CRC, as data fills the frame buffer. */ - uint32_t crc; - - /*! \brief The current byte being broken into bits for transmission. */ - int byte; - /*! \brief The number of bits remaining in byte. */ - int bits; - - /*! \brief True if transmission should end on buffer underflow .*/ - bool tx_end; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/ima_adpcm.h b/libs/spandsp/src/spandsp/private/ima_adpcm.h deleted file mode 100644 index 2fc7d2c114..0000000000 --- a/libs/spandsp/src/spandsp/private/ima_adpcm.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/ima_adpcm.h - Conversion routines between linear 16 bit PCM data - * and IMA/DVI/Intel ADPCM format. - * - * 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. - * - * Based on a bit from here, a bit from there, eye of toad, - * ear of bat, etc - plus, of course, my own 2 cents. - */ - -#if !defined(_SPANDSP_PRIVATE_IMA_ADPCM_H_) -#define _SPANDSP_PRIVATE_IMA_ADPCM_H_ - -/*! - IMA (DVI/Intel) ADPCM conversion state descriptor. This defines the state of - a single working instance of the IMA ADPCM converter. This is used for - either linear to ADPCM or ADPCM to linear conversion. -*/ -struct ima_adpcm_state_s -{ - int variant; - /*! \brief The size of a chunk, in samples. */ - int chunk_size; - /*! \brief The last state of the ADPCM algorithm. */ - int last; - /*! \brief Current index into the step size table. */ - int step_index; - /*! \brief The current IMA code byte in progress. */ - uint16_t ima_byte; - int bits; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/image_translate.h b/libs/spandsp/src/spandsp/private/image_translate.h deleted file mode 100644 index 02a13506df..0000000000 --- a/libs/spandsp/src/spandsp/private/image_translate.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/image_translate.h - Image translation routines for reworking colour - * and gray scale images to be bi-level images of an - * appropriate size to be FAX compatible. - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_IMAGE_TRANSLATE_H_) -#define _SPANDSP_PRIVATE_IMAGE_TRANSLATE_H_ - -struct image_translate_state_s -{ - int input_format; - int input_width; - int input_length; - int input_bytes_per_pixel; - int output_format; - int output_width; - int output_length; - int output_bytes_per_pixel; - int resize; - int raw_input_row; - int raw_output_row; - int output_row; - - uint8_t *raw_pixel_row[2]; - uint8_t *pixel_row[2]; - - t4_row_read_handler_t row_read_handler; - void *row_read_user_data; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/logging.h b/libs/spandsp/src/spandsp/private/logging.h deleted file mode 100644 index fca1d257a9..0000000000 --- a/libs/spandsp/src/spandsp/private/logging.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/logging.h - definitions for error and debug logging. - * - * 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_LOGGING_H_) -#define _SPANDSP_PRIVATE_LOGGING_H_ - -/*! - Logging descriptor. This defines the working state for a single instance of - the logging facility for spandsp. -*/ -struct logging_state_s -{ - int level; - int samples_per_second; - int64_t elapsed_samples; - const char *tag; - const char *protocol; - - message_handler_func_t span_message; - void *user_data; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/lpc10.h b/libs/spandsp/src/spandsp/private/lpc10.h deleted file mode 100644 index e02096e6d5..0000000000 --- a/libs/spandsp/src/spandsp/private/lpc10.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/lpc10.h - LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_LPC10_H_) -#define _SPANDSP_PRIVATE_LPC10_H_ - -/*! - LPC10 codec encoder state descriptor. This defines the state of - a single working instance of the LPC10 encoder. -*/ -struct lpc10_encode_state_s -{ - /*! \brief ??? */ - int error_correction; - - /* State used only by function high_pass_100hz */ - /*! \brief ??? */ - float z11; - /*! \brief ??? */ - float z21; - /*! \brief ??? */ - float z12; - /*! \brief ??? */ - float z22; - - /* State used by function lpc10_analyse */ - /*! \brief ??? */ - float inbuf[LPC10_SAMPLES_PER_FRAME*3]; - /*! \brief ??? */ - float pebuf[LPC10_SAMPLES_PER_FRAME*3]; - /*! \brief ??? */ - float lpbuf[696]; - /*! \brief ??? */ - float ivbuf[312]; - /*! \brief ??? */ - float bias; - /*! \brief No initial value necessary */ - int32_t osbuf[10]; - /*! \brief Initial value 1 */ - int32_t osptr; - /*! \brief ??? */ - int32_t obound[3]; - /*! \brief Initial value vwin[2][0] = 307; vwin[2][1] = 462; */ - int32_t vwin[3][2]; - /*! \brief Initial value awin[2][0] = 307; awin[2][1] = 462; */ - int32_t awin[3][2]; - /*! \brief ??? */ - int32_t voibuf[4][2]; - /*! \brief ??? */ - float rmsbuf[3]; - /*! \brief ??? */ - float rcbuf[3][10]; - /*! \brief ??? */ - float zpre; - - /* State used by function onset */ - /*! \brief ??? */ - float n; - /*! \brief Initial value 1.0f */ - float d__; - /*! \brief No initial value necessary */ - float fpc; - /*! \brief ??? */ - float l2buf[16]; - /*! \brief ??? */ - float l2sum1; - /*! \brief Initial value 1 */ - int32_t l2ptr1; - /*! \brief Initial value 9 */ - int32_t l2ptr2; - /*! \brief No initial value necessary */ - int32_t lasti; - /*! \brief Initial value false */ - bool hyst; - - /* State used by function lpc10_voicing */ - /*! \brief Initial value 20.0f */ - float dither; - /*! \brief ??? */ - float snr; - /*! \brief ??? */ - float maxmin; - /*! \brief Initial value is probably unnecessary */ - float voice[3][2]; - /*! \brief ??? */ - int32_t lbve; - /*! \brief ??? */ - int32_t lbue; - /*! \brief ??? */ - int32_t fbve; - /*! \brief ??? */ - int32_t fbue; - /*! \brief ??? */ - int32_t ofbue; - /*! \brief ??? */ - int32_t sfbue; - /*! \brief ??? */ - int32_t olbue; - /*! \brief ??? */ - int32_t slbue; - - /* State used by function dynamic_pitch_tracking */ - /*! \brief ??? */ - float s[60]; - /*! \brief ??? */ - int32_t p[2][60]; - /*! \brief ??? */ - int32_t ipoint; - /*! \brief ??? */ - float alphax; - - /* State used by function lpc10_pack */ - /*! \brief ??? */ - int32_t isync; -}; - -/*! - LPC10 codec decoder state descriptor. This defines the state of - a single working instance of the LPC10 decoder. -*/ -struct lpc10_decode_state_s -{ - /*! \brief ??? */ - int error_correction; - - /* State used by function decode */ - /*! \brief Initial value 60 */ - int32_t iptold; - /*! \brief Initial value true */ - bool first; - /*! \brief ??? */ - int32_t ivp2h; - /*! \brief ??? */ - int32_t iovoic; - /*! \brief Initial value 60. */ - int32_t iavgp; - /*! \brief ??? */ - int32_t erate; - /*! \brief ??? */ - int32_t drc[10][3]; - /*! \brief ??? */ - int32_t dpit[3]; - /*! \brief ??? */ - int32_t drms[3]; - - /* State used by function synths */ - /*! \brief ??? */ - float buf[LPC10_SAMPLES_PER_FRAME*2]; - /*! \brief Initial value LPC10_SAMPLES_PER_FRAME */ - int32_t buflen; - - /* State used by function pitsyn */ - /*! \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 */ - int32_t ipito; - /*! \brief Initial value 1.0f */ - float rmso; - /*! \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 */ - int32_t jsamp; - /*! \brief Initial value true */ - bool first_pitsyn; - - /* State used by function bsynz */ - /*! \brief ??? */ - int32_t ipo; - /*! \brief ??? */ - float exc[166]; - /*! \brief ??? */ - float exc2[166]; - /*! \brief ??? */ - float lpi[3]; - /*! \brief ??? */ - float hpi[3]; - /*! \brief ??? */ - float rmso_bsynz; - - /* State used by function random */ - /*! \brief ??? */ - int32_t j; - /*! \brief ??? */ - int32_t k; - /*! \brief ??? */ - int16_t y[5]; - - /* State used by function deemp */ - /*! \brief ??? */ - float dei[2]; - /*! \brief ??? */ - float deo[3]; -}; - -#endif -/*- End of include ---------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/modem_connect_tones.h b/libs/spandsp/src/spandsp/private/modem_connect_tones.h deleted file mode 100644 index d76faf1de3..0000000000 --- a/libs/spandsp/src/spandsp/private/modem_connect_tones.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/modem_connect_tones.c - Generation and detection of tones - * associated with modems calling and - * answering calls. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_MODEM_CONNECT_TONES_H_) -#define _SPANDSP_PRIVATE_MODEM_CONNECT_TONES_H_ - -/*! - Modem connect tones generator descriptor. This defines the state - of a single working instance of the tone generator. -*/ -struct modem_connect_tones_tx_state_s -{ - int tone_type; - - int32_t tone_phase_rate; - uint32_t tone_phase; - int16_t level; - /*! \brief Countdown to the next phase hop */ - int hop_timer; - /*! \brief Maximum duration timer */ - int duration_timer; - uint32_t mod_phase; - int32_t mod_phase_rate; - int16_t mod_level; -}; - -/*! - Modem connect tones receiver descriptor. This defines the state - of a single working instance of the tone detector. -*/ -struct modem_connect_tones_rx_state_s -{ - /*! \brief The tone type being detected. */ - int tone_type; - /*! \brief Callback routine, using to report detection of the tone. */ - tone_report_func_t tone_callback; - /*! \brief An opaque pointer passed to tone_callback. */ - void *callback_data; - - /*! \brief The notch filter state. */ - float znotch_1; - float znotch_2; - /*! \brief The 15Hz AM filter state. */ - float z15hz_1; - float z15hz_2; - /*! \brief The in notch power estimate */ - int32_t notch_level; - /*! \brief The total channel power estimate */ - int32_t channel_level; - /*! \brief The 15Hz AM power estimate */ - int32_t am_level; - /*! \brief Sample counter for the small chunks of samples, after which a test is conducted. */ - int chunk_remainder; - /*! \brief The code for the tone currently confirmed present in the audio. */ - int tone_present; - /*! \brief */ - int tone_on; - /*! \brief A millisecond counter, to time the duration of tone sections. */ - int tone_cycle_duration; - /*! \brief A count of the number of good cycles of tone reversal seen. */ - int good_cycles; - /*! \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; - /*! \brief The raw (stuffed) bit stream buffer. */ - unsigned int raw_bit_stream; - /*! \brief The current number of bits in the octet in progress. */ - int num_bits; - /*! \brief Number of consecutive flags seen so far. */ - int flags_seen; - /*! \brief True if framing OK has been announced. */ - bool framing_ok_announced; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/modem_echo.h b/libs/spandsp/src/spandsp/private/modem_echo.h deleted file mode 100644 index 24bc7577b0..0000000000 --- a/libs/spandsp/src/spandsp/private/modem_echo.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/modem_echo.h - An echo cancellor, suitable for electrical echos in GSTN modems - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 2004 Steve Underwood - * - * Based on a bit from here, a bit from there, eye of toad, - * ear of bat, etc - plus, of course, my own 2 cents. - * - * 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_MODEM_ECHO_H_) -#define _SPANDSP_PRIVATE_MODEM_ECHO_H_ - -/*! - Modem line echo canceller descriptor. This defines the working state for a line - echo canceller. -*/ -struct modem_echo_can_state_s -{ - int adapt; - int taps; - - fir16_state_t fir_state; - /*! Echo FIR taps (16 bit version) */ - int16_t *fir_taps16; - /*! Echo FIR taps (32 bit version) */ - int32_t *fir_taps32; - - int tx_power; - int rx_power; - - int curr_pos; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/noise.h b/libs/spandsp/src/spandsp/private/noise.h deleted file mode 100644 index 73b908497f..0000000000 --- a/libs/spandsp/src/spandsp/private/noise.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/noise.h - A low complexity audio noise generator, suitable for - * real time generation (current just approx AWGN) - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_PRIVATE_NOISE_H_) -#define _SPANDSP_PRIVATE_NOISE_H_ - -/*! - Noise generator descriptor. This contains all the state information for an instance - of the noise generator. - */ -struct noise_state_s -{ - int class_of_noise; - int quality; - int32_t rms; - uint32_t rndnum; - int32_t state; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/oki_adpcm.h b/libs/spandsp/src/spandsp/private/oki_adpcm.h deleted file mode 100644 index 9970b5837c..0000000000 --- a/libs/spandsp/src/spandsp/private/oki_adpcm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/oki_adpcm.h - Conversion routines between linear 16 bit PCM data - * and OKI (Dialogic) ADPCM format. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_OKI_ADPCM_H_) -#define _SPANDSP_PRIVATE_OKI_ADPCM_H_ - -/*! - Oki (Dialogic) ADPCM conversion state descriptor. This defines the state of - a single working instance of the Oki ADPCM converter. This is used for - either linear to ADPCM or ADPCM to linear conversion. -*/ -struct oki_adpcm_state_s -{ - /*! \brief The bit rate - 24000 or 32000. */ - int bit_rate; - /*! \brief The last state of the ADPCM algorithm. */ - int16_t last; - /*! \brief Current index into the step size table. */ - int16_t step_index; - /*! \brief The compressed data byte in progress. */ - uint8_t oki_byte; - /*! \brief The signal history for the sample rate converter. */ - int16_t history[32]; - /*! \brief Pointer into the history buffer. */ - int ptr; - /*! \brief Odd/even sample counter. */ - int mark; - /*! \brief Phase accumulator for the sample rate converter. */ - int phase; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/playout.h b/libs/spandsp/src/spandsp/private/playout.h deleted file mode 100644 index dd8c9a53e9..0000000000 --- a/libs/spandsp/src/spandsp/private/playout.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 deleted file mode 100644 index 79975b02f1..0000000000 --- a/libs/spandsp/src/spandsp/private/plc.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 deleted file mode 100644 index 64b8ec3f45..0000000000 --- a/libs/spandsp/src/spandsp/private/power_meter.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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/queue.h b/libs/spandsp/src/spandsp/private/queue.h deleted file mode 100644 index b621ee9fc5..0000000000 --- a/libs/spandsp/src/spandsp/private/queue.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/queue.h - simple in process message queuing - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_QUEUE_H_) -#define _SPANDSP_PRIVATE_QUEUE_H_ - -/*! - Queue descriptor. This defines the working state for a single instance of - a byte stream or message oriented queue. -*/ -struct queue_state_s -{ - /*! \brief Flags indicating the mode of the queue. */ - int flags; - /*! \brief The length of the data buffer. */ - int len; - /*! \brief The buffer input pointer. */ - volatile int iptr; - /*! \brief The buffer output pointer. */ - volatile int optr; -#if defined(SPANDSP_FULLY_DEFINE_QUEUE_STATE_T) - /*! \brief The data buffer, sized at the time the structure is created. */ - uint8_t data[]; -#endif -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/schedule.h b/libs/spandsp/src/spandsp/private/schedule.h deleted file mode 100644 index 1e37b99005..0000000000 --- a/libs/spandsp/src/spandsp/private/schedule.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/schedule.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. - */ - -#if !defined(_SPANDSP_PRIVATE_SCHEDULE_H_) -#define _SPANDSP_PRIVATE_SCHEDULE_H_ - -/*! A scheduled event entry. */ -struct span_sched_s -{ - uint64_t when; - span_sched_callback_func_t callback; - void *user_data; -}; - -/*! A scheduled event queue. */ -struct span_sched_state_s -{ - uint64_t ticker; - int allocated; - int max_to_date; - span_sched_t *sched; - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/sig_tone.h b/libs/spandsp/src/spandsp/private/sig_tone.h deleted file mode 100644 index 1353d32ee1..0000000000 --- a/libs/spandsp/src/spandsp/private/sig_tone.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/sig_tone.h - Signalling tone processing for the 2280Hz, 2400Hz, 2600Hz - * and similar signalling tones used in older protocols. - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_SIG_TONE_H_) -#define _SPANDSP_PRIVATE_SIG_TONE_H_ - -/*! \brief The coefficient set for a pair of cascaded bi-quads that make a signalling notch filter. */ -typedef struct -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t a1[3]; - int16_t b1[3]; - int16_t a2[3]; - int16_t b2[3]; - int postscale; -#else - float a1[3]; - float b1[3]; - float a2[3]; - float b2[3]; -#endif -} sig_tone_notch_coeffs_t; - -/*! \brief The coefficient set for a bi-quad that makes a signalling flat filter. - Some signalling tone schemes require such a filter, and some don't. - It is termed a flat filter, to distinguish it from the sharp filter, - but obviously it is not actually flat. It is a broad band weighting - filter. */ -typedef struct -{ -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief Flat mode bandpass bi-quad parameters */ - int16_t a[3]; - /*! \brief Flat mode bandpass bi-quad parameters */ - int16_t b[3]; - /*! \brief Post filter scaling */ - int postscale; -#else - /*! \brief Flat mode bandpass bi-quad parameters */ - float a[3]; - /*! \brief Flat mode bandpass bi-quad parameters */ - float b[3]; -#endif -} sig_tone_flat_coeffs_t; - -/*! - signalling tone descriptor. This defines the working state for a - single instance of the transmit and receive sides of a signalling - tone processor. -*/ -typedef struct -{ - /*! \brief The tones used. */ - int tone_freq[2]; - /*! \brief The high and low tone amplitudes for each of the tones, in dBm0. */ - int tone_amp[2][2]; - - /*! \brief The delay, in audio samples, before the high level tone drops - to a low level tone. Some signalling protocols require the - signalling tone be started at a high level, to ensure crisp - initial detection at the receiver, but require the tone - amplitude to drop by a number of dBs if it is sustained, - to reduce crosstalk levels. */ - int high_low_timeout; - - /*! \brief Some signalling tone detectors use a sharp initial filter, - changing to a broader, flatter, filter after some delay. This - parameter defines the delay. 0 means it never changes. */ - int sharp_flat_timeout; - - /*! \brief Parameters to control the behaviour of the notch filter, used - to remove the tone from the voice path in some protocols. The - notch is applied as fast as possible, when the signalling tone - is detected. Its removal is delayed by this timeout, to avoid - clicky noises from repeated switching of the filter on rapid - pulses of signalling tone. */ - int notch_lag_time; - - /*! \brief The tone on persistence check, in audio samples. */ - int tone_on_check_time; - /*! \brief The tone off persistence check, in audio samples. */ - int tone_off_check_time; - - /*! \brief The number of tones used. */ - int tones; - /*! \brief The coefficients for the cascaded bi-quads notch filter. */ - const sig_tone_notch_coeffs_t *notch[2]; - /*! \brief The coefficients for the single bi-quad flat mode filter. */ - const sig_tone_flat_coeffs_t *flat; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief Minimum signalling tone to total power ratio, in dB */ - int16_t detection_ratio; - /*! \brief Minimum total power for detection in sharp mode, in dB */ - int16_t sharp_detection_threshold; - /*! \brief Minimum total power for detection in flat mode, in dB */ - int16_t flat_detection_threshold; -#else - /*! \brief Minimum signalling tone to total power ratio, in dB */ - float detection_ratio; - /*! \brief Minimum total power for detection in sharp mode, in dB */ - float sharp_detection_threshold; - /*! \brief Minimum total power for detection in flat mode, in dB */ - float flat_detection_threshold; -#endif -} sig_tone_descriptor_t; - -/*! - Signalling tone transmit state - */ -struct sig_tone_tx_state_s -{ - /*! \brief The callback function used to handle signalling changes. */ - tone_report_func_t sig_update; - /*! \brief A user specified opaque pointer passed to the callback function. */ - void *user_data; - - /*! \brief Tone descriptor */ - const sig_tone_descriptor_t *desc; - - /*! The phase rates for the one or two tones */ - int32_t phase_rate[2]; - /*! The phase accumulators for the one or two tones */ - uint32_t phase_acc[2]; - - /*! The scaling values for the one or two tones, and the high and low level of each tone */ - int16_t tone_scaling[2][2]; - /*! The sample timer, used to switch between the high and low level tones. */ - int high_low_timer; - - /*! \brief Current transmit tone */ - int current_tx_tone; - /*! \brief Current transmit timeout */ - int current_tx_timeout; - /*! \brief Time in current signalling state, in samples. */ - int signalling_state_duration; -}; - -/*! - Signalling tone receive state - */ -struct sig_tone_rx_state_s -{ - /*! \brief The callback function used to handle signalling changes. */ - tone_report_func_t sig_update; - /*! \brief A user specified opaque pointer passed to the callback function. */ - void *user_data; - - /*! \brief Tone descriptor */ - const sig_tone_descriptor_t *desc; - - /*! \brief The current receive tone */ - int current_rx_tone; - /*! \brief The timeout for switching from the high level to low level tone detector. */ - int high_low_timer; - /*! \brief ??? */ - int current_notch_filter; - - struct - { -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The z's for the notch filter */ - int16_t notch_z1[2]; - /*! \brief The z's for the notch filter */ - int16_t notch_z2[2]; -#else - /*! \brief The z's for the notch filter */ - float notch_z1[2]; - /*! \brief The z's for the notch filter */ - float notch_z2[2]; -#endif - - /*! \brief The power output of the notch. */ - power_meter_t power; - } tone[3]; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The z's for the weighting/bandpass filter. */ - int16_t flat_z[2]; -#else - /*! \brief The z's for the weighting/bandpass filter. */ - float flat_z[2]; -#endif - /*! \brief The output power of the flat (unfiltered or flat filtered) path. */ - power_meter_t flat_power; - - /*! \brief Persistence check for tone present */ - int tone_persistence_timeout; - /*! \brief The tone pattern on the last audio sample */ - int last_sample_tone_present; - - /*! \brief The minimum reading from the power meter for detection in flat mode */ - int32_t flat_detection_threshold; - /*! \brief The minimum reading from the power meter for detection in sharp mode */ - int32_t sharp_detection_threshold; - /*! \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. */ - bool flat_mode; - /*! \brief True if the notch filter is enabled in the media path */ - bool notch_enabled; - /*! \brief ??? */ - int flat_mode_timeout; - /*! \brief ??? */ - int notch_insertion_timeout; - - /*! \brief ??? */ - int signalling_state; - /*! \brief ??? */ - int signalling_state_duration; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/silence_gen.h b/libs/spandsp/src/spandsp/private/silence_gen.h deleted file mode 100644 index 695e472c3c..0000000000 --- a/libs/spandsp/src/spandsp/private/silence_gen.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/silence_gen.c - A silence generator, for inserting timed silences. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_SILENCE_GEN_H_) -#define _SPANDSP_PRIVATE_SILENCE_GEN_H_ - -struct silence_gen_state_s -{ - /*! \brief The callback function used to report status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - int remaining_samples; - int total_samples; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/super_tone_rx.h b/libs/spandsp/src/spandsp/private/super_tone_rx.h deleted file mode 100644 index e62d455d47..0000000000 --- a/libs/spandsp/src/spandsp/private/super_tone_rx.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/super_tone_rx.h - Flexible telephony supervisory tone detection. - * - * 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_SUPER_TONE_RX_H_) -#define _SPANDSP_PRIVATE_SUPER_TONE_RX_H_ - -#define SUPER_TONE_BINS 128 - -struct super_tone_rx_segment_s -{ - int f1; - int f2; - int recognition_duration; - int min_duration; - int max_duration; -}; - -struct super_tone_rx_descriptor_s -{ - int used_frequencies; - int monitored_frequencies; - int pitches[SUPER_TONE_BINS/2][2]; - int tones; - super_tone_rx_segment_t **tone_list; - int *tone_segs; - goertzel_descriptor_t *desc; -}; - -struct super_tone_rx_state_s -{ - super_tone_rx_descriptor_t *desc; - float energy; - int detected_tone; - int rotation; - tone_report_func_t tone_callback; - tone_segment_func_t segment_callback; - void *callback_data; - super_tone_rx_segment_t segments[11]; - goertzel_state_t state[]; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/super_tone_tx.h b/libs/spandsp/src/spandsp/private/super_tone_tx.h deleted file mode 100644 index cec758026d..0000000000 --- a/libs/spandsp/src/spandsp/private/super_tone_tx.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/super_tone_tx.h - Flexible telephony supervisory tone generation. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_SUPER_TONE_TX_H_) -#define _SPANDSP_PRIVATE_SUPER_TONE_TX_H_ - -struct super_tone_tx_step_s -{ - tone_gen_tone_descriptor_t tone[SUPER_TONE_TX_MAX_TONES]; - int tone_on; - int length; - int cycles; - super_tone_tx_step_t *next; - super_tone_tx_step_t *nest; -}; - -struct super_tone_tx_state_s -{ - tone_gen_tone_descriptor_t tone[SUPER_TONE_TX_MAX_TONES]; - uint32_t phase[SUPER_TONE_TX_MAX_TONES]; - int current_position; - int level; - super_tone_tx_step_t *levels[SUPER_TONE_TX_MAX_LEVELS]; - int cycles[SUPER_TONE_TX_MAX_LEVELS]; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/swept_tone.h b/libs/spandsp/src/spandsp/private/swept_tone.h deleted file mode 100644 index 52a9a03f90..0000000000 --- a/libs/spandsp/src/spandsp/private/swept_tone.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/swept_tone.h - Swept tone generation - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_SWEPT_TONE_H_) -#define _SPANDSP_PRIVATE_SWEPT_TONE_H_ - -struct swept_tone_state_s -{ - int32_t starting_phase_inc; - int32_t phase_inc_step; - int scale; - int duration; - int repeating; - int pos; - int32_t current_phase_inc; - uint32_t phase; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h deleted file mode 100644 index 0c8329bf4e..0000000000 --- a/libs/spandsp/src/spandsp/private/t30.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t30.h - definitions for T.30 fax processing - * - * 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 */ - -#if !defined(_SPANDSP_PRIVATE_T30_H_) -#define _SPANDSP_PRIVATE_T30_H_ - -/*! - T.30 FAX channel descriptor. This defines the state of a single working - instance of a T.30 FAX channel. -*/ -struct t30_state_s -{ - /*! \brief T.4 context for reading or writing image data. */ - union - { - t4_rx_state_t rx; - t4_tx_state_t tx; - } t4; - /*! \brief The type of FAX operation currently in progress */ - int operation_in_progress; - - /*! \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 for use - between FAX entities. */ - int supported_compressions; - /*! \brief A bit mask of the currently supported image compression modes for the output - of received page images. */ - int supported_output_compressions; - /*! \brief A bit mask of the currently supported bi-level image resolutions. */ - 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. */ - 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. */ - char rx_dcs_string[T30_MAX_DIS_DTC_DCS_LEN*3 + 1]; - /*! \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 - the page. */ - 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. */ - bool remote_interrupts_allowed; - - /*! \brief The information fields received. */ - t30_exchanged_info_t rx_info; - /*! \brief The information fields to be transmitted. */ - t30_exchanged_info_t tx_info; - /*! \brief The country of origin of the remote machine, if known, else NULL. */ - const char *country; - /*! \brief The vendor of the remote machine, if known, else NULL. */ - const char *vendor; - /*! \brief The model of the remote machine, if known, else NULL. */ - const char *model; - - /*! \brief A pointer to a callback routine to be called when phase B events - occur. */ - t30_phase_b_handler_t phase_b_handler; - /*! \brief An opaque pointer supplied in event B callbacks. */ - void *phase_b_user_data; - /*! \brief A pointer to a callback routine to be called when phase D events - occur. */ - t30_phase_d_handler_t phase_d_handler; - /*! \brief An opaque pointer supplied in event D callbacks. */ - void *phase_d_user_data; - /*! \brief A pointer to a callback routine to be called when phase E events - occur. */ - t30_phase_e_handler_t phase_e_handler; - /*! \brief An opaque pointer supplied in event E callbacks. */ - void *phase_e_user_data; - /*! \brief A pointer to a callback routine to be called when frames are - exchanged. */ - t30_real_time_frame_handler_t real_time_frame_handler; - /*! \brief An opaque pointer supplied in real time frame callbacks. */ - void *real_time_frame_user_data; - - /*! \brief A pointer to a callback routine to be called when document events - (e.g. end of transmitted document) occur. */ - t30_document_handler_t document_handler; - /*! \brief An opaque pointer supplied in document callbacks. */ - void *document_user_data; - - /*! \brief The handler for changes to the receive mode */ - t30_set_handler_t set_rx_type_handler; - /*! \brief An opaque pointer passed to the handler for changes to the receive mode */ - void *set_rx_type_user_data; - /*! \brief The handler for changes to the transmit mode */ - t30_set_handler_t set_tx_type_handler; - /*! \brief An opaque pointer passed to the handler for changes to the transmit mode */ - void *set_tx_type_user_data; - - /*! \brief The transmitted HDLC frame handler. */ - t30_send_hdlc_handler_t send_hdlc_handler; - /*! \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. */ - uint8_t local_min_scan_time_code; - - /*! \brief The current T.30 phase. */ - int phase; - /*! \brief The T.30 phase to change to when the current phase ends. */ - int next_phase; - /*! \brief The current state of the T.30 state machine. */ - int state; - /*! \brief The step in sending a sequence of HDLC frames. */ - int step; - - /*! \brief The preparation buffer for the DCS message to be transmitted. */ - uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN]; - /*! \brief The length of the DCS message to be transmitted. */ - int dcs_len; - /*! \brief The preparation buffer for DIS or DTC message to be transmitted. */ - uint8_t local_dis_dtc_frame[T30_MAX_DIS_DTC_DCS_LEN]; - /*! \brief The length of the DIS or DTC message to be transmitted. */ - 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 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. */ - bool short_train; - - /*! \brief True if an image carrier appears to have been received, even if it did not successfully - train. */ - bool image_carrier_attempted; - - /*! \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. */ - int tcf_test_bits; - /*! \brief The current count of consecutive received zero bits, during the trainability test. */ - int tcf_current_zeros; - /*! \brief The maximum consecutive received zero bits seen to date, during the trainability test. */ - int tcf_most_zeros; - - /*! \brief The current fallback step for the fast message transfer modem. */ - 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. */ - 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; - /*! \brief Current transmission mode. */ - int current_tx_type; - - /*! \brief T0 is the answer timeout when calling another FAX machine. - Placing calls is handled outside the FAX processing, but this timeout keeps - running until V.21 modulation is sent or received. - T1 is the remote terminal identification timeout (in audio samples). */ - int timer_t0_t1; - /*! \brief T2, T2A and T2B are the HDLC command timeouts. - T4, T4A and T4B are the HDLC response timeouts (in audio samples). */ - int timer_t2_t4; - /*! \brief A value specifying which of the possible timers is currently running in timer_t2_t4 */ - int timer_t2_t4_is; - /*! \brief Procedural interrupt timeout (in audio samples). */ - int timer_t3; - /*! \brief This is only used in error correcting mode. */ - int timer_t5; - /*! \brief This is only used in full duplex (e.g. ISDN) modes. */ - int timer_t6; - /*! \brief This is only used in full duplex (e.g. ISDN) modes. */ - int timer_t7; - /*! \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. */ - bool far_end_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. */ - 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_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. */ - 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. */ - int ppr_count; - /*! \brief The current count of consecutive T30_RNR messages. */ - int receiver_not_ready_count; - /*! \brief The number of octets to be used per ECM frame. */ - int octets_per_ecm_frame; - /*! \brief The ECM partial page buffer. */ - uint8_t ecm_data[256][260]; - /*! \brief The lengths of the frames in the ECM partial page buffer. */ - int16_t ecm_len[256]; - /*! \brief A bit map of the OK ECM frames, constructed as a PPR frame. */ - uint8_t ecm_frame_map[3 + 32]; - - /*! \brief The current page number for receiving, in ECM or non-ECM mode. This is reset at the start of a call. */ - int rx_page_number; - /*! \brief The current page number for sending, in ECM or non-ECM mode. This is reset at the start of a call. */ - int tx_page_number; - /*! \brief The current block number, in ECM mode */ - int ecm_block; - /*! \brief The number of frames in the current block number, in ECM mode */ - int ecm_frames; - /*! \brief The number of frames sent in the current burst of image transmission, in ECM mode */ - 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 - partial pages still to come. */ - bool ecm_at_page_end; - - /*! \brief The last result for a received non-ECM page - T30_MPS, T30_RTP, or T30_RTN. */ - int last_rx_page_result; - /*! \brief The transmission step queued to follow the one in progress. */ - int next_tx_step; - /*! \brief The FCF for the next receive step. */ - uint8_t next_rx_step; - /*! \brief Image file name for image reception. */ - char rx_file[256]; - /*! \brief The last page we are prepared accept for a received image file. -1 means no restriction. */ - int rx_stop_page; - /*! \brief Image file name to be sent. */ - char tx_file[256]; - /*! \brief The first page to be sent from the image file. -1 means no restriction. */ - int tx_start_page; - /*! \brief The last page to be sent from the image file. -1 means no restriction. */ - int tx_stop_page; - /*! \brief The current completion status. */ - int current_status; - - /*! \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 */ - 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; - - /*! \brief The number of RTP events */ - int rtp_events; - /*! \brief The number of RTN events */ - int rtn_events; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ 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 deleted file mode 100644 index d41132cb3f..0000000000 --- a/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h +++ /dev/null @@ -1,531 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_dis_dtc_dcs_bits.h - ITU T.30 fax control bits definitions - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_T30_DIS_DTC_DCS_BITS_H_) -#define _SPANDSP_PRIVATE_T30_DIS_DTC_DCS_BITS_H_ - -/* Indicates that the terminal has the Simple mode capability defined in ITU-T Rec. T.37. - Internet address signals CIA, TSA or CSA can be sent and received. The recipient terminal - may process or ignore this signal. */ -#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. */ -#define T30_DIS_BIT_T38 3 -#define T30_DCS_BIT_T38 3 - -/* Bit 4 set to "1" indicates 3rd Generation Mobile Network Access to the GSTN Connection. - Bit 4 set to "0" conveys no information about the type of connection. */ -#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. */ -#define T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT 10 -#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 - -#define T30_DIS_BIT_2D_CAPABLE 16 -#define T30_DCS_BIT_2D_MODE 16 - -/* Standard facsimile terminals conforming to ITU-T Rec. T.4 must have the following capability: - Paper length = 297 mm. */ - -#define T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE 17 -#define T30_DCS_BIT_255MM_WIDTH 17 - -#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_MODE 27 - -/* 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 - -/* 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 - -#define T30_DIS_BIT_PLANE_INTERLEAVE_CAPABLE 37 -#define T30_DCS_BIT_PLANE_INTERLEAVE 37 - -#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. - 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. */ - -#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 - -#define T30_DIS_BIT_PASSWORD 50 -#define T30_DCS_BIT_SENDER_ID_TRANSMISSION 50 - -/* 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 -#define T30_DCS_BIT_BFT 53 - -#define T30_DIS_BIT_DTM_CAPABLE 54 -#define T30_DCS_BIT_DTM 54 - -#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_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 - -#define T30_DIS_BIT_DUPLEX_CAPABLE 67 -#define T30_DCS_BIT_DUPLEX_CAPABLE 67 - -#define T30_DIS_BIT_T81_CAPABLE 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 - image data that are digitized to 12 bits/pel/component for JPEG mode. This is also true for T.43 mode if - bit 36 is also set to "1". In a DCS frame, setting bit 71 to "0" indicates that the calling terminal's image - data are 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 calling terminal transmits image data which has been - digitized to 12 bits/pel/component for JPEG mode. This is also true for T.43 mode if bit 36 is also set - to "1". */ -#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 - -#define T30_DIS_BIT_CUSTOM_ILLUMINANT 74 -#define T30_DCS_BIT_CUSTOM_ILLUMINANT 74 - -#define T30_DIS_BIT_CUSTOM_GAMUT_RANGE 75 -#define T30_DCS_BIT_CUSTOM_GAMUT_RANGE 75 - -#define T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE 76 -#define T30_DCS_BIT_NORTH_AMERICAN_LETTER 76 - -#define T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE 77 -#define T30_DCS_BIT_NORTH_AMERICAN_LEGAL 77 - -#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. - - Setting bit 97 to "1" indicates that the called terminal does 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 and MRC mask layer. Bit 97 is valid only when bits 68 and 42 or 43 - (300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm) are set to "1". - - In a DCS frame, setting bit 97 to "0" indicates that the calling terminal does not use - 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 and mask layer. - - Setting bit 97 to "1" indicates that the calling terminal uses 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 and MRC mask layer. - Bit 97 is valid only when bits 68 and 42 or 43 (300 pels/25.4 mm x 300 lines/25.4 mm and - 400 pels/25.4 mm x 400 lines/25.4 mm) are set to "1". - - In a DIS/DTC frame, combinations of bit 42, bit 43 and bit 97 indicate that the called terminal - has higher resolution capabilities as follows: - - Resolution capabilities (pels/25.4 mm) - DIS/DTC Monochrome Colour/gray-scale - 42 43 97 300 x 300 400 x 400 300 x 300 400 x 400 - 0 0 0 no no no no - 1 0 0 yes no no no - 0 1 0 no yes no no - 1 1 0 yes yes no no - 0 0 1 (invalid) - 1 0 1 yes no yes no - 0 1 1 no yes no yes - 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_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 - images. Setting bit 98 to "1" indicates that the called terminal does have the capability to accept - 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. Bit 98 is valid - only when bit 68 is set to "1". In a DCS frame, setting bit 98 to "0" indicates that the calling terminal does - 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_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 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 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 - -#define T30_DIS_BIT_1200_1200_CAPABLE 106 -#define T30_DCS_BIT_1200_1200 106 - -#define T30_DIS_BIT_300_600_CAPABLE 107 -#define T30_DCS_BIT_300_600 107 - -#define T30_DIS_BIT_400_800_CAPABLE 108 -#define T30_DCS_BIT_400_800 108 - -#define T30_DIS_BIT_600_1200_CAPABLE 109 -#define T30_DCS_BIT_600_1200 109 - -/* 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 - -/* 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 - -#define T30_DIS_BIT_CONTINUOUS_DOUBLE_SIDED_CAPABLE 114 -#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 - will send LAB with "1" in bit 92, 93 or 94 even if bit 119 is set to "1". - - Available colour space for DIS/DTC bits 92, 93, 94 and 119 - - 92 93 94 119 Mode of T.44 Available colour space - 0 0 0 x Not available - - 1 0 0 0 Mode 1 LAB only - 1 0 0 1 Mode 1 YCC only - x 1 x 0 Mode 2 or higher LAB only - x x 1 0 Mode 2 or higher LAB only - x 1 x 1 Mode 2 or higher LAB and YCC - x x 1 1 Mode 2 or higher LAB and YCC - - Colour space for DCS bits 92, 93, 94 and 119 - - 92 93 94 119 Mode of T.44 Colour space - 0 0 0 x* Not available - - 1 0 0 0 Mode 1 LAB - 1 0 0 1 Mode 1 YCC - x 1 x 0 Mode 2 or higher LAB - x x 1 0 Mode 2 or higher LAB - x 1 x 1 Mode 2 or higher YCC or mixing of YCC and LAB - x x 1 1 Mode 2 or higher YCC or mixing of YCC and LAB */ -#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. */ -#define T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE 121 -#define T30_DCS_BIT_T38_FLOW_CONTROL_CAPABLE 121 - -/* For resolutions greater than 200 lines/25.4 mm, 4.2.1.1/T.4 specifies the use of specific K - factors for each standardized vertical resolution. To ensure backward compatibility with earlier - versions of ITU-T Rec. T.4, bit 122 indicates when such K factors are being used. */ -#define T30_DIS_BIT_K_GREATER_THAN_4 122 - -/* This bit should be set to "1" if the fax device is an Internet-Aware Fax Device as defined in - ITU-T Rec. T.38 and if it is not affected by the data signal rate indicated by the DIS and DTC - signals when communicating with another Internet-Aware Fax Device operating in T.38 mode. This - bit shall not be used in GSTN mode. */ -#define T30_DIS_BIT_T38_FAX_CAPABLE 123 -/* This bit should be set to "1" if the fax device elects to operate in an Internet-Aware Fax mode - as defined in ITU-T Rec. T.38 in response to a device which has set the related DIS bit to "1". - 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. - - Annex K describes the optional continuous-tone colour and gray scale images mode - (sYCC-JPEG mode) protocol. When bit 127 in DIS/DTC frame is set to "1", the called terminal has the - capability to accept sYCC-JPEG mode. This is defined with complete independent in the colour space - CIELAB. In addition, when bit 127 in DCS frame is set to "1", ECM must be used and bits 15, 17, 18, - 19, 20, 41, 42, 43, 45, 46, 68, 69, 71, 73, 74, 75, 76, 77, 97, 98, 105, 106, 107, 108, - 109, 110 and 111 in DCS frame are "Don't care", and should be set to "0". In the case of - transmission of multiple images, a post message signal PPS-MPS between pages, PPS-NULL between - partial pages and PPS-EOP following the last page should be sent from the calling terminal to the - called terminal. */ -#define T30_DIS_BIT_SYCC_T81_CAPABLE 127 -#define T30_DCS_BIT_SYCC_T81_MODE 127 - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t31.h b/libs/spandsp/src/spandsp/private/t31.h deleted file mode 100644 index 373ca74fc7..0000000000 --- a/libs/spandsp/src/spandsp/private/t31.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t31.h - A T.31 compatible class 1 FAX modem interface. - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_T31_H_) -#define _SPANDSP_PRIVATE_T31_H_ - -#define T31_TX_BUF_LEN (4096) -#define T31_TX_BUF_HIGH_TIDE (4096 - 1024) -#define T31_TX_BUF_LOW_TIDE (1024) - -#define T31_MAX_HDLC_LEN 284 -/*! The maximum length of an HDLC frame buffer. This must be big enough for ECM frames. */ -#define T31_T38_MAX_HDLC_LEN 260 -/*! The number of HDLC transmit buffers */ -#define T31_TX_HDLC_BUFS 256 - -/*! - T.31 T.38 HDLC buffer. -*/ -typedef struct -{ - /*! \brief HDLC message buffers. */ - uint8_t buf[T31_MAX_HDLC_LEN]; - /*! \brief HDLC message lengths. */ - int16_t len; -} t31_hdlc_buf_t; - -/*! - T.31 T.38 HDLC state. -*/ -typedef struct -{ - /*! \brief HDLC message buffers. */ - t31_hdlc_buf_t buf[T31_TX_HDLC_BUFS]; - /*! \brief HDLC buffer number for input. */ - int in; - /*! \brief HDLC buffer number for output. */ - int out; -} t31_hdlc_state_t; - -/*! - Analogue FAX front end channel descriptor. This defines the state of a single working - instance of an analogue line FAX front end. -*/ -typedef struct -{ - fax_modems_state_t modems; - v8_state_t v8; - - /*! The transmit signal handler to be used when the current one has finished sending. */ - span_tx_handler_t next_tx_handler; - void *next_tx_user_data; - - /*! \brief No of data bits in current_byte. */ - int bit_no; - /*! \brief The current data byte in progress. */ - int current_byte; - - /*! \brief Rx power meter, used to detect silence. */ - power_meter_t rx_power; - /*! \brief Last sample, used for an elementary HPF for the power meter. */ - int16_t last_sample; - /*! \brief The current silence threshold. */ - int32_t silence_threshold_power; - - /*! \brief Samples of silence heard */ - int silence_heard; -} t31_audio_front_end_state_t; - -/*! - Analogue FAX front end channel descriptor. This defines the state of a single working - instance of an analogue line FAX front end. -*/ -typedef struct -{ - /*! \brief Internet Aware FAX mode bit mask. */ - int iaf; - /*! \brief Required time between T.38 transmissions, in us. */ - int us_per_tx_chunk; - /*! \brief Bit fields controlling the way data is packed into chunked for transmission. */ - int chunking_modes; - - /*! \brief Core T.38 IFP support */ - t38_core_state_t t38; - - /*! \brief The current transmit step being timed */ - int timed_step; - - /*! \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. */ - int octets_per_data_packet; - - /*! \brief An HDLC context used when sending HDLC messages to the terminal port - as if it were non-ECM data (ECM mode support). */ - hdlc_tx_state_t hdlc_tx_non_ecm; - /*! \brief An HDLC context used when receiving HDLC messages from the terminal port. - as if it were non-ECM data (ECM mode support). */ - hdlc_rx_state_t hdlc_rx_non_ecm; - - struct - { - uint8_t buf[T31_T38_MAX_HDLC_LEN]; - int len; - } hdlc_rx; - - struct - { - /*! \brief The number of extra bits in a fully stuffed version of the - contents of the HDLC transmit buffer. This is needed to accurately - estimate the playout time for this frame, through an analogue modem. */ - int extra_bits; - } hdlc_tx; - - t31_hdlc_state_t hdlc_from_t31; - - /*! \brief True if we are using ECM mode. This is used to select HDLC faking, which is - necessary with clunky class 1 modems. */ - int ecm_mode; - - /*! \brief Counter for trailing non-ECM bytes, used to flush out the far end's modem. */ - int non_ecm_trailer_bytes; - - /*! \brief The next queued tramsit indicator */ - int next_tx_indicator; - /*! \brief The current T.38 data type being transmitted */ - int current_tx_data_type; - - /*! \brief The current operating mode of the receiver. */ - int current_rx_type; - /*! \brief The current operating mode of the transmitter. */ - int current_tx_type; - - /*! \brief Current transmission bit rate. */ - int tx_bit_rate; - /*! \brief A "sample" count, used to time events. */ - int32_t samples; - /*! \brief The value for samples at the next transmission point. */ - int32_t next_tx_samples; - /*! \brief The current transmit timeout. */ - int32_t timeout_tx_samples; - /*! \brief The current receive timeout. */ - int32_t timeout_rx_samples; -} t31_t38_front_end_state_t; - -/*! - T.31 descriptor. This defines the working state for a single instance of - a T.31 FAX modem. -*/ -struct t31_state_s -{ - at_state_t at_state; - t31_modem_control_handler_t modem_control_handler; - void *modem_control_user_data; - - t31_audio_front_end_state_t audio; - t31_t38_front_end_state_t t38_fe; - /*! True if working in T.38 mode. */ - bool t38_mode; - - /*! HDLC buffer, for composing an HDLC frame from the computer to the channel. */ - struct - { - /*! \brief The HDLC transmit buffer. */ - 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. */ - bool final; - } hdlc_tx; - /*! Buffer for data from the computer to the channel. */ - struct - { - /*! \brief The transmit buffer. */ - uint8_t buf[T31_TX_BUF_LEN]; - /*! \brief The number of bytes stored in the transmit buffer. */ - 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. */ - 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 */ - 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. */ - bool rx_frame_received; - - /*! \brief Samples elapsed in the current call */ - int64_t call_samples; - int64_t dte_data_timeout; - - /*! \brief The currently queued modem type. */ - int modem; - /*! \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 */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t38_core.h b/libs/spandsp/src/spandsp/private/t38_core.h deleted file mode 100644 index 6d29957067..0000000000 --- a/libs/spandsp/src/spandsp/private/t38_core.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t38_core.h - An implementation of T.38, less the packet exchange part - * - * 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_T38_CORE_H_) -#define _SPANDSP_PRIVATE_T38_CORE_H_ - -/*! - Core T.38 state, common to all modes of T.38. -*/ -struct t38_core_state_s -{ - /*! \brief Handler routine to transmit IFP packets generated by the T.38 protocol engine */ - t38_tx_packet_handler_t tx_packet_handler; - /*! \brief An opaque pointer passed to tx_packet_handler */ - void *tx_packet_user_data; - - /*! \brief Handler routine to process received indicator packets */ - t38_rx_indicator_handler_t rx_indicator_handler; - /*! \brief Handler routine to process received data packets */ - t38_rx_data_handler_t rx_data_handler; - /*! \brief Handler routine to process the missing packet condition */ - t38_rx_missing_handler_t rx_missing_handler; - /*! \brief An opaque pointer passed to any of the above receive handling routines */ - void *rx_user_data; - - /*! NOTE - Bandwidth reduction shall only be done on suitable Phase C data, i.e., MH, MR - and - in the case of transcoding to JBIG - MMR. MMR and JBIG require reliable data - transport such as that provided by TCP. When transcoding is selected, it shall be - applied to every suitable page in a call. */ - - /*! \brief Method 1: Local generation of TCF (required for use with TCP). - Method 2: Transfer of TCF is required for use with UDP (UDPTL or RTP). - Method 2 is not recommended for use with TCP. */ - int data_rate_management_method; - - /*! \brief The emitting gateway may indicate a preference for either UDP/UDPTL, or - UDP/RTP, or TCP for transport of T.38 IFP Packets. The receiving device - selects the transport protocol. */ - int data_transport_protocol; - - /*! \brief Indicates the capability to remove and insert fill bits in Phase C, non-ECM - data to reduce bandwidth in the packet network. */ - int fill_bit_removal; - - /*! \brief Indicates the ability to convert to/from MMR from/to the line format to - improve the compression of the data, and reduce the bandwidth, in the - packet network. */ - int mmr_transcoding; - - /*! \brief Indicates the ability to convert to/from JBIG to reduce bandwidth. */ - int jbig_transcoding; - - /*! \brief For UDP (UDPTL or RTP) modes, this option indicates the maximum - number of octets that can be stored on the remote device before an - overflow condition occurs. It is the responsibility of the transmitting - application to limit the transfer rate to prevent an overflow. The - negotiated data rate should be used to determine the rate at which - data is being removed from the buffer. */ - int max_buffer_size; - - /*! \brief This option indicates the maximum size of a UDPTL packet or the - maximum size of the payload within an RTP packet that can be accepted - by the remote device. */ - int max_datagram_size; - - /*! \brief This is the version number of ITU-T Rec. T.38. New versions shall be - compatible with previous versions. */ - int t38_version; - - /*! \brief Allow time for TEP playout */ - int allow_for_tep; - - /*! \brief The fastest data rate supported by the T.38 channel. */ - int fastest_image_data_rate; - - /*! \brief Pace transmission */ - int pace_transmission; - - /*! \brief True if IFP packet sequence numbers are relevant. For some transports, like TPKT - over TCP they are not relevent. */ - 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 - for UDP transmission. Zero is valid for the indicator packet category, - to suppress all indicator packets (typicaly for TCP transmission). */ - int category_control[5]; - - /*! \brief The sequence number for the next packet to be transmitted */ - int tx_seq_no; - /*! \brief The sequence number expected in the next received packet */ - int rx_expected_seq_no; - - /*! \brief The current receive indicator - i.e. the last indicator received */ - int current_rx_indicator; - /*! \brief The current receive data type - i.e. the last data type received */ - int current_rx_data_type; - /*! \brief The current receive field type - i.e. the last field_type received */ - int current_rx_field_type; - /*! \brief The current transmit indicator - i.e. the last indicator transmitted */ - int current_tx_indicator; - /*! \brief The bit rate for V.34 operation */ - int v34_rate; - - /*! A count of missing receive packets. This count might not be accurate if the - received packet numbers jump wildly. */ - int missing_packets; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t38_gateway.h b/libs/spandsp/src/spandsp/private/t38_gateway.h deleted file mode 100644 index 5d3a3eb23b..0000000000 --- a/libs/spandsp/src/spandsp/private/t38_gateway.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t38_gateway.h - A T.38, less the packet exchange part - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2007 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_T38_GATEWAY_H_) -#define _SPANDSP_PRIVATE_T38_GATEWAY_H_ - -/*! The number of HDLC transmit buffers */ -#define T38_TX_HDLC_BUFS 256 -/*! The maximum length of an HDLC frame buffer. This must be big enough for ECM frames. */ -#define T38_MAX_HDLC_LEN 260 -/*! The receive buffer length */ -#define T38_RX_BUF_LEN 2048 - -/*! - T.38 gateway T.38 side channel descriptor. -*/ -typedef struct -{ - /*! \brief Core T.38 IFP support */ - t38_core_state_t t38; - - /*! \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 If NSF, NSC, and NSS are to be suppressed by altering their contents to - something the far end will not recognise, this is the string to use for overwriting. */ - uint8_t suppress_nsx_string[2][MAX_NSX_SUPPRESSION]; - - /*! \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. */ - 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; - /*! \brief The T.38 indicator currently in use */ - int in_progress_rx_indicator; - - /*! \brief The current T.38 data type being sent. */ - int current_tx_data_type; -} t38_gateway_t38_state_t; - -/*! - T.38 gateway audio side channel descriptor. -*/ -typedef struct -{ - /*! \brief The FAX modem set for the audio side fo the gateway. */ - fax_modems_state_t modems; -} t38_gateway_audio_state_t; - -/*! - T.38 gateway T.38 side state. -*/ -typedef struct -{ - /*! \brief non-ECM and HDLC modem receive data buffer. */ - uint8_t data[T38_RX_BUF_LEN]; - /*! \brief Current pointer into the data buffer. */ - int data_ptr; - /*! \brief The current octet being received as non-ECM data. */ - uint16_t bit_stream; - /*! \brief The number of bits taken from the modem for the current scan row. This - is used during non-ECM transmission with fill bit removal to see that - T.38 packet transmissions do not stretch too far apart. */ - int bits_absorbed; - /*! \brief The current bit number in the current non-ECM octet. */ - 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. */ - 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; - - /*! \brief The number of bits into the non-ECM buffer */ - int in_bits; - /*! \brief The number of octets fed out from the non-ECM buffer */ - int out_octets; -} t38_gateway_to_t38_state_t; - -/*! - T.38 gateway HDLC buffer. -*/ -typedef struct -{ - /*! \brief HDLC message buffers. */ - uint8_t buf[T38_MAX_HDLC_LEN]; - /*! \brief HDLC message lengths. */ - int16_t len; - /*! \brief HDLC message status flags. */ - uint16_t flags; - /*! \brief HDLC buffer contents. */ - int16_t contents; -} t38_gateway_hdlc_buf_t; - -/*! - T.38 gateway HDLC state. -*/ -typedef struct -{ - /*! \brief HDLC message buffers. */ - t38_gateway_hdlc_buf_t buf[T38_TX_HDLC_BUFS]; - /*! \brief HDLC buffer number for input. */ - int in; - /*! \brief HDLC buffer number for output. */ - int out; -} t38_gateway_hdlc_state_t; - -/*! - T.38 gateway core descriptor. -*/ -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. */ - 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 - follows image_data_mode, but in ECM mode T.30 defines recovery - conditions in which long training is used for image data. */ - 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 */ - 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 */ - bool ecm_mode; - /*! \brief The current bit rate for the fast modem. */ - int fast_bit_rate; - /*! \brief The current fast receive modem type. */ - int fast_rx_modem; - /*! \brief The type of fast receive modem currently active, which may be T38_NONE */ - int fast_rx_active; - - /*! \brief The current timed operation. */ - int timed_mode; - /*! \brief The number of samples until the next timeout event */ - int samples_to_timeout; - - /*! Buffer for HDLC and non-ECM data going to the T.38 channel */ - t38_gateway_to_t38_state_t to_t38; - /*! Buffer for data going to an HDLC modem. */ - t38_gateway_hdlc_state_t hdlc_to_modem; - /*! Buffer for data going to a non-ECM mode modem. */ - t38_non_ecm_buffer_state_t non_ecm_to_modem; - - /*! \brief A pointer to a callback routine to be called when frames are - exchanged. */ - t38_gateway_real_time_frame_handler_t real_time_frame_handler; - /*! \brief An opaque pointer supplied in real time frame callbacks. */ - void *real_time_frame_user_data; -} t38_gateway_core_state_t; - -/*! - T.38 gateway state. -*/ -struct t38_gateway_state_s -{ - /*! T.38 side state */ - t38_gateway_t38_state_t t38x; - /*! Audio side state */ - t38_gateway_audio_state_t audio; - /*! T.38 core state */ - t38_gateway_core_state_t core; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h deleted file mode 100644 index 9220f78af1..0000000000 --- a/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t38_non_ecm_buffer.h - A rate adapting buffer for T.38 non-ECM image - * and TCF data - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2007, 2008 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_T38_NON_ECM_BUFFER_H_) -#define _SPANDSP_PRIVATE_T38_NON_ECM_BUFFER_H_ - -/*! \brief A flow controlled non-ECM image data buffer, for buffering T.38 to analogue - modem data. -*/ -struct t38_non_ecm_buffer_state_s -{ - /*! \brief Minimum number of bits per row, used when fill bits are being deleted on the - link, and restored at the emitting gateway. */ - int min_bits_per_row; - - /*! \brief non-ECM modem transmit data buffer. */ - uint8_t data[T38_NON_ECM_TX_BUF_LEN]; - /*! \brief The current write point in the buffer. */ - int in_ptr; - /*! \brief The current read point in the buffer. */ - int out_ptr; - /*! \brief The location of the most recent EOL marker in the buffer. */ - int latest_eol_ptr; - /*! \brief The number of bits to date in the current row, used when min_row_bits is - to be applied. */ - int row_bits; - - /*! \brief The bit stream entering the buffer, used to detect EOLs */ - unsigned int bit_stream; - /*! \brief The non-ECM flow control fill octet (0xFF before the first data, and 0x00 - once data has started). */ - 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. */ - 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. */ - bool image_data_mode; - - /*! \brief The number of octets input to the buffer. */ - int in_octets; - /*! \brief The number of rows input to the buffer. */ - int in_rows; - /*! \brief The number of non-ECM fill octets generated for minimum row bits - purposes. */ - int min_row_bits_fill_octets; - /*! \brief The number of octets output from the buffer. */ - int out_octets; - /*! \brief The number of rows output from the buffer. */ - int out_rows; - /*! \brief The number of non-ECM fill octets generated for flow control - purposes. */ - int flow_control_fill_octets; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t38_terminal.h b/libs/spandsp/src/spandsp/private/t38_terminal.h deleted file mode 100644 index 219b1e3cf7..0000000000 --- a/libs/spandsp/src/spandsp/private/t38_terminal.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t38_terminal.h - T.38 termination, less the packet exchange part - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_PRIVATE_T38_TERMINAL_H_) -#define _SPANDSP_PRIVATE_T38_TERMINAL_H_ - -typedef struct -{ - /*! \brief Internet Aware FAX mode bit mask. */ - int iaf; - /*! \brief Required time between T.38 transmissions, in microseconds. */ - int us_per_tx_chunk; - /*! \brief Bit fields controlling the way data is packed into chunked for transmission. */ - int chunking_modes; - - /*! \brief Core T.38 IFP support */ - t38_core_state_t t38; - - /*! \brief The current transmit step being timed */ - int timed_step; - - /*! \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 - reception period. */ - 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. */ - int octets_per_data_packet; - - struct - { - /*! \brief HDLC receive buffer */ - uint8_t buf[T38_MAX_HDLC_LEN]; - /*! \brief The length of the contents of the HDLC receive buffer */ - int len; - } hdlc_rx; - - struct - { - /*! \brief HDLC transmit buffer */ - uint8_t buf[T38_MAX_HDLC_LEN]; - /*! \brief The length of the contents of the HDLC transmit buffer */ - int len; - /*! \brief Current pointer within the contents of the HDLC transmit buffer */ - int ptr; - /*! \brief The number of extra bits in a fully stuffed version of the - contents of the HDLC transmit buffer. This is needed to accurately - estimate the playout time for this frame, through an analogue modem. */ - int extra_bits; - } hdlc_tx; - - /*! \brief Counter for trailing non-ECM bytes, used to flush out the far end's modem. */ - int non_ecm_trailer_bytes; - - /*! \brief The next T.38 indicator queued for transmission. */ - int next_tx_indicator; - /*! \brief The current T.38 data type being transmitted. */ - int current_tx_data_type; - - /*! \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; - /*! \brief The current operating mode of the transmitter. */ - int current_tx_type; - - /*! \brief Current transmission bit rate. */ - int tx_bit_rate; - /*! \brief A "sample" count, used to time events. */ - int32_t samples; - /*! \brief The value for samples at the next transmission point. */ - int32_t next_tx_samples; - /*! \brief The current transmit timeout. */ - int32_t timeout_tx_samples; - /*! \brief The current receive timeout. */ - int32_t timeout_rx_samples; -} t38_terminal_front_end_state_t; - -/*! - T.38 terminal state. -*/ -struct t38_terminal_state_s -{ - /*! \brief The T.30 back-end */ - t30_state_t t30; - - /*! \brief The T.38 front-end */ - t38_terminal_front_end_state_t t38_fe; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t42.h b/libs/spandsp/src/spandsp/private/t42.h deleted file mode 100644 index e151afc6fc..0000000000 --- a/libs/spandsp/src/spandsp/private/t42.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t42.h - ITU T.42 JPEG for 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_T42_H_) -#define _SPANDSP_PRIVATE_T42_H_ - -#include -#include - -struct lab_params_s -{ - /* Lab gamut */ - float range_L; - float range_a; - float range_b; - float offset_L; - float offset_a; - float offset_b; - int ab_are_signed; - - /* 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 */ -struct t42_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; - uint32_t image_width; - uint32_t image_length; - uint16_t samples_per_pixel; - int image_type; - int no_subsampling; - int itu_ycc; - int quality; - - /* 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; -}; - -/* State of a working instance of the T.42 JPEG FAX decoder */ -struct t42_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; - /*! A callback routine to handle decoded comments */ - t4_row_write_handler_t comment_handler; - /*! An opaque pointer passed to comment_handler() */ - 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; - - /* 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 - pending. */ - uint8_t *comment; - /*! Length of data pointed to by comment */ - size_t comment_len; - - /*! \brief The size of the compressed image, in bytes. */ - int compressed_image_size; - - 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; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t43.h b/libs/spandsp/src/spandsp/private/t43.h deleted file mode 100644 index 59746b3bc6..0000000000 --- a/libs/spandsp/src/spandsp/private/t43.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3f89e1d38b..0000000000 --- a/libs/spandsp/src/spandsp/private/t4_rx.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t4_rx.h - definitions for T.4 FAX receive processing - * - * 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_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. -*/ -typedef struct -{ - /*! \brief The current file name. */ - const char *file; - /*! \brief The libtiff context for the current TIFF file */ - TIFF *tiff_file; - - /*! Image type - bilevel, gray, colour */ - int image_type; - /*! \brief The compression type for output to the TIFF file. */ - 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. */ - uint16_t fill_order; - - /*! \brief The number of pages in the current image file. */ - int pages_in_file; - - /*! \brief The time at which handling of the current page began. */ - time_t page_start_time; - - /*! \brief A point to the image buffer. */ - uint8_t *image_buffer; - /*! \brief The size of the image in the image buffer, in bytes. */ - int image_size; - /*! \brief The current size of the image buffer. */ - int image_buffer_size; -} t4_rx_tiff_state_t; - -/*! - T.4 FAX decompression metadata descriptor. This contains information about the image - which may be relevant to the backend, but is not relevant to the image decoding process. -*/ -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. */ - int y_resolution; - - /* "Background" information about the FAX, which can be stored in the image file. */ - /*! \brief The vendor of the machine which produced the file. */ - const char *vendor; - /*! \brief The model of machine which produced the file. */ - const char *model; - /*! \brief The remote end's ident string. */ - const char *far_ident; - /*! \brief The FAX sub-address. */ - const char *sub_address; - /*! \brief The FAX DCS information, as an ASCII hex string. */ - 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. -*/ -struct t4_rx_state_s -{ - /*! \brief Callback function to write a row of pixels to the image destination. */ - t4_row_write_handler_t row_handler; - /*! \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; - - union - { - no_decoder_state_t no_decoder; - t4_t6_decode_state_t t4_t6; - t85_decode_state_t t85; -#if defined(SPANDSP_SUPPORT_T88) - t88_decode_state_t t88; -#endif - t42_decode_state_t t42; - 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; - - /*! \brief All TIFF file specific state information for the T.4 context. */ - t4_rx_tiff_state_t tiff; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t4_t6_decode.h b/libs/spandsp/src/spandsp/private/t4_t6_decode.h deleted file mode 100644 index 616e1be879..0000000000 --- a/libs/spandsp/src/spandsp/private/t4_t6_decode.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t4_t6_decode.h - definitions for T.4/T.6 fax decoding - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2009 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_T4_T6_DECODE_H_) -#define _SPANDSP_PRIVATE_T4_T6_DECODE_H_ - -/*! - T.4 1D, T4 2D and T6 decompressor state. -*/ -struct t4_t6_decode_state_s -{ - /*! \brief Callback function to write a row of pixels to the image destination. */ - t4_row_write_handler_t row_write_handler; - /*! \brief Opaque pointer passed to row_write_handler. */ - void *row_write_user_data; - - /*! \brief The type of compression used between the FAX machines. */ - int encoding; - /*! \brief Width of the current page, in pixels. */ - int image_width; - - /*! \brief Length of the current page, in pixels. */ - int image_length; - /*! \brief The current number of bytes per row of uncompressed image data. */ - int bytes_per_row; - - /*! \brief The current number of bits in the current encoded row. */ - int row_bits; - /*! \brief Pointer to the buffer for the current pixel row. */ - uint8_t *row_buf; - - /*! \brief This variable is set if we are treating the current row as a 2D encoded - one. */ - int row_is_2d; - /*! \brief The current length of the current row. */ - int row_len; - - /*! \brief Black and white run-lengths for the current row. */ - uint32_t *cur_runs; - /*! \brief Black and white run-lengths for the reference row. */ - uint32_t *ref_runs; - - /*! \brief This variable is used to count the consecutive EOLS we have seen. If it - reaches six, this is the end of the image. It is initially set to -1 for - 1D and 2D decoding, as an indicator that we must wait for the first EOL, - before decoding any image data. */ - int consecutive_eols; - - /*! \brief The reference or starting changing element on the coding line. At the - start of the coding line, a0 is set on an imaginary white changing element - situated just before the first element on the line. During the coding of - the coding line, the position of a0 is defined by the previous coding mode. - (See T.4/4.2.1.3.2.). */ - int a0; - /*! \brief The first changing element on the reference line to the right of a0 and of - opposite colour to a0. */ - int b1; - /*! \brief The length of the in-progress run of black or white. */ - int run_length; - /*! \brief 2D horizontal mode control. */ - int black_white; - /*! \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; - /*! \brief The current step into the reference row run-lengths buffer. */ - int b_cursor; - - /*! \brief Incoming bit buffer for decompression. */ - uint32_t rx_bitstream; - /*! \brief The number of bits currently in rx_bitstream. */ - int rx_bits; - /*! \brief The number of bits to be skipped before trying to match the next code word. */ - int rx_skip_bits; - - /*! \brief Decoded pixel stream buffer. */ - uint32_t pixel_stream; - /*! \brief The number of pixels currently in pixel_stream. */ - int pixels; - - /*! \brief The minimum bits in any row of the current page. For monitoring only. */ - int min_row_bits; - /*! \brief The maximum bits in any row of the current page. For monitoring only. */ - int max_row_bits; - - /*! \brief The size of the compressed image, in bits. */ - int compressed_image_size; - /*! \brief The current number of consecutive bad rows. */ - int curr_bad_row_run; - /*! \brief The longest run of consecutive bad rows seen in the current page. */ - int longest_bad_row_run; - /*! \brief The total number of bad rows in the current page. */ - int bad_rows; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t4_t6_encode.h b/libs/spandsp/src/spandsp/private/t4_t6_encode.h deleted file mode 100644 index 4ac35f76a9..0000000000 --- a/libs/spandsp/src/spandsp/private/t4_t6_encode.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t4_t6_encode.h - definitions for T.4/T.6 fax compression - * - * 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_T4_T6_ENCODE_H_) -#define _SPANDSP_PRIVATE_T4_T6_ENCODE_H_ - -/*! - T.4 1D, T4 2D and T6 compressor state. -*/ -struct t4_t6_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; - - /*! \brief The type of compression used. */ - int encoding; - /*! \brief Width of the current page, in pixels. */ - int image_width; - /*! \brief The minimum number of encoded bits per row. This is a timing thing - for hardware FAX machines. */ - int min_bits_per_row; - /*! \brief The current maximum contiguous rows that may be 2D encoded. */ - int max_rows_to_next_1d_row; - - /*! \brief Length of the current page, in pixels. */ - int image_length; - /*! \brief The current number of bytes per row of uncompressed image data. */ - int bytes_per_row; - - /*! \brief Number of rows left that can be 2D encoded, before a 1D encoded row - must be used. */ - int rows_to_next_1d_row; - /*! \brief The current number of bits in the current encoded row. */ - int row_bits; - - /*! \brief This variable is set if we are treating the current row as a 2D encoded - one. */ - bool row_is_2d; - - /*! \brief Encoded data bits buffer. */ - uint32_t tx_bitstream; - /*! \brief The number of bits currently in tx_bitstream. */ - int tx_bits; - /*! \brief The working chunk of the output bit stream */ - uint8_t *bitstream; - /*! \brief Input pointer to the output bit stream buffer. */ - int bitstream_iptr; - /*! \brief Output pointer to the output bit stream buffer. */ - int bitstream_optr; - /*! \brief Pointer to the bit within the byte containing the next image bit to transmit. */ - int bit_pos; - - /*! \brief Black and white run-lengths for the current row. */ - uint32_t *cur_runs; - /*! \brief Black and white run-lengths for the reference row. */ - uint32_t *ref_runs; - /*! \brief The number of runs currently in the reference row. */ - int ref_steps; - - /*! \brief The minimum bits in any row of the current page. For monitoring only. */ - int min_row_bits; - /*! \brief The maximum bits in any row of the current page. For monitoring only. */ - int max_row_bits; - - /*! \brief The size of the compressed image, in bits. */ - int compressed_image_size; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h deleted file mode 100644 index 009152d9e2..0000000000 --- a/libs/spandsp/src/spandsp/private/t4_tx.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t4_tx.h - definitions for T.4 FAX transmit processing - * - * 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_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. -*/ -typedef struct -{ - /*! \brief The current file name. */ - const char *file; - /*! \brief The libtiff context for the current TIFF file */ - TIFF *tiff_file; - - /*! \brief The compression type used in the TIFF file */ - uint16_t compression; - /*! \brief Image type - bi-level, gray, colour, etc. */ - int image_type; - /*! \brief The TIFF photometric setting for the current page. */ - uint16_t photo_metric; - /*! \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; - - /*! \brief A pointer to the image buffer. */ - uint8_t *image_buffer; - /*! \brief The size of the image in the image buffer, in bytes. */ - int image_size; - /*! \brief The current size of the image buffer. */ - int image_buffer_size; - /*! \brief Row counter for playing out the rows of the image. */ - int row; - /*! \brief Row counter used when the image is resized or dithered flat. */ - int raw_row; -} t4_tx_tiff_state_t; - -/*! - T.4 FAX compression metadata descriptor. This contains information about the image - which may be relevant to the backend, but is not generally relevant to the image - encoding process. The exception here is the y-resolution, which is used in T.4 2-D - encoding for non-ECM applications, to optimise the balance of density and robustness. -*/ -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. -*/ -struct t4_tx_state_s -{ - /*! \brief Callback function to read a row of pixels from the image source. */ - t4_row_read_handler_t row_handler; - /*! \brief Opaque pointer passed to row_read_handler. */ - void *row_handler_user_data; - - /*! \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 size of the compressed image on the line side, in bits. */ - int line_image_size; - - /*! \brief The first page to transfer. -1 to start at the beginning of the file. */ - int start_page; - /*! \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 - the page. */ - 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; - /*! \brief The local ident string. This is used with header_info to form a - page header line. */ - const char *local_ident; - /*! \brief The page number of current page. The first page is zero. If FAX page - headers are used, the page number in the header will be one more than - this value (i.e. they start from 1). */ - int current_page; - - /*! \brief The composed text of the FAX page header, if there is one. */ - char *header_text; - /*! \brief Optional per instance time zone for the FAX page header timestamp. */ - tz_t *tz; - - /*! \brief Row counter for playing out the rows of the header line. */ - int header_row; - - union - { - no_encoder_state_t no_encoder; - t4_t6_encode_state_t t4_t6; - t85_encode_state_t t85; -#if defined(SPANDSP_SUPPORT_T88) - t88_encode_state_t t88; -#endif - t42_encode_state_t t42; - t43_encode_state_t t43; -#if defined(SPANDSP_SUPPORT_T45) - t45_encode_state_t t45; -#endif - } encoder; - - t4_image_get_handler_t image_get_handler; - - int apply_lab; - lab_params_t lab_params; - uint8_t *colour_map; - int colour_map_entries; - - 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. */ - t4_tx_tiff_state_t tiff; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t81_t82_arith_coding.h b/libs/spandsp/src/spandsp/private/t81_t82_arith_coding.h deleted file mode 100644 index 0efe3f00ca..0000000000 --- a/libs/spandsp/src/spandsp/private/t81_t82_arith_coding.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t81_t82_arith_coding.h - ITU T.81 and T.82 QM-coder arithmetic encoding - * and decoding - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_T81_T82_ARITH_CODING_H_) -#define _SPANDSP_PRIVATE_T81_T82_ARITH_CODING_H_ - -/* State of a working instance of the QM-coder arithmetic encoder */ -struct t81_t82_arith_encode_state_s -{ - /*! A register - see T.82 Table 23 */ - uint32_t a; - /*! C register - see T.82 Table 23 */ - uint32_t c; - /*! Probability status for contexts. MSB = MPS */ - uint8_t st[4096]; - /*! Number of buffered 0xFF values that might still overflow */ - int32_t sc; - /*! Bit shift counter. This determines when the next byte will be written */ - int ct; - /*! Buffer for the most recent output byte which is not 0xFF */ - int buffer; - /*! Callback function to deliver the encoded data, byte by byte */ - void (*output_byte_handler)(void *, int); - /*! Opaque pointer passed to byte_out */ - void *user_data; -}; - -/* State of a working instance of the QM-coder arithmetic decoder */ -struct t81_t82_arith_decode_state_s -{ - /*! A register - see T.82 Table 25 */ - uint32_t a; - /*! C register - see T.82 Table 25 */ - uint32_t c; - /*! Probability status for contexts. MSB = MPS */ - uint8_t st[4096]; - /*! Bit-shift counter. Determines when next byte will be read. - Special value -1 signals that zero-padding has started */ - int ct; - /*! Pointer to next PSCD data byte */ - const uint8_t *pscd_ptr; - /*! Pointer to byte after PSCD */ - const uint8_t *pscd_end; - /*! Boolean flag that controls initial fill of s->c */ - int startup; - /*! Boolean flag that triggers return -2 between reaching PSCD end - and decoding the first symbol that might never have been encoded - in the first place */ - int nopadding; -}; - -#endif - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t85.h b/libs/spandsp/src/spandsp/private/t85.h deleted file mode 100644 index 5eb2b50676..0000000000 --- a/libs/spandsp/src/spandsp/private/t85.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/t85.h - ITU T.85 JBIG for FAX image processing - * - * Written by Steve Underwood - * - * Copyright (C) 2008, 2009 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_T85_H_) -#define _SPANDSP_PRIVATE_T85_H_ - -/* Maximum number of ATMOVEs per stripe that the decoder can handle */ -#define T85_ATMOVES_MAX 1 - -/* TP special pixels */ -#define TPB2CX 0x195 -#define TPB3CX 0x0E5 - -/* T.82 table 2 - symbolic constants */ -enum -{ - T82_STUFF = 0x00, - T82_RESERVE = 0x01, - T82_SDNORM = 0x02, - T82_SDRST = 0x03, - T82_ABORT = 0x04, - T82_NEWLEN = 0x05, - T82_ATMOVE = 0x06, - T82_COMMENT = 0x07, - T82_ESC = 0xFF -}; - -/* State of a working instance of the T.85 JBIG FAX encoder */ -struct t85_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; - - /*! The number of bit planes. Always 1 for true T.85 */ - uint8_t bit_planes; - uint8_t current_bit_plane; - /*! The width of the full image, in pixels */ - uint32_t xd; - /*! The height of the full image, in pixels */ - uint32_t yd; - /*! The number of rows per stripe */ - uint32_t l0; - /*! Maximum ATMOVE window size (0 - 127) */ - int mx; - /*! Encoding parameters */ - int options; - /*! 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 - pending. */ - const uint8_t *comment; - /*! Length of data pointed to by comment */ - size_t comment_len; - - /*! Next row number to be encoded */ - uint32_t y; - /*! Next row within current stripe */ - uint32_t i; - /*! Flag for handling NEWLEN processing. */ - int newlen; - /*! X-offset of adaptive template pixel */ - int32_t tx; - /*! Adaptive template algorithm variables */ - uint32_t c_all; - /*! Adaptive template algorithm variables */ - uint32_t c[128]; - /*! New TX value, or <0 for analysis in progress */ - int32_t new_tx; - /*! 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 - we divide up for the 3 row buffers. */ - uint8_t *row_buf; - uint8_t *bitstream; - int bitstream_len; - int bitstream_iptr; - int bitstream_optr; - int fill_with_white; - - /*! \brief The size of the compressed image, in bytes. */ - int compressed_image_size; - - /*! Arithmetic encoder state */ - t81_t82_arith_encode_state_t s; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -/* State of a working instance of the T.85 JBIG FAX decoder */ -struct t85_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; - /*! A callback routine to handle decoded comments */ - t4_row_write_handler_t comment_handler; - /*! An opaque pointer passed to comment_handler() */ - void *comment_user_data; - /*! The maximum length of comment to be passed to the comment handler */ - uint32_t max_comment_len; - - uint8_t min_bit_planes; - uint8_t max_bit_planes; - /*! The maximum permitted width of the full image, in pixels */ - uint32_t max_xd; - /*! The maximum permitted height of the full image, in pixels */ - uint32_t max_yd; - - /*! The number of bit planes expected, according to the header. Always 1 for true T.85 */ - uint8_t bit_planes; - uint8_t current_bit_plane; - - /*! The width of the full image, in pixels */ - uint32_t xd; - /*! The height of the full image, in pixels */ - uint32_t yd; - /*! The number of rows per stripe */ - uint32_t l0; - /*! Maximum ATMOVE window size */ - int mx; - /*! Encoding parameters */ - int options; - - /*! The current row and the previous 2 rows of image data */ - int p[3]; - /*! Pointers to the 3 row buffers */ - uint8_t *prev_row[3]; - /*! Pointer to a block of allocated memory 3 rows long, which - we divide up for the 3 row buffers. */ - uint8_t *row_buf; - /*! The length of the row buffer */ - int row_buf_len; - /*! Bytes per pixel row */ - size_t bytes_per_row; - /*! X-offset of AT pixel */ - int32_t tx; - /*! Number of bytes read so far */ - uint32_t bie_len; - /*! Buffer space for the BIH or marker segments fragments */ - uint8_t buffer[20]; - /*! Number of bytes in buffer. */ - int buf_len; - /*! Required number of bytes in buffer to proceed with processing - its contents. */ - int buf_needed; - /*! The content of a decoded COMMENT marker segment. */ - uint8_t *comment; - /*! The expected length of a decoded COMMENT segment */ - uint32_t comment_len; - /*! The length of COMMENT decoded to date */ - uint32_t comment_progress; - /*! Current column */ - uint32_t x; - /*! Current row */ - uint32_t y; - /*! Current row within the current stripe */ - uint32_t i; - /*! Number of AT moves in the current stripe */ - int at_moves; - /*! Rows at which an AT move will happen */ - uint32_t at_row[T85_ATMOVES_MAX]; - /*! ATMOVE x-offsets in current stripe */ - int at_tx[T85_ATMOVES_MAX]; - /*! Working data for decode_pscd() */ - uint32_t row_h[3]; - /*! Flag for TPBON/TPDON: next pixel is a pseudo pixel */ - int pseudo; - /*! Line is not typical flag. */ - int lntp; - /*! Flag that row_write_handler() requested an interrupt. */ - int interrupt; - /*! Flag that the data to be decoded has run out. */ - int end_of_data; - /*! Arithmetic decoder state */ - t81_t82_arith_decode_state_t s; - - /*! \brief The size of the compressed image, in bytes. */ - int compressed_image_size; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/time_scale.h b/libs/spandsp/src/spandsp/private/time_scale.h deleted file mode 100644 index 1b55a00874..0000000000 --- a/libs/spandsp/src/spandsp/private/time_scale.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/time_scale.h - Time scaling for linear speech data - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_TIME_SCALE_H_) -#define _SPANDSP_PRIVATE_TIME_SCALE_H_ - -#define TIME_SCALE_MAX_SAMPLE_RATE 48000 -#define TIME_SCALE_MIN_PITCH 60 -#define TIME_SCALE_MAX_PITCH 250 -#define TIME_SCALE_BUF_LEN (2*TIME_SCALE_MAX_SAMPLE_RATE/TIME_SCALE_MIN_PITCH) - -/*! Audio time scaling descriptor. */ -struct time_scale_state_s -{ - /*! \brief The sample rate of both the incoming and outgoing signal */ - int sample_rate; - /*! \brief The minimum pitch we will search for, in samples per cycle */ - int min_pitch; - /*! \brief The maximum pitch we will search for, in samples per cycle */ - int max_pitch; - /*! \brief The playout speed, as the fraction output time/input time. - (i.e. >1.0 == slow down, 1.0 == no speed change, <1.0 == speed up) */ - float playout_rate; - /*! \brief */ - double rcomp; - /*! \brief The fractional sample adjustment, to allow for non-integer values of lcp. */ - double rate_nudge; - /*! \brief */ - int lcp; - /*! \brief The active length of buf at the current sample rate. */ - int buf_len; - /*! \brief The number of samples in buf */ - int fill; - /*! \brief Buffer for residual samples kept over from one call of time_scale() to - the next. */ - int16_t buf[TIME_SCALE_BUF_LEN]; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/timezone.h b/libs/spandsp/src/spandsp/private/timezone.h deleted file mode 100644 index 78519f0f7a..0000000000 --- a/libs/spandsp/src/spandsp/private/timezone.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/timezone.h - Timezone handling for time interpretation - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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_TIMEZONE_H_) -#define _SPANDSP_PRIVATE_TIMEZONE_H_ - -#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ - -#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ - -#define SPANDSP_TZNAME_MAX 255 - -/* The TZ_MAX_TIMES value below is enough to handle a bit more than a - * year's worth of solar time (corrected daily to the nearest second) or - * 138 years of Pacific Presidential Election time - * (where there are three time zone transitions every fourth year). */ -#define TZ_MAX_TIMES 370 - -#if !defined(NOSOLAR) -#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ -#else -/* Must be at least 14 for Europe/Riga as of Jan 12 1995, - * as noted by Earl Chew . */ -#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ -#endif - -#define TZ_BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - -/* Time type information */ -struct tz_ttinfo_s -{ - int32_t gmtoff; /* UTC offset in seconds */ - int isdst; /* Used to set tm_isdst */ - int abbrind; /* Abbreviation list index */ - bool ttisstd; /* True if transition is std time */ - bool ttisgmt; /* True if transition is UTC */ -}; - -/* Leap second information */ -struct tz_lsinfo_s -{ - time_t trans; /* Transition time */ - int32_t corr; /* Correction to apply */ -}; - -struct tz_state_s -{ - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - time_t ats[TZ_MAX_TIMES]; - uint8_t types[TZ_MAX_TIMES]; - struct tz_ttinfo_s ttis[TZ_MAX_TYPES]; - char chars[TZ_BIGGEST(TZ_MAX_CHARS + 1, (2*(SPANDSP_TZNAME_MAX + 1)))]; - struct tz_lsinfo_s lsis[TZ_MAX_LEAPS]; -}; - -struct tz_s -{ - struct tz_state_s state; - char lcl_tzname[SPANDSP_TZNAME_MAX + 1]; - int lcl_is_set; - const char *tzname[2]; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/tone_detect.h b/libs/spandsp/src/spandsp/private/tone_detect.h deleted file mode 100644 index 2b4a1d276b..0000000000 --- a/libs/spandsp/src/spandsp/private/tone_detect.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/tone_detect.h - General telephony tone detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 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_TONE_DETECT_H_) -#define _SPANDSP_PRIVATE_TONE_DETECT_H_ - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/tone_generate.h b/libs/spandsp/src/spandsp/private/tone_generate.h deleted file mode 100644 index 12dfaeb5d4..0000000000 --- a/libs/spandsp/src/spandsp/private/tone_generate.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/tone_generate.h - General telephony tone generation. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_TONE_GENERATE_H_) -#define _SPANDSP_PRIVATE_TONE_GENERATE_H_ - -struct tone_gen_tone_descriptor_s -{ - int32_t phase_rate; -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t gain; -#else - float gain; -#endif -}; - -/*! - Cadenced multi-tone generator descriptor. -*/ -struct tone_gen_descriptor_s -{ - tone_gen_tone_descriptor_t tone[4]; - int duration[4]; - int repeat; -}; - -/*! - Cadenced multi-tone generator state descriptor. This defines the state of - a single working instance of a generator. -*/ -struct tone_gen_state_s -{ - tone_gen_tone_descriptor_t tone[4]; - - uint32_t phase[4]; - int duration[4]; - int repeat; - - int current_section; - int current_position; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v17rx.h b/libs/spandsp/src/spandsp/private/v17rx.h deleted file mode 100644 index f6f847c553..0000000000 --- a/libs/spandsp/src/spandsp/private/v17rx.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v17rx.h - ITU V.17 modem receive part - * - * 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_V17RX_H_) -#define _SPANDSP_PRIVATE_V17RX_H_ - -/* Target length for the equalizer is about 63 taps, to deal with the worst stuff - in V.56bis. */ -/*! The length of the equalizer buffer */ -#define V17_EQUALIZER_LEN 33 - -/*! Samples before the target position in the equalizer buffer */ -#define V17_EQUALIZER_PRE_LEN 16 - -/*! The number of taps in the pulse shaping/bandpass filter */ -#define V17_RX_FILTER_STEPS 27 - -/* We can store more trellis depth that we look back over, so that we can push out a group - of symbols in one go, giving greater processing efficiency, at the expense of a bit more - latency through the modem. */ -/* Right now we don't take advantage of this optimisation. */ -/*! The depth of the trellis buffer */ -#define V17_TRELLIS_STORAGE_DEPTH 16 -/*! How far we look back into history for trellis decisions */ -#define V17_TRELLIS_LOOKBACK_DEPTH 16 - -/*! - V.17 modem receive side descriptor. This defines the working state for a - single instance of a V.17 modem receiver. -*/ -struct v17_rx_state_s -{ - /*! \brief The bit rate of the modem. Valid values are 7200 9600, 12000 and 14400. */ - int bit_rate; - /*! \brief The callback function used to put each bit received. */ - put_bit_func_t put_bit; - /*! \brief A user specified opaque pointer passed to the put_but routine. */ - void *put_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - /*! \brief A callback function which may be enabled to report every symbol's - constellation position. */ - qam_report_handler_t qam_report; - /*! \brief A user specified opaque pointer passed to the qam_report callback - routine. */ - void *qam_user_data; - -#if defined(SPANDSP_USE_FIXED_POINTx) - /*! \brief The scaling factor assessed by the AGC algorithm. */ - int16_t agc_scaling; - /*! \brief The previous value of agc_scaling, needed to reuse old training. */ - int16_t agc_scaling_save; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - int16_t eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexi16_t eq_coeff[V17_EQUALIZER_LEN]; - /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */ - complexi16_t eq_coeff_save[V17_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexi16_t eq_buf[V17_EQUALIZER_LEN]; - - /*! Low band edge filter for symbol sync. */ - int32_t symbol_sync_low[2]; - /*! High band edge filter for symbol sync. */ - int32_t symbol_sync_high[2]; - /*! DC filter for symbol sync. */ - int32_t symbol_sync_dc_filter[2]; - /*! Baud phase for symbol sync. */ - int32_t baud_phase; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - int32_t training_error; - - /*! \brief The proportional part of the carrier tracking filter. */ - int32_t carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - int32_t carrier_track_i; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter[V17_RX_FILTER_STEPS]; - - /*! \brief A pointer to the current constellation. */ - const complexi16_t *constellation; -#else - /*! \brief The scaling factor assessed by the AGC algorithm. */ - float agc_scaling; - /*! \brief The previous value of agc_scaling, needed to reuse old training. */ - float agc_scaling_save; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - float eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexf_t eq_coeff[V17_EQUALIZER_LEN]; - /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */ - complexf_t eq_coeff_save[V17_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexf_t eq_buf[V17_EQUALIZER_LEN]; - - /*! Low band edge filter for symbol sync. */ - float symbol_sync_low[2]; - /*! High band edge filter for symbol sync. */ - float symbol_sync_high[2]; - /*! DC filter for symbol sync. */ - float symbol_sync_dc_filter[2]; - /*! Baud phase for symbol sync. */ - float baud_phase; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - float training_error; - - /*! \brief The proportional part of the carrier tracking filter. */ - float carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - float carrier_track_i; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter[V17_RX_FILTER_STEPS]; - - /*! \brief A pointer to the current constellation. */ - const complexf_t *constellation; -#endif - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The current state of the differential decoder */ - int diff; - /*! \brief The register for the data scrambler. */ - uint32_t scramble_reg; - /*! \brief Scrambler tap */ - int scrambler_tap; - - /*! \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. */ - int training_count; - /*! \brief The value of the last signal sample, using the a simple HPF for signal power estimation. */ - int16_t last_sample; - /*! \brief >0 if a signal above the minimum is present. It may or may not be a V.17 signal. */ - int signal_present; - /*! \brief Whether or not a carrier drop was detected and the signal delivery is pending. */ - int carrier_drop_pending; - /*! \brief A count of the current consecutive samples below the carrier off threshold. */ - int low_samples; - /*! \brief A highest magnitude sample seen. */ - int16_t high_sample; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The carrier update rate saved for reuse when using short training. */ - int32_t carrier_phase_rate_save; - - /*! \brief A power meter, to measure the HPF'ed signal power in the channel. */ - power_meter_t power; - /*! \brief The power meter level at which carrier on is declared. */ - int32_t carrier_on_power; - /*! \brief The power meter level at which carrier off is declared. */ - int32_t carrier_off_power; - - /*! \brief Current read offset into the equalizer buffer. */ - int eq_step; - /*! \brief Current write offset into the equalizer buffer. */ - int eq_put_step; - /*! \brief Symbol count to the next equalizer update. */ - int eq_skip; - - /*! \brief The current half of the baud. */ - int baud_half; - - /*! \brief The total symbol timing correction since the carrier came up. - This is only for performance analysis purposes. */ - int total_baud_timing_correction; - - /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */ - int32_t last_angles[2]; - /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */ - int32_t diff_angles[16]; - - /*! \brief A pointer to the current space map. There is a space map for - each trellis state. */ - int space_map; - /*! \brief The number of bits in each symbol at the current bit rate. */ - int bits_per_symbol; - - /*! \brief Current pointer to the trellis buffers */ - int trellis_ptr; - /*! \brief The trellis. */ - int full_path_to_past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8]; - /*! \brief The trellis. */ - int past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8]; -#if defined(SPANDSP_USE_FIXED_POINTx) - /*! \brief Euclidean distances (actually the squares of the distances) - from the last states of the trellis. */ - uint32_t distances[8]; -#else - /*! \brief Euclidean distances (actually the squares of the distances) - from the last states of the trellis. */ - float distances[8]; -#endif - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v17tx.h b/libs/spandsp/src/spandsp/private/v17tx.h deleted file mode 100644 index acf2819371..0000000000 --- a/libs/spandsp/src/spandsp/private/v17tx.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v17tx.h - ITU V.17 modem transmit part - * - * 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_V17TX_H_) -#define _SPANDSP_PRIVATE_V17TX_H_ - -/*! The number of taps in the pulse shaping/bandpass filter */ -#define V17_TX_FILTER_STEPS 9 - -/*! - V.17 modem transmit side descriptor. This defines the working state for a - single instance of a V.17 modem transmitter. -*/ -struct v17_tx_state_s -{ - /*! \brief The bit rate of the modem. Valid values are 4800, 7200 and 9600. */ - int bit_rate; - /*! \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 function. */ - void *get_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The gain factor needed to achieve the specified output power. */ - int16_t gain; - /*! \brief A pointer to the constellation currently in use. */ - const complexi16_t *constellation; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter_re[V17_TX_FILTER_STEPS]; - int16_t rrc_filter_im[V17_TX_FILTER_STEPS]; -#else - /*! \brief The gain factor needed to achieve the specified output power. */ - float gain; - /*! \brief A pointer to the constellation currently in use. */ - const complexf_t *constellation; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter_re[V17_TX_FILTER_STEPS]; - float rrc_filter_im[V17_TX_FILTER_STEPS]; -#endif - - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The current state of the differential encoder. */ - int diff; - /*! \brief The current state of the convolutional encoder. */ - int convolution; - /*! \brief The code number for the current position in the constellation. */ - int constellation_state; - - /*! \brief The register for the data scrambler. */ - uint32_t scramble_reg; - /*! \brief Scrambler tap */ - int scrambler_tap; - /*! \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; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The current fractional phase of the baud timing. */ - int baud_phase; - - /*! \brief The current number of data bits per symbol. This does not include - the redundant bit. */ - int bits_per_symbol; - /*! \brief The get_bit function in use at any instant. */ - get_bit_func_t current_get_bit; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v18.h b/libs/spandsp/src/spandsp/private/v18.h deleted file mode 100644 index 7a82e71df7..0000000000 --- a/libs/spandsp/src/spandsp/private/v18.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v18.h - V.18 text telephony for the deaf. - * - * Written by Steve Underwood - * - * Copyright (C) 2004-2009 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_V18_H_) -#define _SPANDSP_PRIVATE_V18_H_ - -struct v18_state_s -{ - /*! \brief True if we are the calling modem */ - bool calling_party; - int mode; - int initial_mode; - int current_mode; - int nation; - put_msg_func_t put_msg; - void *user_data; - bool repeat_shifts; - bool autobauding; - - union - { - queue_state_t queue; - uint8_t buf[QUEUE_STATE_T_SIZE(128)]; - } queue; - tone_gen_descriptor_t alert_tone_desc; - tone_gen_state_t alert_tone_gen; - 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; - bool tx_draining; - uint8_t next_byte; - - fsk_rx_state_t fsk_rx; - dtmf_rx_state_t dtmf_rx; - -#if defined(SPANDSP_USE_FIXED_POINTx) - /*! Minimum acceptable tone level for detection. */ - int32_t threshold; - /*! The accumlating total energy on the same period over which the Goertzels work. */ - int32_t energy; -#else - /*! Minimum acceptable tone level for detection. */ - float threshold; - /*! The accumlating total energy on the same period over which the Goertzels work. */ - float energy; -#endif - goertzel_state_t tone_390; - goertzel_state_t tone_980; - goertzel_state_t tone_1180; - goertzel_state_t tone_1270; - goertzel_state_t tone_1300; - goertzel_state_t tone_1400; - goertzel_state_t tone_1650; - goertzel_state_t tone_1800; - /*! The current sample number within a processing block. */ - int current_sample; - /*! Tone state duration */ - int duration; - int target_duration; - int in_tone; - - int baudot_rx_shift; - int consecutive_ones; - uint8_t rx_msg[256 + 1]; - int rx_msg_len; - int bit_pos; - int in_progress; - int rx_suppression; - int tx_suppression; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v22bis.h b/libs/spandsp/src/spandsp/private/v22bis.h deleted file mode 100644 index dac5becb68..0000000000 --- a/libs/spandsp/src/spandsp/private/v22bis.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v22bis.h - ITU V.22bis modem - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_V22BIS_H_) -#define _SPANDSP_PRIVATE_V22BIS_H_ - -/*! The length of the equalizer buffer */ -#define V22BIS_EQUALIZER_LEN 17 -/*! Samples before the target position in the equalizer buffer */ -#define V22BIS_EQUALIZER_PRE_LEN 8 - -/*! The number of taps in the transmit pulse shaping filter */ -#define V22BIS_TX_FILTER_STEPS 9 - -/*! The number of taps in the receive pulse shaping/bandpass filter */ -#define V22BIS_RX_FILTER_STEPS 27 - -/*! Segments of the training sequence on the receive side */ -enum -{ - V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION, - V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION, - V22BIS_RX_TRAINING_STAGE_LOG_PHASE, - V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES, - V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING, - V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200, - V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING, - V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400, - V22BIS_RX_TRAINING_STAGE_PARKED -}; - -/*! Segments of the training sequence on the transmit side */ -enum -{ - V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION = 0, - V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE, - V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE, - V22BIS_TX_TRAINING_STAGE_U11, - V22BIS_TX_TRAINING_STAGE_U0011, - V22BIS_TX_TRAINING_STAGE_S11, - V22BIS_TX_TRAINING_STAGE_TIMED_S11, - V22BIS_TX_TRAINING_STAGE_S1111, - V22BIS_TX_TRAINING_STAGE_PARKED -}; - -#if defined(SPANDSP_USE_FIXED_POINT) -extern const complexi16_t v22bis_constellation[16]; -#else -extern const complexf_t v22bis_constellation[16]; -#endif - -/*! - V.22bis modem descriptor. This defines the working state for a single instance - of a V.22bis modem. -*/ -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. */ - 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. */ - void *get_bit_user_data; - /*! \brief The callback function used to put each bit received. */ - put_bit_func_t put_bit; - /*! \brief A user specified opaque pointer passed to the put_bit callback routine. */ - void *put_bit_user_data; - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - int negotiated_bit_rate; - - /* Receive section */ - struct - { - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The register for the data scrambler. */ - uint32_t scramble_reg; - /*! \brief A counter for the number of consecutive bits of repeating pattern through - the scrambler. */ - int scrambler_pattern_count; - - /*! \brief 0 if receiving user data. A training stage value during training */ - int training; - /*! \brief A count of how far through the current training step we are. */ - int training_count; - - /*! \brief >0 if a signal above the minimum is present. It may or may not be a V.22bis signal. */ - int signal_present; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - - /*! \brief A callback function which may be enabled to report every symbol's - constellation position. */ - qam_report_handler_t qam_report; - /*! \brief A user specified opaque pointer passed to the qam_report callback - routine. */ - void *qam_user_data; - - /*! \brief A power meter, to measure the HPF'ed signal power in the channel. */ - power_meter_t rx_power; - /*! \brief The power meter level at which carrier on is declared. */ - int32_t carrier_on_power; - /*! \brief The power meter level at which carrier off is declared. */ - int32_t carrier_off_power; - - int constellation_state; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The scaling factor assessed by the AGC algorithm. */ - int16_t agc_scaling; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter[V22BIS_RX_FILTER_STEPS]; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - int16_t eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexi16_t eq_coeff[V22BIS_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexi16_t eq_buf[V22BIS_EQUALIZER_LEN]; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - int32_t training_error; - /*! \brief The proportional part of the carrier tracking filter. */ - int32_t carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - int32_t carrier_track_i; -#else - /*! \brief The scaling factor assessed by the AGC algorithm. */ - float agc_scaling; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter[V22BIS_RX_FILTER_STEPS]; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - float eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexf_t eq_coeff[V22BIS_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexf_t eq_buf[V22BIS_EQUALIZER_LEN]; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - float training_error; - /*! \brief The proportional part of the carrier tracking filter. */ - float carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - float carrier_track_i; -#endif - /*! \brief Current offset into the equalizer buffer. */ - int eq_step; - /*! \brief Current write offset into the equalizer buffer. */ - int eq_put_step; - - /*! \brief Integration variable for damping the Gardner algorithm tests. */ - int gardner_integrate; - /*! \brief Current step size of Gardner algorithm integration. */ - int gardner_step; - /*! \brief The total symbol timing correction since the carrier came up. - This is only for performance analysis purposes. */ - int total_baud_timing_correction; - /*! \brief The current fractional phase of the baud timing. */ - int baud_phase; - - int sixteen_way_decisions; - - int pattern_repeats; - int last_raw_bits; - } rx; - - /* Transmit section */ - struct - { -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The guard tone level. */ - int16_t guard_tone_gain; - /*! \brief The gain factor needed to achieve the specified output power. */ - int16_t gain; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter_re[V22BIS_TX_FILTER_STEPS]; - int16_t rrc_filter_im[V22BIS_TX_FILTER_STEPS]; -#else - /*! \brief The guard tone level. */ - float guard_tone_gain; - /*! \brief The gain factor needed to achieve the specified output power. */ - float gain; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter_re[V22BIS_TX_FILTER_STEPS]; - float rrc_filter_im[V22BIS_TX_FILTER_STEPS]; -#endif - - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The register for the data scrambler. */ - uint32_t scramble_reg; - /*! \brief A counter for the number of consecutive bits of repeating pattern through - the scrambler. */ - int scrambler_pattern_count; - - /*! \brief 0 if transmitting user data. A training stage value during training */ - int training; - /*! \brief A counter used to track progress through sending the training sequence. */ - int training_count; - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The current phase of the guard tone (i.e. the DDS parameter). */ - uint32_t guard_phase; - /*! \brief The update rate for the phase of the guard tone (i.e. the DDS increment). */ - int32_t guard_phase_rate; - /*! \brief The current fractional phase of the baud timing. */ - int baud_phase; - /*! \brief The code number for the current position in the constellation. */ - int constellation_state; - /*! \brief An indicator to mark that we are tidying up to stop transmission. */ - int shutdown; - /*! \brief The get_bit function in use at any instant. */ - get_bit_func_t current_get_bit; - } tx; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Reinitialise an existing V.22bis modem receive context. - \brief Reinitialise an existing V.22bis modem receive context. - \param s The modem context. - \return 0 for OK, -1 for bad parameter */ -int v22bis_rx_restart(v22bis_state_t *s); - -void v22bis_report_status_change(v22bis_state_t *s, int status); - -void v22bis_equalizer_coefficient_reset(v22bis_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v27ter_rx.h b/libs/spandsp/src/spandsp/private/v27ter_rx.h deleted file mode 100644 index fc7912febc..0000000000 --- a/libs/spandsp/src/spandsp/private/v27ter_rx.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v27ter_rx.h - ITU V.27ter modem receive part - * - * 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_V27TER_RX_H_) -#define _SPANDSP_PRIVATE_V27TER_RX_H_ - -/* Target length for the equalizer is about 43 taps for 4800bps and 32 taps for 2400bps - to deal with the worst stuff in V.56bis. */ -/*! The length of the equalizer buffer. Must be a power of 2 */ -#define V27TER_EQUALIZER_LEN 32 -/*! Samples before the target central position in the equalizer buffer */ -#define V27TER_EQUALIZER_PRE_LEN 16 - -/*! The number of taps in the 4800bps pulse shaping/bandpass filter */ -#define V27TER_RX_4800_FILTER_STEPS 27 -/*! The number of taps in the 2400bps pulse shaping/bandpass filter */ -#define V27TER_RX_2400_FILTER_STEPS 27 - -#if V27TER_RX_4800_FILTER_STEPS > V27TER_RX_2400_FILTER_STEPS -#define V27TER_RX_FILTER_STEPS V27TER_RX_4800_FILTER_STEPS -#else -#define V27TER_RX_FILTER_STEPS V27TER_RX_2400_FILTER_STEPS -#endif - -/*! - V.27ter modem receive side descriptor. This defines the working state for a - single instance of a V.27ter modem receiver. -*/ -struct v27ter_rx_state_s -{ - /*! \brief The bit rate of the modem. Valid values are 2400 and 4800. */ - int bit_rate; - /*! \brief The callback function used to put each bit received. */ - put_bit_func_t put_bit; - /*! \brief A user specified opaque pointer passed to the put_bit routine. */ - void *put_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - /*! \brief A callback function which may be enabled to report every symbol's - constellation position. */ - qam_report_handler_t qam_report; - /*! \brief A user specified opaque pointer passed to the qam_report callback - routine. */ - void *qam_user_data; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The scaling factor assessed by the AGC algorithm. */ - int16_t agc_scaling; - /*! \brief The previous value of agc_scaling, needed to reuse old training. */ - int16_t agc_scaling_save; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - int16_t eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexi16_t eq_coeff[V27TER_EQUALIZER_LEN]; - /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */ - complexi16_t eq_coeff_save[V27TER_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexi16_t eq_buf[V27TER_EQUALIZER_LEN]; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - int32_t training_error; - - /*! \brief The proportional part of the carrier tracking filter. */ - int32_t carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - int32_t carrier_track_i; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter[V27TER_RX_FILTER_STEPS]; -#else - /*! \brief The scaling factor assessed by the AGC algorithm. */ - float agc_scaling; - /*! \brief The previous value of agc_scaling, needed to reuse old training. */ - float agc_scaling_save; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - float eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexf_t eq_coeff[V27TER_EQUALIZER_LEN]; - /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */ - complexf_t eq_coeff_save[V27TER_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexf_t eq_buf[V27TER_EQUALIZER_LEN]; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - float training_error; - - /*! \brief The proportional part of the carrier tracking filter. */ - float carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - float carrier_track_i; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter[V27TER_RX_FILTER_STEPS]; -#endif - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The register for the training and data scrambler. */ - uint32_t scramble_reg; - /*! \brief A counter for the number of consecutive bits of repeating pattern through - the scrambler. */ - 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. */ - 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. */ - int training_count; - /*! \brief The value of the last signal sample, using the a simple HPF for signal power estimation. */ - int16_t last_sample; - /*! \brief >0 if a signal above the minimum is present. It may or may not be a V.27ter signal. */ - int signal_present; - /*! \brief Whether or not a carrier drop was detected and the signal delivery is pending. */ - int carrier_drop_pending; - /*! \brief A count of the current consecutive samples below the carrier off threshold. */ - int low_samples; - /*! \brief A highest magnitude sample seen. */ - int16_t high_sample; - - /*! \brief The position of the current symbol in the constellation, used for - differential decoding. */ - int constellation_state; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The carrier update rate saved for reuse when using short training. */ - int32_t carrier_phase_rate_save; - - /*! \brief A power meter, to measure the HPF'ed signal power in the channel. */ - power_meter_t power; - /*! \brief The power meter level at which carrier on is declared. */ - int32_t carrier_on_power; - /*! \brief The power meter level at which carrier off is declared. */ - int32_t carrier_off_power; - - /*! \brief Current read offset into the equalizer buffer. */ - int eq_step; - /*! \brief Current write offset into the equalizer buffer. */ - int eq_put_step; - /*! \brief Symbol counter to the next equalizer update. */ - int eq_skip; - - /*! \brief The current half of the baud. */ - int baud_half; - - /*! \brief Integration variable for damping the Gardner algorithm tests. */ - int gardner_integrate; - /*! \brief Current step size of Gardner algorithm integration. */ - int gardner_step; - /*! \brief The total symbol timing correction since the carrier came up. - This is only for performance analysis purposes. */ - int total_baud_timing_correction; - - /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */ - int32_t last_angles[2]; - /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */ - int32_t diff_angles[16]; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v27ter_tx.h b/libs/spandsp/src/spandsp/private/v27ter_tx.h deleted file mode 100644 index add5b36979..0000000000 --- a/libs/spandsp/src/spandsp/private/v27ter_tx.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v27ter_tx.h - ITU V.27ter modem transmit part - * - * 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_V27TER_TX_H_) -#define _SPANDSP_PRIVATE_V27TER_TX_H_ - -/*! The number of taps in the pulse shaping/bandpass filter */ -#define V27TER_TX_FILTER_STEPS 9 - -/*! - V.27ter modem transmit side descriptor. This defines the working state for a - single instance of a V.27ter modem transmitter. -*/ -struct v27ter_tx_state_s -{ - /*! \brief The bit rate of the modem. Valid values are 2400 and 4800. */ - int bit_rate; - /*! \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 function. */ - void *get_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The gain factor needed to achieve the specified output power at 2400bps. */ - int16_t gain_2400; - /*! \brief The gain factor needed to achieve the specified output power at 4800bps. */ - int16_t gain_4800; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter_re[V27TER_TX_FILTER_STEPS]; - int16_t rrc_filter_im[V27TER_TX_FILTER_STEPS]; -#else - /*! \brief The gain factor needed to achieve the specified output power at 2400bps. */ - float gain_2400; - /*! \brief The gain factor needed to achieve the specified output power at 4800bps. */ - float gain_4800; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter_re[V27TER_TX_FILTER_STEPS]; - float rrc_filter_im[V27TER_TX_FILTER_STEPS]; -#endif - - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The register for the training and data scrambler. */ - uint32_t scramble_reg; - /*! \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. */ - bool in_training; - /*! \brief A counter used to track progress through sending the training sequence. */ - int training_step; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The current fractional phase of the baud timing. */ - int baud_phase; - /*! \brief The code number for the current position in the constellation. */ - int constellation_state; - /*! \brief The get_bit function in use at any instant. */ - get_bit_func_t current_get_bit; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v29rx.h b/libs/spandsp/src/spandsp/private/v29rx.h deleted file mode 100644 index 8b38b467bf..0000000000 --- a/libs/spandsp/src/spandsp/private/v29rx.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v29rx.h - ITU V.29 modem receive part - * - * 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_V29RX_H_) -#define _SPANDSP_PRIVATE_V29RX_H_ - -/* Target length for the equalizer is about 63 taps, to deal with the worst stuff - in V.56bis. */ -/*! The length of the equalizer buffer */ -#define V29_EQUALIZER_LEN 33 -/*! Samples before the target position in the equalizer buffer */ -#define V29_EQUALIZER_PRE_LEN 16 - -/*! The number of taps in the pulse shaping/bandpass filter */ -#define V29_RX_FILTER_STEPS 27 - -/*! - V.29 modem receive side descriptor. This defines the working state for a - single instance of a V.29 modem receiver. -*/ -struct v29_rx_state_s -{ - /*! \brief The bit rate of the modem. Valid values are 4800, 7200 and 9600. */ - int bit_rate; - /*! \brief The callback function used to put each bit received. */ - put_bit_func_t put_bit; - /*! \brief A user specified opaque pointer passed to the put_bit routine. */ - void *put_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - - /*! \brief A callback function which may be enabled to report every symbol's - constellation position. */ - qam_report_handler_t qam_report; - /*! \brief A user specified opaque pointer passed to the qam_report callback - routine. */ - void *qam_user_data; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief The scaling factor assessed by the AGC algorithm. */ - int16_t agc_scaling; - /*! \brief The previous value of agc_scaling, needed to reuse old training. */ - int16_t agc_scaling_save; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - int16_t eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexi16_t eq_coeff[V29_EQUALIZER_LEN]; - /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */ - complexi16_t eq_coeff_save[V29_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexi16_t eq_buf[V29_EQUALIZER_LEN]; - - /*! Low band edge filter for symbol sync. */ - int32_t symbol_sync_low[2]; - /*! High band edge filter for symbol sync. */ - int32_t symbol_sync_high[2]; - /*! DC filter for symbol sync. */ - int32_t symbol_sync_dc_filter[2]; - /*! Baud phase for symbol sync. */ - int32_t baud_phase; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - int32_t training_error; - - /*! \brief The proportional part of the carrier tracking filter. */ - int32_t carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - int32_t carrier_track_i; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter[V29_RX_FILTER_STEPS]; -#else - /*! \brief The scaling factor assessed by the AGC algorithm. */ - float agc_scaling; - /*! \brief The previous value of agc_scaling, needed to reuse old training. */ - float agc_scaling_save; - - /*! \brief The current delta factor for updating the equalizer coefficients. */ - float eq_delta; - /*! \brief The adaptive equalizer coefficients. */ - complexf_t eq_coeff[V29_EQUALIZER_LEN]; - /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */ - complexf_t eq_coeff_save[V29_EQUALIZER_LEN]; - /*! \brief The equalizer signal buffer. */ - complexf_t eq_buf[V29_EQUALIZER_LEN]; - - /*! Low band edge filter for symbol sync. */ - float symbol_sync_low[2]; - /*! High band edge filter for symbol sync. */ - float symbol_sync_high[2]; - /*! DC filter for symbol sync. */ - float symbol_sync_dc_filter[2]; - /*! Baud phase for symbol sync. */ - float baud_phase; - - /*! \brief A measure of how much mismatch there is between the real constellation, - and the decoded symbol positions. */ - float training_error; - - /*! \brief The proportional part of the carrier tracking filter. */ - float carrier_track_p; - /*! \brief The integral part of the carrier tracking filter. */ - float carrier_track_i; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter[V29_RX_FILTER_STEPS]; -#endif - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The register for the data scrambler. */ - uint32_t scramble_reg; - /*! \brief The register for the training scrambler. */ - 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. */ - 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. */ - int training_count; - /*! \brief The value of the last signal sample, using the a simple HPF for signal power estimation. */ - int16_t last_sample; - /*! \brief >0 if a signal above the minimum is present. It may or may not be a V.29 signal. */ - int signal_present; - /*! \brief Whether or not a carrier drop was detected and the signal delivery is pending. */ - int carrier_drop_pending; - /*! \brief A count of the current consecutive samples below the carrier off threshold. */ - int low_samples; - /*! \brief A highest magnitude sample seen. */ - int16_t high_sample; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The carrier update rate saved for reuse when using short training. */ - int32_t carrier_phase_rate_save; - - /*! \brief A power meter, to measure the HPF'ed signal power in the channel. */ - power_meter_t power; - /*! \brief The power meter level at which carrier on is declared. */ - int32_t carrier_on_power; - /*! \brief The power meter level at which carrier off is declared. */ - int32_t carrier_off_power; - - /*! \brief Current read offset into the equalizer buffer. */ - int eq_step; - /*! \brief Current write offset into the equalizer buffer. */ - int eq_put_step; - /*! \brief Symbol counter to the next equalizer update. */ - int eq_skip; - - /*! \brief The current half of the baud. */ - int baud_half; - - /*! \brief The total symbol timing correction since the carrier came up. - This is only for performance analysis purposes. */ - int total_baud_timing_correction; - - /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */ - int32_t last_angles[2]; - /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */ - int32_t diff_angles[16]; - - /*! \brief The position of the current symbol in the constellation, used for - differential decoding. */ - int constellation_state; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v29tx.h b/libs/spandsp/src/spandsp/private/v29tx.h deleted file mode 100644 index 58f86a2af7..0000000000 --- a/libs/spandsp/src/spandsp/private/v29tx.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v29tx.h - ITU V.29 modem transmit part - * - * 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_V29TX_H_) -#define _SPANDSP_PRIVATE_V29TX_H_ - -/*! The number of taps in the pulse shaping/bandpass filter */ -#define V29_TX_FILTER_STEPS 9 - -/*! - V.29 modem transmit side descriptor. This defines the working state for a - single instance of a V.29 modem transmitter. -*/ -struct v29_tx_state_s -{ - /*! \brief The bit rate of the modem. Valid values are 4800, 7200 and 9600. */ - int bit_rate; - /*! \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 function. */ - void *get_bit_user_data; - - /*! \brief The callback function used to report modem status changes. */ - modem_status_func_t status_handler; - /*! \brief A user specified opaque pointer passed to the status function. */ - void *status_user_data; - -#if defined(SPANDSP_USE_FIXED_POINT) - /*! \brief Gain required to achieve the specified output power, not allowing - for the size of the current constellation. */ - int16_t base_gain; - /*! \brief Gain required to achieve the specified output power, allowing - for the size of the current constellation. */ - int16_t gain; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - int16_t rrc_filter_re[V29_TX_FILTER_STEPS]; - int16_t rrc_filter_im[V29_TX_FILTER_STEPS]; -#else - /*! \brief Gain required to achieve the specified output power, not allowing - for the size of the current constellation. */ - float base_gain; - /*! \brief Gain required to achieve the specified output power, allowing - for the size of the current constellation. */ - float gain; - /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */ - float rrc_filter_re[V29_TX_FILTER_STEPS]; - float rrc_filter_im[V29_TX_FILTER_STEPS]; -#endif - - /*! \brief Current offset into the RRC pulse shaping filter buffer. */ - int rrc_filter_step; - - /*! \brief The register for the data scrambler. */ - 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. */ - 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 - training pattern to the bit rate. */ - int training_offset; - - /*! \brief The current phase of the carrier (i.e. the DDS parameter). */ - uint32_t carrier_phase; - /*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */ - int32_t carrier_phase_rate; - /*! \brief The current fractional phase of the baud timing. */ - int baud_phase; - /*! \brief The code number for the current position in the constellation. */ - int constellation_state; - /*! \brief The get_bit function in use at any instant. */ - get_bit_func_t current_get_bit; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v42.h b/libs/spandsp/src/spandsp/private/v42.h deleted file mode 100644 index 5d0a060a77..0000000000 --- a/libs/spandsp/src/spandsp/private/v42.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v42.h - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 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_V42_H_) -#define _SPANDSP_PRIVATE_V42_H_ - -/*! Max retries (9.2.2) */ -#define V42_DEFAULT_N_400 5 -/*! Default for max octets in an information field (9.2.3) */ -#define V42_DEFAULT_N_401 128 -/*! Maximum supported value for max octets in an information field */ -#define V42_MAX_N_401 128 -/*! Default window size (k) (9.2.4) */ -#define V42_DEFAULT_WINDOW_SIZE_K 15 -/*! Maximum supported window size (k) */ -#define V42_MAX_WINDOW_SIZE_K 15 - -/*! The number of info frames to allocate */ -#define V42_INFO_FRAMES (V42_MAX_WINDOW_SIZE_K + 1) -/*! The number of control frames to allocate */ -#define V42_CTRL_FRAMES 8 - -typedef struct -{ - /* V.42 LAP.M parameters */ - uint8_t v42_tx_window_size_k; - uint8_t v42_rx_window_size_k; - uint16_t v42_tx_n401; - uint16_t v42_rx_n401; - - /* V.42bis compressor parameters */ - uint8_t comp; - int comp_dict_size; - int comp_max_string; -} v42_config_parameters_t; - -typedef struct frame_s -{ - int len; - uint8_t buf[4 + V42_MAX_N_401]; -} v42_frame_t; - -/*! - LAP-M descriptor. This defines the working state for a single instance of LAP-M. -*/ -typedef struct -{ - get_msg_func_t iframe_get; - void *iframe_get_user_data; - - put_msg_func_t iframe_put; - void *iframe_put_user_data; - - modem_status_func_t status_handler; - void *status_user_data; - - hdlc_rx_state_t hdlc_rx; - hdlc_tx_state_t hdlc_tx; - - /*! Negotiated values for the window and maximum info sizes */ - uint8_t tx_window_size_k; - uint8_t rx_window_size_k; - uint16_t tx_n401; - uint16_t rx_n401; - - uint8_t cmd_addr; - uint8_t rsp_addr; - uint8_t vs; - uint8_t va; - uint8_t vr; - int state; - int configuring; - bool local_busy; - bool far_busy; - bool rejected; - int retry_count; - - /* The control frame buffer, and its pointers */ - int ctrl_put; - int ctrl_get; - v42_frame_t ctrl_buf[V42_CTRL_FRAMES]; - - /* The info frame buffer, and its pointers */ - int info_put; - int info_get; - int info_acked; - v42_frame_t info_buf[V42_INFO_FRAMES]; - - void (*packer_process)(v42_state_t *m, int bits); -} lapm_state_t; - -/*! V.42 support negotiation parameters */ -typedef struct -{ - /*! Stage in negotiating V.42 support */ - int rx_negotiation_step; - int rxbits; - int rxstream; - int rxoks; - int odp_seen; - int txbits; - int txstream; - int txadps; -} v42_negotiation_t; - -/*! - V.42 descriptor. This defines the working state for a single - instance of a V.42 error corrector. -*/ -struct v42_state_s -{ - /*! 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. */ - bool detect; - - /*! The bit rate, used to time events */ - int tx_bit_rate; - - v42_config_parameters_t config; - v42_negotiation_t neg; - lapm_state_t lapm; - - int bit_timer; - void (*bit_timer_func)(v42_state_t *m); - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v42bis.h b/libs/spandsp/src/spandsp/private/v42bis.h deleted file mode 100644 index 216199d79b..0000000000 --- a/libs/spandsp/src/spandsp/private/v42bis.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v42bis.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_V42BIS_H_) -#define _SPANDSP_PRIVATE_V42BIS_H_ - -/*! - V.42bis dictionary node. - Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used - as a "no such value" marker in this structure. -*/ -typedef struct -{ - /*! \brief The value of the octet represented by the current dictionary node */ - uint8_t node_octet; - /*! \brief The parent of this node */ - uint16_t parent; - /*! \brief The first child of this node */ - uint16_t child; - /*! \brief The next node at the same depth */ - uint16_t next; -} v42bis_dict_node_t; - -/*! - V.42bis compression or decompression. This defines the working state for a single instance - of V.42bis compression or decompression. -*/ -typedef struct -{ - /*! \brief Compression enabled. */ - int v42bis_parm_p0; - /*! \brief Compression mode. */ - int compression_mode; - /*! \brief Callback function to handle output data. */ - put_msg_func_t handler; - /*! \brief An opaque pointer passed in calls to the data handler. */ - void *user_data; - /*! \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 */ - bool transparent; - /*! \brief Next empty dictionary entry */ - uint16_t v42bis_parm_c1; - /*! \brief Current codeword size */ - uint16_t v42bis_parm_c2; - /*! \brief Threshold for codeword size change */ - uint16_t v42bis_parm_c3; - /*! \brief The current update point in the dictionary */ - uint16_t update_at; - /*! \brief The last entry matched in the dictionary */ - uint16_t last_matched; - /*! \brief The last entry added to the dictionary */ - uint16_t last_added; - /*! \brief Total number of codewords in the dictionary */ - int v42bis_parm_n2; - /*! \brief Maximum permitted string length */ - int v42bis_parm_n7; - /*! \brief The dictionary */ - v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; - - /*! \brief The octet string in progress */ - uint8_t string[V42BIS_MAX_STRING_SIZE]; - /*! \brief The current length of the octet string in progress */ - int string_length; - /*! \brief The amount of the octet string in progress which has already - been flushed out of the buffer */ - int flushed_length; - - /*! \brief Compression performance metric */ - uint16_t compression_performance; - - /*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */ - uint32_t bit_buffer; - /*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */ - int bit_count; - - /*! \brief The output composition buffer */ - uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH]; - /*! \brief The length of the contents of the output composition buffer */ - int output_octet_count; - - /*! \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 */ - bool escaped; -} v42bis_comp_state_t; - -/*! - V.42bis compression/decompression descriptor. This defines the working state for a - single instance of V.42bis compress/decompression. -*/ -struct v42bis_state_s -{ - /*! \brief Compression state. */ - v42bis_comp_state_t compress; - /*! \brief Decompression state. */ - v42bis_comp_state_t decompress; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/v8.h b/libs/spandsp/src/spandsp/private/v8.h deleted file mode 100644 index 3c07b0e3bc..0000000000 --- a/libs/spandsp/src/spandsp/private/v8.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * private/v8.h - V.8 modem negotiation processing. - * - * 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. - */ - -#if !defined(_SPANDSP_PRIVATE_V8_H_) -#define _SPANDSP_PRIVATE_V8_H_ - -struct v8_state_s -{ - /*! \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; - /*! \brief An opaque pointer passed to result_handler */ - void *result_handler_user_data; - - /*! \brief The current state of the V.8 protocol */ - int state; - bool fsk_tx_on; - int modem_connect_tone_tx_on; - int negotiation_timer; - int ci_timer; - int ci_count; - fsk_tx_state_t v21tx; - fsk_rx_state_t v21rx; - queue_state_t *tx_queue; - modem_connect_tones_tx_state_t ansam_tx; - modem_connect_tones_rx_state_t ansam_rx; - - v8_parms_t parms; - v8_parms_t result; - - /*! \brief The number of modulation bytes to use when sending. */ - int modulation_bytes; - - /* V.8 data parsing */ - uint32_t bit_stream; - int bit_cnt; - /* Indicates the type of message coming up */ - int preamble_type; - uint8_t rx_data[64]; - int rx_data_ptr; - - /*! \brief a reference copy of the last CM or JM message, used when - testing for matches. */ - uint8_t cm_jm_data[64]; - int cm_jm_len; - bool got_cm_jm; - bool got_cj; - int zero_byte_count; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/queue.h b/libs/spandsp/src/spandsp/queue.h deleted file mode 100644 index 7e56a59fc7..0000000000 --- a/libs/spandsp/src/spandsp/queue.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * queue.h - simple in process message queuing - * - * 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 */ - -/*! \page queue_page Queuing -\section queue_page_sec_1 What does it do? -This module provides lock free queuing for either octet streams or messages. -Specifically, lock free means one thread can write and another can read without -locking the queue. It does NOT means a free-for-all is possible, with many -threads writing or many threads reading. Those things would require locking, -to avoid conflicts between the multiple threads acting on one end of the queue. - -\section queue_page_sec_2 How does it work? -???. -*/ - -#if !defined(_SPANDSP_QUEUE_H_) -#define _SPANDSP_QUEUE_H_ - -/*! Flag bit to indicate queue reads are atomic operations. This must be set - if the queue is to be used with the message oriented functions. */ -#define QUEUE_READ_ATOMIC 0x0001 -/*! Flag bit to indicate queue writes are atomic operations. This must be set - if the queue is to be used with the message oriented functions. */ -#define QUEUE_WRITE_ATOMIC 0x0002 - -/*! - Queue descriptor. This defines the working state for a single instance of - a byte stream or message oriented queue. -*/ -typedef struct queue_state_s queue_state_t; - -#define QUEUE_STATE_T_SIZE(len) (sizeof(queue_state_t) + len + 1) - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! 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(bool) queue_empty(queue_state_t *s); - -/*! Check the available free space in a queue's buffer. - \brief Check available free space. - \param s The queue context. - \return The number of bytes of free space. */ -SPAN_DECLARE(int) queue_free_space(queue_state_t *s); - -/*! Check the contents of a queue. - \brief Check the contents of a queue. - \param s The queue context. - \return The number of bytes in the queue. */ -SPAN_DECLARE(int) queue_contents(queue_state_t *s); - -/*! Flush the contents of a queue. - \brief Flush the contents of a queue. - \param s The queue context. */ -SPAN_DECLARE(void) queue_flush(queue_state_t *s); - -/*! Copy bytes from a queue. This is similar to queue_read, but - the data remains in the queue. - \brief Copy bytes from a queue. - \param s The queue context. - \param buf The buffer into which the bytes will be read. - \param len The length of the buffer. - \return the number of bytes returned. */ -SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len); - -/*! Read bytes from a queue. - \brief Read bytes from a queue. - \param s The queue context. - \param buf The buffer into which the bytes will be read. - \param len The length of the buffer. - \return the number of bytes returned. */ -SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len); - -/*! Read a byte from a queue. - \brief Read a byte from a queue. - \param s The queue context. - \return the byte, or -1 if the queue is empty. */ -SPAN_DECLARE(int) queue_read_byte(queue_state_t *s); - -/*! Write bytes to a queue. - \brief Write bytes to a queue. - \param s The queue context. - \param buf The buffer containing the bytes to be written. - \param len The length of the buffer. - \return the number of bytes actually written. */ -SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len); - -/*! Write a byte to a queue. - \brief Write a byte to a queue. - \param s The queue context. - \param byte The byte to be written. - \return the number of bytes actually written. */ -SPAN_DECLARE(int) queue_write_byte(queue_state_t *s, uint8_t byte); - -/*! Test the length of the message at the head of a queue. - \brief Test message length. - \param s The queue context. - \return The length of the next message, in byte. If there are - no messages in the queue, -1 is returned. */ -SPAN_DECLARE(int) queue_state_test_msg(queue_state_t *s); - -/*! Read a message from a queue. If the message is longer than the buffer - provided, only the first len bytes of the message will be returned. The - remainder of the message will be discarded. - \brief Read a message from a queue. - \param s The queue context. - \param buf The buffer into which the message will be read. - \param len The length of the buffer. - \return The number of bytes returned. If there are - no messages in the queue, -1 is returned. */ -SPAN_DECLARE(int) queue_read_msg(queue_state_t *s, uint8_t *buf, int len); - -/*! Write a message to a queue. - \brief Write a message to a queue. - \param s The queue context. - \param buf The buffer from which the message will be written. - \param len The length of the message. - \return The number of bytes actually written. */ -SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len); - -/*! Initialise a queue. - \brief Initialise a queue. - \param s The queue context. If is imperative that the context this - points to is immediately followed by a buffer of the required - size + 1 octet. - \param len The length of the queue's buffer. - \param flags Flags controlling the operation of the queue. - Valid flags are QUEUE_READ_ATOMIC and QUEUE_WRITE_ATOMIC. - \return A pointer to the context if OK, else NULL. */ -SPAN_DECLARE(queue_state_t *) queue_init(queue_state_t *s, int len, int flags); - -/*! Release a queue. - \brief Release a queue. - \param s The queue context. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) queue_release(queue_state_t *s); - -/*! Free a queue. - \brief Delete a queue. - \param s The queue context. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) queue_free(queue_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/saturated.h b/libs/spandsp/src/spandsp/saturated.h deleted file mode 100644 index 4cc61a81d5..0000000000 --- a/libs/spandsp/src/spandsp/saturated.h +++ /dev/null @@ -1,421 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * saturated.h - General saturated arithmetic routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 2008 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_SATURATED_H_) -#define _SPANDSP_SATURATED_H_ - -/*! \page saturated_page Saturated arithmetic - -\section saturated_page_sec_1 What does it do? - - -\section saturated_page_sec_2 How does it work? - -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ int16_t saturate16(int32_t amp) -{ -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int16_t z; - - __asm__ __volatile__( - " ssat %[z],#16,%[amp];\n" - : [z] "=r" (z) - : [amp] "r" (amp) - ); - return z; -#else - int16_t z; - - /* Hopefully this is optimised for the common case - not clipping */ - z = (int16_t) amp; - if (amp == z) - return z; - if (amp > INT16_MAX) - return INT16_MAX; - return INT16_MIN; -#endif -} -/*- End of function --------------------------------------------------------*/ - -/*! Saturate to 15 bits, rather than the usual 16 bits. This is often a useful function. */ -static __inline__ int16_t saturate15(int32_t amp) -{ -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int16_t z; - - __asm__ __volatile__( - " ssat %[z],#15,%[amp];\n" - : [z] "=r" (z) - : [amp] "r" (amp) - ); - return z; -#else - if (amp > 16383) - return 16383; - if (amp < -16384) - return -16384; - return (int16_t) amp; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint16_t saturateu16(int32_t amp) -{ -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - uint16_t z; - - __asm__ __volatile__( - " usat %[z],#16,%[amp];\n" - : [z] "=r" (z) - : [amp] "r" (amp) - ); - return z; -#else - uint16_t z; - - /* Hopefully this is optimised for the common case - not clipping */ - z = (uint16_t) amp; - if (amp == z) - return z; - if (amp > UINT16_MAX) - return UINT16_MAX; - return 0; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint8_t saturateu8(int32_t amp) -{ -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - uint8_t z; - - __asm__ __volatile__( - " usat %[z],#8,%[amp];\n" - : [z] "=r" (z) - : [amp] "r" (amp) - ); - return z; -#else - uint8_t z; - - /* Hopefully this is optimised for the common case - not clipping */ - z = (uint8_t) amp; - if (amp == z) - return z; - if (amp > UINT8_MAX) - return UINT8_MAX; - return 0; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t fsaturatef(float famp) -{ - if (famp > (float) INT16_MAX) - return INT16_MAX; - if (famp < (float) INT16_MIN) - return INT16_MIN; - return (int16_t) lrintf(famp); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t fsaturate(double damp) -{ - if (damp > (double) INT16_MAX) - return INT16_MAX; - if (damp < (double) INT16_MIN) - return INT16_MIN; - return (int16_t) lrint(damp); -} -/*- End of function --------------------------------------------------------*/ - -/* Saturate to a 16 bit integer, using the fastest float to int conversion */ -static __inline__ int16_t ffastsaturatef(float famp) -{ - if (famp > (float) INT16_MAX) - return INT16_MAX; - if (famp < (float) INT16_MIN) - return INT16_MIN; - return (int16_t) lfastrintf(famp); -} -/*- End of function --------------------------------------------------------*/ - -/* Saturate to a 16 bit integer, using the fastest double to int conversion */ -static __inline__ int16_t ffastsaturate(double damp) -{ - if (damp > (double) INT16_MAX) - return INT16_MAX; - if (damp < (double) INT16_MIN) - return INT16_MIN; - return (int16_t) lfastrint(damp); -} -/*- End of function --------------------------------------------------------*/ - -/* Saturate to a 16 bit integer, using the closest float to int conversion */ -static __inline__ float ffsaturatef(float famp) -{ - if (famp > (float) INT16_MAX) - return (float) INT16_MAX; - if (famp < (float) INT16_MIN) - return (float) INT16_MIN; - return famp; -} -/*- End of function --------------------------------------------------------*/ - -/* Saturate to a 16 bit integer, using the closest double to int conversion */ -static __inline__ double ffsaturate(double famp) -{ - if (famp > (double) INT16_MAX) - return (double) INT16_MAX; - if (famp < (double) INT16_MIN) - return (double) INT16_MIN; - return famp; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t sat_add16(int16_t x, int16_t y) -{ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__(" addw %[y],%[x];\n" - " jno 0f;\n" - " movw $0x7FFF,%[x];\n" - " adcw $0,%[x];\n" - "0:" - : [x] "+r" (x) - : [y] "ir" (y) - : "cc"); - return x; -#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int16_t z; - - __asm__ __volatile__( - " qadd16 %[z],%[x],%[y];\n" - : [z] "=r" (z) - : [x] "r" (x), [y] "r" (y) - ); - return z; -//#elif defined(__GNUC__) && defined(__ARM_ARCH_5T__) -#else - return saturate16((int32_t) x + y); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t sat_add32(int32_t x, int32_t y) -{ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__(" addl %[y],%[x];\n" - " jno 0f;\n" - " movl $0x7FFFFFFF,%[x];\n" - " adcl $0,%[x];\n" - "0:" - : [x] "+r" (x) - : [y] "ir" (y) - : "cc"); - return x; -#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int32_t z; - - __asm__ __volatile__(" qadd %[z],%[x],%[y];\n" - : [z] "=r" (z) - : [x] "r" (x), [y] "r" (y)); - return z; -//#elif defined(__GNUC__) && defined(__ARM_ARCH_5T__) -#else - int32_t z; - - z = x + y; - if ((x ^ y) >= 0) - { - if ((z ^ x) < 0) - z = (x < 0) ? INT32_MIN : INT32_MAX; - } - return z; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t sat_sub16(int16_t x, int16_t y) -{ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__(" subw %[y],%[x];\n" - " jno 0f;\n" - " movw $0x8000,%[x];\n" - " sbbw $0,%[x];\n" - "0:" - : [x] "+r" (x) - : [y] "ir" (y) - : "cc"); - return x; -#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int16_t z; - - __asm__ __volatile__(" qsub16 %[z],%[x],%[y];\n" - : [z] "=r" (z) - : [x] "r" (x), [y] "r" (y)); - return z; -//#elif defined(__GNUC__) && defined(__ARM_ARCH_5T__) -#else - return saturate16((int32_t) x - y); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t sat_sub32(int32_t x, int32_t y) -{ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__(" subl %[y],%[x];\n" - " jno 0f;\n" - " movl $0x80000000,%[x];\n" - " sbbl $0,%[x];\n" - "0:" - : [x] "+r" (x) - : [y] "ir" (y) - : "cc"); - return x; -#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int32_t z; - - __asm__ __volatile__(" qsub %[z],%[x],%[y];\n" - : [z] "=r" (z) - : [x] "r" (x), [y] "r" (y)); - return z; -//#elif defined(__GNUC__) && defined(__ARM_ARCH_5T__) -#else - int32_t z; - - z = x - y; - if ((x ^ y) < 0) - { - if ((z ^ x) < 0) - z = (x < 0L) ? INT32_MIN : INT32_MAX; - } - return z; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t sat_mul16(int16_t x, int16_t y) -{ - int32_t z; - -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - __asm__ __volatile__(" smulbb %[z],%[x],%[y];\n" - " qadd %[z],%[z],%[z];\n" - : [z] "=r" (z) - : [x] "r" (x), [y] "r" (y)); - /* The qadd added one to the shift of 15 */ - return (int16_t) (z >> 16); -#else - z = (int32_t) x*y; - if (z == 0x40000000) - return INT16_MAX; - /*endif*/ - return (int16_t) (z >> 15); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t sat_mul32_16(int16_t x, int16_t y) -{ - int32_t z; - -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - __asm__ __volatile__(" smulbb %[z],%[x],%[y];\n" - " qadd %[z],%[z],%[z];\n" - : [z] "=r" (z) - : [x] "r" (x), [y] "r" (y)); - return z; -#else - z = (int32_t) x*y; - if (z == 0x40000000) - return INT32_MAX; - return z << 1; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t sat_mac32_16(int32_t z, int16_t x, int16_t y) -{ -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int32_t product; - - __asm__ __volatile__(" smulbb %[p],%[x],%[y];\n" - " qdadd %[z],%[z],%[p];\n" - : [z] "+r" (z) - : [x] "r" (x), [y] "r" (y), [p] "r" (product)); - return z; -#else - return sat_add32(z, sat_mul32_16(x, y)); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t sat_msu32_16(int32_t z, int16_t x, int16_t y) -{ -#if defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__)) - int32_t product; - - __asm__ __volatile__(" smulbb %[p],%[x],%[y];\n" - " qdsub %[z],%[z],%[p];\n" - : [z] "+r" (z) - : [x] "r" (x), [y] "r" (y), [p] "r" (product)); - return z; -#else - return sat_sub32(z, sat_mul32_16(x, y)); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int16_t sat_abs16(int16_t x) -{ - if (x == INT16_MIN) - return INT16_MAX; - return (int16_t) abs(x); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int32_t sat_abs32(int32_t x) -{ - if (x == INT32_MIN) - return INT32_MAX; - return abs(x); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/schedule.h b/libs/spandsp/src/spandsp/schedule.h deleted file mode 100644 index 95509e016a..0000000000 --- a/libs/spandsp/src/spandsp/schedule.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * schedule.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 */ - -/*! \page schedule_page Scheduling -\section schedule_page_sec_1 What does it do? -???. - -\section schedule_page_sec_2 How does it work? -???. -*/ - -#if !defined(_SPANDSP_SCHEDULE_H_) -#define _SPANDSP_SCHEDULE_H_ - -/*! A scheduled event entry. */ -typedef struct span_sched_s span_sched_t; - -/*! A scheduled event queue. */ -typedef struct span_sched_state_s span_sched_state_t; - -typedef void (*span_sched_callback_func_t)(span_sched_state_t *s, void *user_data); - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(uint64_t) span_schedule_next(span_sched_state_t *s); -SPAN_DECLARE(uint64_t) span_schedule_time(span_sched_state_t *s); - -SPAN_DECLARE(int) span_schedule_event(span_sched_state_t *s, int us, span_sched_callback_func_t function, void *user_data); -SPAN_DECLARE(void) span_schedule_update(span_sched_state_t *s, int us); -SPAN_DECLARE(void) span_schedule_del(span_sched_state_t *s, int id); - -SPAN_DECLARE(span_sched_state_t *) span_schedule_init(span_sched_state_t *s); -SPAN_DECLARE(int) span_schedule_release(span_sched_state_t *s); -SPAN_DECLARE(int) span_schedule_free(span_sched_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/sig_tone.h b/libs/spandsp/src/spandsp/sig_tone.h deleted file mode 100644 index 8213e1ca73..0000000000 --- a/libs/spandsp/src/spandsp/sig_tone.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * sig_tone.h - Signalling tone processing for the 2280Hz, 2400Hz, 2600Hz - * and similar signalling tones used in older protocols. - * - * 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 */ - -/*! \page sig_tone_page The 2280/2400/2600Hz signalling tone processor -\section sig_tone_sec_1 What does it do? -The signalling tone processor handles the 2280Hz, 2400Hz and 2600Hz tones, used -in many analogue signalling procotols, and digital ones derived from them. - -\section sig_tone_sec_2 How does it work? -Most single and two voice frequency signalling systems share many features, as these -features have developed in similar ways over time, to address the limitations of -early tone signalling systems. - -The usual practice is to start the generation of tone at a high energy level, so a -strong signal is available at the receiver, for crisp tone detection. If the tone -remains on for a significant period, the energy level is reduced, to minimise crosstalk. -During the signalling transitions, only the tone is sent through the channel, and the media -signal is suppressed. This means the signalling receiver has a very clean signal to work with, -allowing for crisp detection of the signalling tone. However, when the signalling tone is on -for extended periods, there may be supervisory information in the media signal, such as voice -announcements. To allow these to pass through the system, the signalling tone is mixed with -the media signal. It is the job of the signalling receiver to separate the signalling tone -and the media. The necessary filtering may degrade the quality of the voice signal, but at -least supervisory information may be heard. -*/ - -#if !defined(_SPANDSP_SIG_TONE_H_) -#define _SPANDSP_SIG_TONE_H_ - -/* The optional tone sets */ -enum -{ - /*! European 2280Hz signalling tone. Tone 1 is 2280Hz. Tone 2 is not used. */ - SIG_TONE_2280HZ = 1, - /*! US 2600Hz signalling tone. Tone 1 is 2600Hz. Tone 2 is not used. */ - SIG_TONE_2600HZ, - /*! US 2400Hz + 2600Hz signalling tones. Tone 1 is 2600Hz. Tone 2 is 2400Hz. */ - SIG_TONE_2400HZ_2600HZ -}; - -/* Mode control and report bits for transmit and receive */ -enum -{ - /*! Signalling tone 1 is present */ - SIG_TONE_1_PRESENT = 0x001, - /*! Signalling tone 1 has changed state (ignored when setting tx mode) */ - SIG_TONE_1_CHANGE = 0x002, - /*! Signalling tone 2 is present */ - SIG_TONE_2_PRESENT = 0x004, - /*! Signalling tone 2 has changed state (ignored when setting tx mode) */ - SIG_TONE_2_CHANGE = 0x008, - /*! The media signal is passing through. Tones might be added to it. */ - SIG_TONE_TX_PASSTHROUGH = 0x010, - /*! The media signal is passing through. Tones might be extracted from it, if detected. */ - SIG_TONE_RX_PASSTHROUGH = 0x040, - /*! Force filtering of the signalling tone, whether signalling is being detected or not. - This is mostly useful for test purposes. */ - SIG_TONE_RX_FILTER_TONE = 0x080, - /*! Request an update of the transmit status, upon timeout of the previous status. */ - SIG_TONE_TX_UPDATE_REQUEST = 0x100, - /*! Request an update of the receiver status, upon timeout of the previous status. */ - SIG_TONE_RX_UPDATE_REQUEST = 0x200 -}; - -typedef struct sig_tone_tx_state_s sig_tone_tx_state_t; - -typedef struct sig_tone_rx_state_s sig_tone_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Process a block of received audio samples. - \brief Process a block of received audio samples. - \param s The signalling tone context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len); - -/*! Set the receive mode. - \brief Set the receive mode. - \param s The signalling tone context. - \param mode The new mode for the receiver. - \param duration The duration for this mode, before an update is requested. - A duration of zero means forever. */ -SPAN_DECLARE(void) sig_tone_rx_set_mode(sig_tone_rx_state_t *s, int mode, int duration); - -/*! Initialise a signalling tone receiver context. - \brief Initialise a signalling tone context. - \param s The signalling tone context. - \param tone_type The type of signalling tone. - \param sig_update Callback function to handle signalling updates. - \param user_data An opaque pointer. - \return A pointer to the signalling tone context, or NULL if there was a problem. */ -SPAN_DECLARE(sig_tone_rx_state_t *) sig_tone_rx_init(sig_tone_rx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data); - -/*! Release a signalling tone receiver context. - \brief Release a signalling tone receiver context. - \param s The signalling tone context. - \return 0 for OK */ -SPAN_DECLARE(int) sig_tone_rx_release(sig_tone_rx_state_t *s); - -/*! Free a signalling tone receiver context. - \brief Free a signalling tone receiver context. - \param s The signalling tone context. - \return 0 for OK */ -SPAN_DECLARE(int) sig_tone_rx_free(sig_tone_rx_state_t *s); - -/*! Generate a block of signalling tone audio samples. - \brief Generate a block of signalling tone audio samples. - \param s The signalling tone context. - \param amp The audio sample buffer. - \param len The number of samples to be generated. - \return The number of samples actually generated. */ -SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len); - -/*! Set the tone mode. - \brief Set the tone mode. - \param s The signalling tone context. - \param mode The new mode for the transmitted tones. - \param duration The duration for this mode, before an update is requested. - A duration of zero means forever. */ -SPAN_DECLARE(void) sig_tone_tx_set_mode(sig_tone_tx_state_t *s, int mode, int duration); - -/*! Initialise a signalling tone transmitter context. - \brief Initialise a signalling tone context. - \param s The signalling tone context. - \param tone_type The type of signalling tone. - \param sig_update Callback function to handle signalling updates. - \param user_data An opaque pointer. - \return A pointer to the signalling tone context, or NULL if there was a problem. */ -SPAN_DECLARE(sig_tone_tx_state_t *) sig_tone_tx_init(sig_tone_tx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data); - -/*! Release a signalling tone transmitter context. - \brief Release a signalling tone transmitter context. - \param s The signalling tone context. - \return 0 for OK */ -SPAN_DECLARE(int) sig_tone_tx_release(sig_tone_tx_state_t *s); - -/*! Free a signalling tone transmitter context. - \brief Free a signalling tone transmitter context. - \param s The signalling tone context. - \return 0 for OK */ -SPAN_DECLARE(int) sig_tone_tx_free(sig_tone_tx_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/silence_gen.h b/libs/spandsp/src/spandsp/silence_gen.h deleted file mode 100644 index 94357b7247..0000000000 --- a/libs/spandsp/src/spandsp/silence_gen.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * silence_gen.c - A silence generator, for inserting timed silences. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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_SILENCE_GEN_H_) -#define _SPANDSP_SILENCE_GEN_H_ - -typedef struct silence_gen_state_s silence_gen_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Generate a block of silent audio samples. - \brief Generate a block of silent audio samples. - \param s The silence generator context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. This will be zero when - there is nothing to send. -*/ -SPAN_DECLARE(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len); - -/*! Set a silence generator context to output continuous silence. - \brief Set a silence generator context to output continuous silence. - \param s The silence generator context. -*/ -SPAN_DECLARE(void) silence_gen_always(silence_gen_state_t *s); - -/*! Set a silence generator context to output a specified period of silence. - \brief Set a silence generator context to output a specified period of silence. - \param s The silence generator context. - \param silent_samples The number of samples to be generated. -*/ -SPAN_DECLARE(void) silence_gen_set(silence_gen_state_t *s, int silent_samples); - -/*! Alter the period of a silence generator context by a specified amount. - \brief Alter the period of a silence generator context by a specified amount. - \param s The silence generator context. - \param silent_samples The number of samples to change the setting by. A positive number - increases the duration. A negative number reduces it. The duration - is prevented from going negative. -*/ -SPAN_DECLARE(void) silence_gen_alter(silence_gen_state_t *s, int silent_samples); - -/*! Find how long a silence generator context has to run. - \brief Find how long a silence generator context has to run. - \param s The silence generator context. - \return The number of samples remaining. -*/ -SPAN_DECLARE(int) silence_gen_remainder(silence_gen_state_t *s); - -/*! Find the total silence generated to date by a silence generator context. - \brief Find the total silence generated to date. - \param s The silence generator context. - \return The number of samples generated. -*/ -SPAN_DECLARE(int) silence_gen_generated(silence_gen_state_t *s); - -/*! Change the status reporting function associated with a silence generator context. - \brief Change the status reporting function associated with a silence generator context. - \param s The silence generator context. - \param handler The callback routine used to report status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Initialise a timed silence generator context. - \brief Initialise a timed silence generator context. - \param s The silence generator context. - \param silent_samples The initial number of samples to set the silence to. - \return A pointer to the silence generator context. -*/ -SPAN_DECLARE(silence_gen_state_t *) silence_gen_init(silence_gen_state_t *s, int silent_samples); - -SPAN_DECLARE(int) silence_gen_release(silence_gen_state_t *s); - -SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s); - -/* The following dummy routines, to absorb data, don't really have a proper home, - so they have been put here. */ - -/*! A dummy routine to use as a receive callback, when we aren't really - trying to process what is received. It just absorbs and ignores the - data. - \brief Dummy receive callback. - \param user_data The context. - \param amp The signal.buffer - \param len The length of the signal buffer - \return 0. -*/ -SPAN_DECLARE(int) span_dummy_rx(void *user_data, const int16_t amp[], int len); - -/*! A dummy routine to use as a signal modifier callback, when we aren't - really trying to process the signal. It just returns without affecting - anything. - \brief Dummy signal modifier callback. - \param user_data The context. - \param amp The signal.buffer - \param len The length of the signal buffer - \return 0. -*/ -SPAN_DECLARE(int) span_dummy_mod(void *user_data, int16_t amp[], int len); - -/*! A dummy routine to use as a receive fillin callback, when we aren't really - trying to process what is received. It just absorbs and ignores the - request. - \brief Dummy receive fillin callback. - \param user_data The context. - \param len The length of the signal buffer - \return 0. -*/ -SPAN_DECLARE(int) span_dummy_rx_fillin(void *user_data, int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/stdbool.h b/libs/spandsp/src/spandsp/stdbool.h deleted file mode 100644 index 2881e83068..0000000000 --- a/libs/spandsp/src/spandsp/stdbool.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 - -#ifdef _MSC_VER -#pragma warning (disable: 4005) -#endif - -#if !defined(__cplusplus) - -#ifndef _MSC_VER -typedef int _Bool; -#endif -typedef int bool; -#define false 0 -#define true (!false) - -#else - -typedef bool _Bool; -#define false false -#define true true - -#endif - -#ifdef _MSC_VER -#pragma warning (default: 4005) -#endif - -/* Signal that all the definitions are present. */ -#define __bool_true_false_are_defined 1 - -#endif diff --git a/libs/spandsp/src/spandsp/super_tone_rx.h b/libs/spandsp/src/spandsp/super_tone_rx.h deleted file mode 100644 index 4ea640c685..0000000000 --- a/libs/spandsp/src/spandsp/super_tone_rx.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * super_tone_rx.h - Flexible telephony supervisory tone detection. - * - * 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_SUPER_TONE_RX_H_) -#define _SPANDSP_SUPER_TONE_RX_H_ - -/*! \page super_tone_rx_page Supervisory tone detection - -\section super_tone_rx_page_sec_1 What does it do? - -The supervisory tone detector may be configured to detect most of the world's -telephone supervisory tones - things like ringback, busy, number unobtainable, -and so on. - -\section super_tone_rx_page_sec_2 How does it work? - -The supervisory tone detector is passed a series of data structures describing -the tone patterns - the frequencies and cadencing - of the tones to be searched -for. It constructs one or more Goertzel filters to monitor the required tones. -If tones are close in frequency a single Goertzel set to the centre of the -frequency range will be used. This optimises the efficiency of the detector. The -Goertzel filters are applied without applying any special window functional -(i.e. they use a rectangular window), so they have a sinc like response. -However, for most tone patterns their rejection qualities are adequate. - -The detector aims to meet the need of the standard call progress tones, to -ITU-T E.180/Q.35 (busy, dial, ringback, reorder). Also, the extended tones, -to ITU-T E.180, Supplement 2 and EIA/TIA-464-A (recall dial tone, special -ringback tone, intercept tone, call waiting tone, busy verification tone, -executive override tone, confirmation tone). -*/ - -/*! Tone detection indication callback routine */ -typedef void (*tone_report_func_t)(void *user_data, int code, int level, int delay); - -typedef void (*tone_segment_func_t)(void *data, int f1, int f2, int duration); - -typedef struct super_tone_rx_segment_s super_tone_rx_segment_t; - -typedef struct super_tone_rx_descriptor_s super_tone_rx_descriptor_t; - -typedef struct super_tone_rx_state_s super_tone_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Create a new supervisory tone detector descriptor. - \param desc The supervisory tone set desciptor. If NULL, the routine will allocate space for a - descriptor. - \return The supervisory tone set descriptor. -*/ -SPAN_DECLARE(super_tone_rx_descriptor_t *) super_tone_rx_make_descriptor(super_tone_rx_descriptor_t *desc); - -/*! Free a supervisory tone detector descriptor. - \param desc The supervisory tone set desciptor. - \return 0 for OK, -1 for fail. -*/ -SPAN_DECLARE(int) super_tone_rx_free_descriptor(super_tone_rx_descriptor_t *desc); - -/*! Add a new tone pattern to a supervisory tone detector set. - \param desc The supervisory tone set descriptor. - \return The new tone ID. */ -SPAN_DECLARE(int) super_tone_rx_add_tone(super_tone_rx_descriptor_t *desc); - -/*! Add a new tone pattern element to a tone pattern in a supervisory tone detector. - \param desc The supervisory tone set desciptor. - \param tone The tone ID within the descriptor. - \param f1 Frequency 1 (-1 for a silent period). - \param f2 Frequency 2 (-1 for a silent period, or only one frequency). - \param min The minimum duration, in ms. - \param max The maximum duration, in ms. - \return The new number of elements in the tone description. -*/ -SPAN_DECLARE(int) super_tone_rx_add_element(super_tone_rx_descriptor_t *desc, - int tone, - int f1, - int f2, - int min, - int max); - -/*! Initialise a supervisory tone detector. - \param s The supervisory tone detector context. - \param desc The tone descriptor. - \param callback The callback routine called to report the valid detection or termination of - one of the monitored tones. - \param user_data An opaque pointer passed when calling the callback routine. - \return The supervisory tone detector context. -*/ -SPAN_DECLARE(super_tone_rx_state_t *) super_tone_rx_init(super_tone_rx_state_t *s, - super_tone_rx_descriptor_t *desc, - tone_report_func_t callback, - void *user_data); - -/*! Release a supervisory tone detector. - \param s The supervisory tone context. - \return 0 for OK, -1 for fail. -*/ -SPAN_DECLARE(int) super_tone_rx_release(super_tone_rx_state_t *s); - -/*! Free a supervisory tone detector. - \param s The supervisory tone context. - \return 0 for OK, -1 for fail. -*/ -SPAN_DECLARE(int) super_tone_rx_free(super_tone_rx_state_t *s); - -/*! Define a callback routine to be called to report the valid detection or termination of - one of the monitored tones. - \param s The supervisory tone context. - \param callback The callback routine called to report the valid detection or termination of - one of the monitored tones. - \param user_data An opaque pointer passed when calling the callback routine. -*/ -SPAN_DECLARE(void) super_tone_rx_tone_callback(super_tone_rx_state_t *s, - tone_report_func_t callback, - void *user_data); - -/*! Define a callback routine to be called each time a tone pattern element is complete. This is - mostly used when analysing a tone. - \param s The supervisory tone context. - \param callback The callback routine. -*/ -SPAN_DECLARE(void) super_tone_rx_segment_callback(super_tone_rx_state_t *s, - tone_segment_func_t callback); - -/*! Apply supervisory tone detection processing to a block of audio samples. - \brief Apply supervisory tone detection processing to a block of audio samples. - \param super The supervisory tone context. - \param amp The audio sample buffer. - \param samples The number of samples in the buffer. - \return The number of samples processed. -*/ -SPAN_DECLARE(int) super_tone_rx(super_tone_rx_state_t *super, const int16_t amp[], int samples); - -/*! Allow for a missing block of samples to a supervisory tone detector. - \brief Allow for a missing block of samples to a supervisory tone detector. - \param super The supervisory tone context. - \param samples The number of samples to allow for. - \return The number of samples processed. -*/ -SPAN_DECLARE(int) super_tone_rx_fillin(super_tone_rx_state_t *s, int samples); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/super_tone_tx.h b/libs/spandsp/src/spandsp/super_tone_tx.h deleted file mode 100644 index 879319ae47..0000000000 --- a/libs/spandsp/src/spandsp/super_tone_tx.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * super_tone_tx.h - Flexible telephony supervisory tone generation. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_SUPER_TONE_TX_H_) -#define _SPANDSP_SUPER_TONE_TX_H_ - -/*! \page super_tone_tx_page Supervisory tone generation - -\section super_tone_tx_page_sec_1 What does it do? - -The supervisory tone generator may be configured to generate most of the world's -telephone supervisory tones - things like ringback, busy, number unobtainable, -and so on. It uses tree structure tone descriptions, which can deal with quite -complex cadence patterns. - -\section super_tone_tx_page_sec_2 How does it work? - -*/ - -#define SUPER_TONE_TX_MAX_LEVELS 4 -#define SUPER_TONE_TX_MAX_TONES 4 - -typedef struct super_tone_tx_step_s super_tone_tx_step_t; - -typedef struct super_tone_tx_state_s super_tone_tx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(super_tone_tx_step_t *) super_tone_tx_make_step(super_tone_tx_step_t *s, - float f1, - float l1, - float f2, - float l2, - int length, - int cycles); - -SPAN_DECLARE(int) super_tone_tx_free_tone(super_tone_tx_step_t *s); - -/*! Initialise a supervisory tone generator. - \brief Initialise a supervisory tone generator. - \param s The supervisory tone generator context. - \param tree The supervisory tone tree to be generated. - \return The supervisory tone generator context. */ -SPAN_DECLARE(super_tone_tx_state_t *) super_tone_tx_init(super_tone_tx_state_t *s, super_tone_tx_step_t *tree); - -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); - -/*! Generate a block of audio samples for a supervisory tone pattern. - \brief Generate a block of audio samples for a supervisory tone pattern. - \param s The supervisory tone context. - \param amp The audio sample buffer. - \param max_samples The maximum number of samples to be generated. - \return The number of samples generated. */ -SPAN_DECLARE(int) super_tone_tx(super_tone_tx_state_t *s, int16_t amp[], int max_samples); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/swept_tone.h b/libs/spandsp/src/spandsp/swept_tone.h deleted file mode 100644 index 917b507fff..0000000000 --- a/libs/spandsp/src/spandsp/swept_tone.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * swept_tone.h - Swept tone generation - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_SWEPT_TONE_H_) -#define _SPANDSP_SWEPT_TONE_H_ - -/*! \page swept_tone_page The swept tone generator -\section swept_tone_page_sec_1 What does it do? -*/ - -typedef struct swept_tone_state_s swept_tone_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(swept_tone_state_t *) swept_tone_init(swept_tone_state_t *s, float start, float end, float level, int duration, int repeating); - -SPAN_DECLARE(int) swept_tone(swept_tone_state_t *s, int16_t amp[], int len); - -SPAN_DECLARE(float) swept_tone_current_frequency(swept_tone_state_t *s); - -SPAN_DECLARE(int) swept_tone_release(swept_tone_state_t *s); - -SPAN_DECLARE(int) swept_tone_free(swept_tone_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h deleted file mode 100644 index 00749004f2..0000000000 --- a/libs/spandsp/src/spandsp/t30.h +++ /dev/null @@ -1,639 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30.h - definitions for T.30 fax processing - * - * 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 */ - -#if !defined(_SPANDSP_T30_H_) -#define _SPANDSP_T30_H_ - -/*! \page t30_page T.30 FAX protocol handling - -\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 features. It does not interface to the outside world. -Seperate modules do that for T.38, analogue line, and other forms of FAX -communication. - -Current features of this module include: - - - FAXing to and from multi-page TIFF/F files, whose images are one of the standard - FAX sizes. - - V.27ter, V.29 and V.17 modes (2400bps, to 14,400bps). - - T.4 1D (MH), T.4 2D,(MR) and T.6 (MMR) compression. - - Error correction mode (ECM). - - All standard horizonal resolutions (R8, R16, 300dpi, 600dpi, 800dpi, 1200dpi). - - All standard vertical resolutions (standard, fine, superfine, 300dpi, 600dpi, 800dpi, 1200dpi). - - All standard page widths (A4, B4, A3). - - All standard page lengths (A4, B4, North American letter, North American legal, continuous). - - Monitoring and sending identifier strings (CSI, TSI, and CIG). - - Monitoring and sending sub-address strings (SUB). - - Monitoring and sending polling sub-addresses (SEP). - - Monitoring and sending polled sub-addresses (PSA). - - Monitoring and sending sender identifications (SID). - - Monitoring and sending passwords (PWD). - - Monitoring of non-standard facility frames (NSF, NSC, and NSS). - - Sending custom non-standard facility frames (NSF, NSC, and NSS). - - Analogue modem and T.38 operation. - -\section t30_page_sec_2 How does it work? - -Some of the following is paraphrased from some notes found a while ago on the Internet. -I cannot remember exactly where they came from, but they are useful. - -\subsection t30_page_sec_2a The answer (CED) tone - -The T.30 standard says an answering fax device must send CED (a 2100Hz tone) for -approximately 3 seconds before sending the first handshake message. Some machines -send an 1100Hz or 1850Hz tone, and some send no tone at all. In fact, this answer -tone is so unpredictable, it cannot really be used. It should, however, always be -generated according to the specification. - -\subsection t30_page_sec_2b Common Timing Deviations - -The T.30 spec. specifies a number of time-outs. For example, after dialing a number, -a calling fax system should listen for a response for 35 seconds before giving up. -These time-out periods are as follows: - - - T1 - 35+-5s: the maximum time for which two fax system will attempt to identify each other - - T2 - 6+-1s: a time-out used to start the sequence for changing transmit parameters - - T3 - 10+-5s: a time-out used in handling operator interrupts - - T5 - 60+-5s: a time-out used in error correction mode - -These time-outs are sometimes misinterpreted. In addition, they are routinely -ignored, sometimes with good reason. For example, after placing a call, the -calling fax system is supposed to wait for 35 seconds before giving up. If the -answering unit does not answer on the first ring or if a voice answering machine -is connected to the line, or if there are many delays through the network, -the delay before answer can be much longer than 35 seconds. - -Fax units that support error correction mode (ECM) can respond to a post-image -handshake message with a receiver not ready (RNR) message. The calling unit then -queries the receiving fax unit with a receiver ready (RR) message. If the -answering unit is still busy (printing for example), it will repeat the RNR -message. According to the T.30 standard, this sequence (RR/RNR RR/RNR) can be -repeated for up to the end of T5 (60+-5s). However, many fax systems -ignore the time-out and will continue the sequence indefinitely, unless the user -manually overrides. - -All the time-outs are subject to alteration, and sometimes misuse. Good T.30 -implementations must do the right thing, and tolerate others doing the wrong thing. - -\subsection t30_page_sec_2c Variations in the inter-carrier gap - -T.30 specifies 75+-20ms of silence between signals using different modulation -schemes. Examples are between the end of a DCS signal and the start of a TCF signal, -and between the end of an image and the start of a post-image signal. Many fax systems -violate this requirement, especially for the silent period between DCS and TCF. -This may be stretched to well over 100ms. If this period is too long, it can interfere with -handshake signal error recovery, should a packet be corrupted on the line. Systems -should ensure they stay within the prescribed T.30 limits, and be tolerant of others -being out of spec.. - -\subsection t30_page_sec_2d Other timing variations - -Testing is required to determine the ability of a fax system to handle -variations in the duration of pauses between unacknowledged handshake message -repetitions, and also in the pauses between the receipt of a handshake command and -the start of a response to that command. In order to reduce the total -transmission time, many fax systems start sending a response message before the -end of the command has been received. - -\subsection t30_page_sec_2e Other deviations from the T.30 standard - -There are many other commonly encountered variations between machines, including: - - - frame sequence deviations - - preamble and flag sequence variations - - improper EOM usage - - unusual data rate fallback sequences - - common training pattern detection algorithms - - image transmission deviations - - use of the talker echo protect tone - - image padding and short lines - - RTP/RTN handshake message usage - - long duration lines - - nonstandard disconnect sequences - - DCN usage -*/ - -/*! The maximum length of a DIS, DTC or DCS frame */ -#define T30_MAX_DIS_DTC_DCS_LEN 22 -/*! The maximum length of the body of an ident string */ -#define T30_MAX_IDENT_LEN 20 -/*! The maximum length of the user string to insert in page headers */ -#define T30_MAX_PAGE_HEADER_INFO 50 - -typedef struct t30_state_s t30_state_t; - -/*! - T.30 phase B callback handler. This handler can be used to process addition - information available in some FAX calls, such as passwords. The callback handler - can access whatever additional information might have been received, using - t30_get_received_info(). - \brief T.30 phase B callback handler. - \param user_data An opaque pointer. - \param result The phase B event code. - \return The new status. Normally, T30_ERR_OK is returned. -*/ -typedef int (*t30_phase_b_handler_t)(void *user_data, int result); - -/*! - T.30 phase D callback handler. - \brief T.30 phase D callback handler. - \param user_data An opaque pointer. - \param result The phase D event code. - \return The new status. Normally, T30_ERR_OK is returned. -*/ -typedef int (*t30_phase_d_handler_t)(void *user_data, int result); - -/*! - T.30 phase E callback handler. - \brief T.30 phase E callback handler. - \param user_data An opaque pointer. - \param completion_code The phase E completion code. -*/ -typedef void (*t30_phase_e_handler_t)(void *user_data, int completion_code); - -/*! - T.30 real time frame handler. - \brief T.30 real time frame handler. - \param user_data An opaque pointer. - \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)(void *user_data, - bool direction, - const uint8_t msg[], - int len); - -/*! - T.30 document handler. - \brief T.30 document handler. - \param user_data An opaque pointer. - \param result The document event code. -*/ -typedef int (*t30_document_handler_t)(void *user_data, int status); - -/*! - T.30 set a receive or transmit type handler. - \brief T.30 set a receive or transmit type handler. - \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. -*/ -typedef void (*t30_set_handler_t)(void *user_data, int type, int bit_rate, int short_train, int use_hdlc); - -/*! - T.30 send HDLC handler. - \brief T.30 send HDLC handler. - \param user_data An opaque pointer. - \param msg The HDLC message. - \param len The length of the message. -1 to flush the HDLC queue. -*/ -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. -*/ -enum -{ - T30_ERR_OK = 0, /*! OK */ - - /* Link problems */ - T30_ERR_CEDTONE, /*! The CED tone exceeded 5s */ - T30_ERR_T0_EXPIRED, /*! Timed out waiting for initial communication */ - T30_ERR_T1_EXPIRED, /*! Timed out waiting for the first message */ - T30_ERR_T3_EXPIRED, /*! Timed out waiting for procedural interrupt */ - T30_ERR_HDLC_CARRIER, /*! The HDLC carrier did not stop in a timely manner */ - T30_ERR_CANNOT_TRAIN, /*! Failed to train with any of the compatible modems */ - T30_ERR_OPER_INT_FAIL, /*! Operator intervention failed */ - T30_ERR_INCOMPATIBLE, /*! Far end is not compatible */ - T30_ERR_RX_INCAPABLE, /*! Far end is not able to receive */ - T30_ERR_TX_INCAPABLE, /*! Far end is not able to transmit */ - T30_ERR_NORESSUPPORT, /*! Far end cannot receive at the resolution of the image */ - T30_ERR_NOSIZESUPPORT, /*! Far end cannot receive at the size of image */ - T30_ERR_UNEXPECTED, /*! Unexpected message received */ - - /* Phase E status values returned to a transmitter */ - T30_ERR_TX_BADDCS, /*! Received bad response to DCS or training */ - T30_ERR_TX_BADPG, /*! Received a DCN from remote after sending a page */ - T30_ERR_TX_ECMPHD, /*! Invalid ECM response received from receiver */ - T30_ERR_TX_GOTDCN, /*! Received a DCN while waiting for a DIS */ - T30_ERR_TX_INVALRSP, /*! Invalid response after sending a page */ - T30_ERR_TX_NODIS, /*! Received other than DIS while waiting for DIS */ - T30_ERR_TX_PHBDEAD, /*! Received no response to DCS, training or TCF */ - T30_ERR_TX_PHDDEAD, /*! No response after sending a page */ - T30_ERR_TX_T5EXP, /*! Timed out waiting for receiver ready (ECM mode) */ - - /* Phase E status values returned to a receiver */ - T30_ERR_RX_ECMPHD, /*! Invalid ECM response received from transmitter */ - T30_ERR_RX_GOTDCS, /*! DCS received while waiting for DTC */ - T30_ERR_RX_INVALCMD, /*! Unexpected command after page received */ - T30_ERR_RX_NOCARRIER, /*! Carrier lost during fax receive */ - T30_ERR_RX_NOEOL, /*! Timed out while waiting for EOL (end of line) */ - T30_ERR_RX_NOFAX, /*! Timed out while waiting for first line */ - T30_ERR_RX_T2EXPDCN, /*! Timer T2 expired while waiting for DCN */ - T30_ERR_RX_T2EXPD, /*! Timer T2 expired while waiting for phase D */ - T30_ERR_RX_T2EXPFAX, /*! Timer T2 expired while waiting for fax page */ - T30_ERR_RX_T2EXPMPS, /*! Timer T2 expired while waiting for next fax page */ - T30_ERR_RX_T2EXPRR, /*! Timer T2 expired while waiting for RR command */ - T30_ERR_RX_T2EXP, /*! Timer T2 expired while waiting for NSS, DCS or MCF */ - T30_ERR_RX_DCNWHY, /*! Unexpected DCN while waiting for DCS or DIS */ - T30_ERR_RX_DCNDATA, /*! Unexpected DCN while waiting for image data */ - T30_ERR_RX_DCNFAX, /*! Unexpected DCN while waiting for EOM, EOP or MPS */ - T30_ERR_RX_DCNPHD, /*! Unexpected DCN after EOM or MPS sequence */ - T30_ERR_RX_DCNRRD, /*! Unexpected DCN after RR/RNR sequence */ - T30_ERR_RX_DCNNORTN, /*! Unexpected DCN after requested retransmission */ - - /* TIFF file problems */ - T30_ERR_FILEERROR, /*! TIFF/F file cannot be opened */ - T30_ERR_NOPAGE, /*! TIFF/F page not found */ - T30_ERR_BADTIFF, /*! TIFF/F format is not compatible */ - T30_ERR_BADPAGE, /*! TIFF/F page number tag missing */ - T30_ERR_BADTAG, /*! Incorrect values for TIFF/F tags */ - T30_ERR_BADTIFFHDR, /*! Bad TIFF/F header - incorrect values in fields */ - T30_ERR_NOMEM, /*! Cannot allocate memory for more pages */ - - /* General problems */ - T30_ERR_RETRYDCN, /*! Disconnected after permitted retries */ - T30_ERR_CALLDROPPED, /*! The call dropped prematurely */ - - /* Feature negotiation issues */ - T30_ERR_NOPOLL, /*! Poll not accepted */ - T30_ERR_IDENT_UNACCEPTABLE, /*! Far end's ident is not acceptable */ - T30_ERR_SUB_UNACCEPTABLE, /*! Far end's sub-address is not acceptable */ - T30_ERR_SEP_UNACCEPTABLE, /*! Far end's selective polling address is not acceptable */ - T30_ERR_PSA_UNACCEPTABLE, /*! Far end's polled sub-address is not acceptable */ - T30_ERR_SID_UNACCEPTABLE, /*! Far end's sender identification is not acceptable */ - T30_ERR_PWD_UNACCEPTABLE, /*! Far end's password is not acceptable */ - T30_ERR_TSA_UNACCEPTABLE, /*! Far end's transmitting subscriber internet address is not acceptable */ - T30_ERR_IRA_UNACCEPTABLE, /*! Far end's internet routing address is not acceptable */ - T30_ERR_CIA_UNACCEPTABLE, /*! Far end's calling subscriber internet address is not acceptable */ - T30_ERR_ISP_UNACCEPTABLE, /*! Far end's internet selective polling address is not acceptable */ - T30_ERR_CSA_UNACCEPTABLE /*! Far end's called subscriber internet address is not acceptable */ -}; - -/*! - I/O modes for the T.30 protocol. - These are allocated such that the lower 4 bits represents the variant of the modem - e.g. the - particular bit rate selected. -*/ -enum -{ - T30_MODEM_NONE = 0, - T30_MODEM_PAUSE, - T30_MODEM_CED, - T30_MODEM_CNG, - T30_MODEM_V21, - T30_MODEM_V27TER, - T30_MODEM_V29, - T30_MODEM_V17, - T30_MODEM_V34HDX, - T30_MODEM_DONE -}; - -enum -{ - /*! Support the V.27ter modem (2400, and 4800bps) for image transfer. */ - T30_SUPPORT_V27TER = 0x01, - /*! Support the V.29 modem (9600, and 7200bps) for image transfer. */ - T30_SUPPORT_V29 = 0x02, - /*! Support the V.17 modem (14400, 12000, 9600 and 7200bps) for image transfer. */ - T30_SUPPORT_V17 = 0x04, - /*! Support the V.34 modem (up to 33,600bps) for image transfer. */ - T30_SUPPORT_V34HDX = 0x08, - /*! Support the Internet aware FAX mode (no bit rate limit) for image transfer. */ - T30_SUPPORT_IAF = 0x10 -}; - -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 -{ - /*! Enable support of identification, through the SID and/or PWD frames. */ - T30_SUPPORT_IDENTIFICATION = 0x01, - /*! Enable support of selective polling, through the SEP frame. */ - T30_SUPPORT_SELECTIVE_POLLING = 0x02, - /*! Enable support of polling sub-addressing, through the PSA frame. */ - T30_SUPPORT_POLLED_SUB_ADDRESSING = 0x04, - /*! Enable support of multiple selective polling, through repeated used of the SEP and PSA frames. */ - T30_SUPPORT_MULTIPLE_SELECTIVE_POLLING = 0x08, - /*! Enable support of sub-addressing, through the SUB frame. */ - T30_SUPPORT_SUB_ADDRESSING = 0x10, - /*! Enable support of transmitting subscriber internet address, through the TSA frame. */ - T30_SUPPORT_TRANSMITTING_SUBSCRIBER_INTERNET_ADDRESS = 0x20, - /*! Enable support of internet routing address, through the IRA frame. */ - T30_SUPPORT_INTERNET_ROUTING_ADDRESS = 0x40, - /*! Enable support of calling subscriber internet address, through the CIA frame. */ - T30_SUPPORT_CALLING_SUBSCRIBER_INTERNET_ADDRESS = 0x80, - /*! Enable support of internet selective polling address, through the ISP frame. */ - T30_SUPPORT_INTERNET_SELECTIVE_POLLING_ADDRESS = 0x100, - /*! Enable support of called subscriber internet address, through the CSA frame. */ - T30_SUPPORT_CALLED_SUBSCRIBER_INTERNET_ADDRESS = 0x200, - /*! Enable support of the field not valid (FNV) frame. */ - T30_SUPPORT_FIELD_NOT_VALID = 0x400, - /*! Enable support of the command repeat (CRP) frame. */ - T30_SUPPORT_COMMAND_REPEAT = 0x800 -}; - -enum -{ - T30_IAF_MODE_T37 = 0x01, - T30_IAF_MODE_T38 = 0x02, - T30_IAF_MODE_FLOW_CONTROL = 0x04, - /*! Continuous flow mode means data is sent as fast as possible, usually across - the Internet, where speed is not constrained by a PSTN modem. */ - T30_IAF_MODE_CONTINUOUS_FLOW = 0x08, - /*! No TCF means TCF is not exchanged. The end points must sort out usable speed - issues locally. */ - T30_IAF_MODE_NO_TCF = 0x10, - /*! No fill bits means do not insert fill bits, even if the T.30 messages request - them. */ - T30_IAF_MODE_NO_FILL_BITS = 0x20, - /*! No indicators means do not send indicator messages when using T.38. */ - T30_IAF_MODE_NO_INDICATORS = 0x40, - /*! Use relaxed timers for T.38. This is appropriate when using TCP/TPKT for T.38, - as there is no point in anything but a long backstop timeout in such a mode. */ - T30_IAF_MODE_RELAXED_TIMERS = 0x80 -}; - -typedef struct -{ - /*! \brief The identifier string (CSI, TSI, CIG). */ - char ident[T30_MAX_IDENT_LEN + 1]; - /*! \brief The sub-address string (SUB). */ - char sub_address[T30_MAX_IDENT_LEN + 1]; - /*! \brief The selective polling sub-address (SEP). */ - char selective_polling_address[T30_MAX_IDENT_LEN + 1]; - /*! \brief The polled sub-address (PSA). */ - char polled_sub_address[T30_MAX_IDENT_LEN + 1]; - /*! \brief The sender identification (SID). */ - char sender_ident[T30_MAX_IDENT_LEN + 1]; - /*! \brief The password (PWD). */ - char password[T30_MAX_IDENT_LEN + 1]; - /*! \brief Non-standard facilities (NSF). */ - uint8_t *nsf; - size_t nsf_len; - /*! \brief Non-standard facilities command (NSC). */ - uint8_t *nsc; - size_t nsc_len; - /*! \brief Non-standard facilities set-up (NSS). */ - uint8_t *nss; - size_t nss_len; - /*! \brief Transmitting subscriber internet address (TSA). */ - int tsa_type; - char *tsa; - size_t tsa_len; - /*! \brief Internet routing address (IRA). */ - int ira_type; - char *ira; - size_t ira_len; - /*! \brief Calling subscriber internet address (CIA). */ - int cia_type; - char *cia; - size_t cia_len; - /*! \brief Internet selective polling address (ISP). */ - int isp_type; - char *isp; - size_t isp_len; - /*! \brief Called subscriber internet address (CSA). */ - int csa_type; - char *csa; - size_t csa_len; -} t30_exchanged_info_t; - -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 The number of pages sent so far. */ - int pages_tx; - /*! \brief The number of pages received so far. */ - int pages_rx; - /*! \brief The number of pages in the file (<0 if not known). */ - int pages_in_file; - /*! \brief The type of image of the most recent file page */ - int image_type; - /*! \brief The horizontal column-to-column resolution of the most recent file page, in pixels per metre */ - int image_x_resolution; - /*! \brief The vertical row-to-row resolution of the most recent file page, in pixels per metre */ - int image_y_resolution; - /*! \brief The number of horizontal pixels in the most recent file page. */ - int image_width; - /*! \brief The number of vertical pixels in the most recent file page. */ - int image_length; - /*! \brief The type of image of the most recent exchanged page */ - int type; - /*! \brief The horizontal column-to-column resolution of the most recent exchanged page, in pixels per metre */ - int x_resolution; - /*! \brief The vertical row-to-row resolution of the most recent exchanged page, in pixels per metre */ - int y_resolution; - /*! \brief The number of horizontal pixels in the most recent exchanged page. */ - int width; - /*! \brief The number of vertical pixels in the most recent exchanged page. */ - int length; - /*! \brief The size of the image, in bytes */ - int image_size; - /*! \brief The type of compression used between the FAX machines */ - 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. */ - int longest_bad_row_run; - /*! \brief The number of HDLC frame retries, if error correcting mode is used. */ - int error_correcting_mode_retries; - /*! \brief Current status. */ - int current_status; - /*! \brief The number of RTP events in this call. */ - int rtp_events; - /*! \brief The number of RTN events in this call. */ - int rtn_events; -} t30_stats_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! 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 - context is for an answering party. - \param set_rx_type_handler - \param set_rx_type_user_data - \param set_tx_type_handler - \param set_tx_type_user_data - \param send_hdlc_handler - \param send_hdlc_user_data - \return A pointer to the context, or NULL if there was a problem. */ -SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s, - bool calling_party, - t30_set_handler_t set_rx_type_handler, - void *set_rx_type_user_data, - t30_set_handler_t set_tx_type_handler, - void *set_tx_type_user_data, - t30_send_hdlc_handler_t send_hdlc_handler, - void *send_hdlc_user_data); - -/*! Release a T.30 context. - \brief Release a T.30 context. - \param s The T.30 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_release(t30_state_t *s); - -/*! Free a T.30 context. - \brief Free a T.30 context. - \param s The T.30 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_free(t30_state_t *s); - -/*! Restart a T.30 context. - \brief Restart 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 - context is for an answering party. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_restart(t30_state_t *s, bool calling_party); - -/*! Check if a T.30 call is still active. This may be used to regularly poll - 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. */ -SPAN_DECLARE(int) t30_call_active(t30_state_t *s); - -/*! Cleanup a T.30 context if the call terminates. - \brief Cleanup a T.30 context if the call terminates. - \param s The T.30 context. */ -SPAN_DECLARE(void) t30_terminate(t30_state_t *s); - -/*! Inform the T.30 engine of a status change in the front end (end of tx, rx signal change, etc.). - \brief Inform the T.30 engine of a status change in the front end (end of tx, rx signal change, etc.). - \param user_data The T.30 context. - \param status The type of status change which occured. */ -SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status); - -/*! Get a bit of received non-ECM image data. - \brief Get a bit of received non-ECM image data. - \param user_data An opaque pointer, which must point to the T.30 context. - \return The next bit to transmit. */ -SPAN_DECLARE(int) t30_non_ecm_get_bit(void *user_data); - -/*! Get a chunk of received non-ECM image data. - \brief Get a bit of received non-ECM image data. - \param user_data An opaque pointer, which must point to the T.30 context. - \param buf The buffer to contain the data. - \param max_len The maximum length of the chunk. - \return The actual length of the chunk. */ -SPAN_DECLARE(int) t30_non_ecm_get(void *user_data, uint8_t buf[], int max_len); - -/*! Process a bit of received non-ECM image data. - \brief Process a bit of received non-ECM image data - \param user_data An opaque pointer, which must point to the T.30 context. - \param bit The received bit. */ -SPAN_DECLARE(void) t30_non_ecm_put_bit(void *user_data, int bit); - -/*! Process a chunk of received non-ECM image data. - \brief Process a chunk of received non-ECM image data - \param user_data An opaque pointer, which must point to the T.30 context. - \param buf The buffer containing the received data. - \param len The length of the data in buf. */ -SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len); - -/*! Process a received HDLC frame. - \brief Process a received HDLC frame. - \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. */ -SPAN_DECLARE(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. - \brief Report the passage of time to the T.30 engine. - \param s The T.30 context. - \param samples The time change in 1/8000th second steps. */ -SPAN_DECLARE(void) t30_timer_update(t30_state_t *s, int samples); - -/*! Get the current transfer statistics for the file being sent or received. - \brief Get the current transfer statistics. - \param s The T.30 context. - \param t A pointer to a buffer for the statistics. */ -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. */ -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. */ -SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t30_api.h b/libs/spandsp/src/spandsp/t30_api.h deleted file mode 100644 index e6b47fb877..0000000000 --- a/libs/spandsp/src/spandsp/t30_api.h +++ /dev/null @@ -1,590 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_api.h - definitions for T.30 fax processing - * - * 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 */ - -#if !defined(_SPANDSP_T30_API_H_) -#define _SPANDSP_T30_API_H_ - -enum -{ - T33_NONE = 0, - T33_SST = 1, - T33_EXT = 2 -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Get the specified field from a T.33 formatted string. - \brief Get the specified field from a T.33 formatted string. - \param field The extracted field. - \param t33 The T.33 formatted string. - \param field_no The field number to extract. The first field is 0. - \return The extracted field type. -1 indicates a over length or badly formatted field. */ -SPAN_DECLARE(int) t33_sub_address_extract_field(uint8_t field[21], const uint8_t t33[], int field_no); - -/*! Append the specified field to a T.33 formatted string. - \brief Append the specified field to a T.33 formatted string. - \param t33 The T.33 formatted string. - \param field The field to be adppended. - \param type The type of the field to be appended. */ -SPAN_DECLARE(void) t33_sub_address_add_field(uint8_t t33[], const uint8_t field[], int type); - -/*! Set the transmitted NSF frame to be associated with a T.30 context. - \brief Set the transmitted NSF frame to be associated with a T.30 context. - \param s The T.30 context. - \param nsf A pointer to the frame. - \param len The length of the frame. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_nsf(t30_state_t *s, const uint8_t *nsf, int len); - -/*! Get an NSF frame to be associated with a T.30 context. - \brief Set an NSF frame to be associated with a T.30 context. - \param s The T.30 context. - \param nsf A pointer to the frame. - \return the length of the NSF message. */ -SPAN_DECLARE(size_t) t30_get_tx_nsf(t30_state_t *s, const uint8_t *nsf[]); - -/*! Get an NSF frame to be associated with a T.30 context. - \brief Set an NSF frame to be associated with a T.30 context. - \param s The T.30 context. - \param nsf A pointer to the frame. - \return the length of the NSF message. */ -SPAN_DECLARE(size_t) t30_get_rx_nsf(t30_state_t *s, const uint8_t *nsf[]); - -/*! Set the transmitted NSC frame to be associated with a T.30 context. - \brief Set the transmitted NSC frame to be associated with a T.30 context. - \param s The T.30 context. - \param nsc A pointer to the frame. - \param len The length of the frame. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_nsc(t30_state_t *s, const uint8_t *nsc, int len); - -/*! Get an NSC frame to be associated with a T.30 context. - \brief Set an NSC frame to be associated with a T.30 context. - \param s The T.30 context. - \param nsc A pointer to the frame. - \return the length of the NSC message. */ -SPAN_DECLARE(size_t) t30_get_tx_nsc(t30_state_t *s, const uint8_t *nsc[]); - -/*! Get an NSC frame to be associated with a T.30 context. - \brief Set an NSC frame to be associated with a T.30 context. - \param s The T.30 context. - \param nsc A pointer to the frame. - \return the length of the NSC message. */ -SPAN_DECLARE(size_t) t30_get_rx_nsc(t30_state_t *s, const uint8_t *nsc[]); - -/*! Set the transmitted NSS frame to be associated with a T.30 context. - \brief Set the transmitted NSS frame to be associated with a T.30 context. - \param s The T.30 context. - \param nss A pointer to the frame. - \param len The length of the frame. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_nss(t30_state_t *s, const uint8_t *nss, int len); - -/*! Get an NSS frame to be associated with a T.30 context. - \brief Set an NSS frame to be associated with a T.30 context. - \param s The T.30 context. - \param nss A pointer to the frame. - \return the length of the NSS message. */ -SPAN_DECLARE(size_t) t30_get_tx_nss(t30_state_t *s, const uint8_t *nss[]); - -/*! Get an NSS frame to be associated with a T.30 context. - \brief Set an NSS frame to be associated with a T.30 context. - \param s The T.30 context. - \param nss A pointer to the frame. - \return the length of the NSS message. */ -SPAN_DECLARE(size_t) t30_get_rx_nss(t30_state_t *s, const uint8_t *nss[]); - -/*! Set the transmitted identifier associated with a T.30 context. - \brief Set the transmitted identifier associated with a T.30 context. - \param s The T.30 context. - \param id A pointer to the identifier. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_ident(t30_state_t *s, const char *id); - -/*! Get the transmitted identifier associated with a T.30 context. - \brief Set the transmitted identifier associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the identifier. */ -SPAN_DECLARE(const char *) t30_get_tx_ident(t30_state_t *s); - -/*! Get the transmitted identifier associated with a T.30 context. - \brief Set the transmitted identifier associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the identifier. */ -SPAN_DECLARE(const char *) t30_get_rx_ident(t30_state_t *s); - -/*! Set the transmitted sub-address associated with a T.30 context. - \brief Set the transmitted sub-address associated with a T.30 context. - \param s The T.30 context. - \param sub_address A pointer to the sub-address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_sub_address(t30_state_t *s, const char *sub_address); - -/*! Get the received sub-address associated with a T.30 context. - \brief Get the received sub-address associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the sub-address. */ -SPAN_DECLARE(const char *) t30_get_tx_sub_address(t30_state_t *s); - -/*! Get the received sub-address associated with a T.30 context. - \brief Get the received sub-address associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the sub-address. */ -SPAN_DECLARE(const char *) t30_get_rx_sub_address(t30_state_t *s); - -/*! Set the transmitted selective polling address (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted selective polling address associated with a T.30 context. - \param s The T.30 context. - \param selective_polling_address A pointer to the selective polling address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_selective_polling_address(t30_state_t *s, const char *selective_polling_address); - -/*! Get the received selective polling address (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received selective polling address associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the selective polling address. */ -SPAN_DECLARE(const char *) t30_get_tx_selective_polling_address(t30_state_t *s); - -/*! Get the received selective polling address (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received selective polling address associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the selective polling address. */ -SPAN_DECLARE(const char *) t30_get_rx_selective_polling_address(t30_state_t *s); - -/*! Set the transmitted polled sub-address (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted polled sub-address associated with a T.30 context. - \param s The T.30 context. - \param polled_sub_address A pointer to the polled sub-address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_polled_sub_address(t30_state_t *s, const char *polled_sub_address); - -/*! Get the received polled sub-address (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received polled sub-address associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the polled sub-address. */ -SPAN_DECLARE(const char *) t30_get_tx_polled_sub_address(t30_state_t *s); - -/*! Get the received polled sub-address (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received polled sub-address associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the polled sub-address. */ -SPAN_DECLARE(const char *) t30_get_rx_polled_sub_address(t30_state_t *s); - -/*! Set the transmitted sender ident (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted sender ident associated with a T.30 context. - \param s The T.30 context. - \param sender_ident A pointer to the sender ident. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_sender_ident(t30_state_t *s, const char *sender_ident); - -/*! Get the received sender ident (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received sender ident associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the sender ident. */ -SPAN_DECLARE(const char *) t30_get_tx_sender_ident(t30_state_t *s); - -/*! Get the received sender ident (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received sender ident associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the sender ident. */ -SPAN_DECLARE(const char *) t30_get_rx_sender_ident(t30_state_t *s); - -/*! Set the transmitted password (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted password associated with a T.30 context. - \param s The T.30 context. - \param password A pointer to the password. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_password(t30_state_t *s, const char *password); - -/*! Get the received password (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received password associated with a T.30 context. - \param s The T.30 context. - \return A pointer to the password. */ -SPAN_DECLARE(const char *) t30_get_tx_password(t30_state_t *s); - -/*! Get the received password (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received password associated with a T.30 context. - \param s The T.30 context. - \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. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \param len The length of the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_tsa(t30_state_t *s, int type, const char *address, int len); - -/*! Get the transmitted TSA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received TSA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return The length of the address. */ -SPAN_DECLARE(size_t) t30_get_tx_tsa(t30_state_t *s, int *type, const char *address[]); - -/*! Get the received TSA associated with a T.30 context. - \brief Get the received TSA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return The length of the address. */ -SPAN_DECLARE(size_t) t30_get_rx_tsa(t30_state_t *s, int *type, const char *address[]); - -/*! Set the transmitted IRA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted IRA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \param len The length of the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_ira(t30_state_t *s, int type, const char *address, int len); - -/*! Get the transmitted IRA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received IRA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return The length of the address. */ -SPAN_DECLARE(size_t) t30_get_tx_ira(t30_state_t *s, int *type, const char *address[]); - -/*! Get the received IRA associated with a T.30 context. - \brief Get the received IRA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return The length of the address. */ -SPAN_DECLARE(size_t) t30_get_rx_ira(t30_state_t *s, int *type, const char *address[]); - -/*! Set the transmitted CIA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted CIA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \param len The length of the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_cia(t30_state_t *s, int type, const char *address, int len); - -/*! Get the transmitted CIA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received CIA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return The length of the address. */ -SPAN_DECLARE(size_t) t30_get_tx_cia(t30_state_t *s, int *type, const char *address[]); - -/*! Get the received CIA associated with a T.30 context. - \brief Get the received CIA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(size_t) t30_get_rx_cia(t30_state_t *s, int *type, const char *address[]); - -/*! Set the transmitted ISP (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted ISP associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \param len The length of the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_isp(t30_state_t *s, int type, const char *address, int len); - -/*! Get the transmitted ISP (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received ISP associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(size_t) t30_get_tx_isp(t30_state_t *s, int *type, const char *address[]); - -/*! Get the received ISP associated with a T.30 context. - \brief Get the received ISP associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(size_t) t30_get_rx_isp(t30_state_t *s, int *type, const char *address[]); - -/*! Set the transmitted CSA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Set the transmitted CSA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \param len The length of the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_csa(t30_state_t *s, int type, const char *address, int len); - -/*! Get the transmitted CSA (i.e. the one we will send to the far - end) associated with a T.30 context. - \brief Get the received CSA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return The length of the address. */ -SPAN_DECLARE(size_t) t30_get_tx_csa(t30_state_t *s, int *type, const char *address[]); - -/*! Get the received CSA associated with a T.30 context. - \brief Get the received CSA associated with a T.30 context. - \param s The T.30 context. - \param type The type of address. - \param address A pointer to the address. - \return 0 for OK, else -1. */ -SPAN_DECLARE(size_t) t30_get_rx_csa(t30_state_t *s, int *type, const char *address[]); - -/*! 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, 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. - \param s The T.30 context. - \param info A pointer to the information string. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_page_header_info(t30_state_t *s, const char *info); - -/*! Set the transmitted header timestamp timezone associated with a T.30 context. - \brief Set the transmitted header timestamp timezone associated with a T.30 context. - \param s The T.30 context. - \param info A pointer to the POSIZ timezone string. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t30_set_tx_page_header_tz(t30_state_t *s, const char *tzstring); - -/*! Get the header information associated with a T.30 context. - \brief Get the header information associated with a T.30 context. - \param s The T.30 context. - \param info A pointer to a buffer for the header information. The buffer - should be at least 51 bytes long. - \return the length of the string. */ -SPAN_DECLARE(size_t) t30_get_tx_page_header_info(t30_state_t *s, char *info); - -/*! Get the country of origin of the remote FAX machine associated with a T.30 context. - \brief Get the country of origin of the remote FAX machine associated with a T.30 context. - \param s The T.30 context. - \return a pointer to the country name, or NULL if the country is not known. */ -SPAN_DECLARE(const char *) t30_get_rx_country(t30_state_t *s); - -/*! Get the name of the vendor of the remote FAX machine associated with a T.30 context. - \brief Get the name of the vendor of the remote FAX machine associated with a T.30 context. - \param s The T.30 context. - \return a pointer to the vendor name, or NULL if the vendor is not known. */ -SPAN_DECLARE(const char *) t30_get_rx_vendor(t30_state_t *s); - -/*! Get the name of the model of the remote FAX machine associated with a T.30 context. - \brief Get the name of the model of the remote FAX machine associated with a T.30 context. - \param s The T.30 context. - \return a pointer to the model name, or NULL if the model is not known. */ -SPAN_DECLARE(const char *) t30_get_rx_model(t30_state_t *s); - -/*! Specify the file name of the next TIFF file to be received by a T.30 - context. - \brief Set next receive file name. - \param s The T.30 context. - \param file The file name - \param stop_page The maximum page to receive. -1 for no restriction. */ -SPAN_DECLARE(void) t30_set_rx_file(t30_state_t *s, const char *file, int stop_page); - -/*! Specify the file name of the next TIFF file to be transmitted by a T.30 - context. - \brief Set next transmit file name. - \param s The T.30 context. - \param file The file name - \param start_page The first page to send. -1 for no restriction. - \param stop_page The last page to send. -1 for no restriction. */ -SPAN_DECLARE(void) t30_set_tx_file(t30_state_t *s, const char *file, int start_page, int stop_page); - -/*! 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, 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, or false for not ECM capable. - \return 0 if OK, else -1. */ -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 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_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. - \param s The T.30 context. - \param min_time The minimum permitted scan line time, in milliseconds. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_minimum_scan_line_time(t30_state_t *s, int min_time); - -/*! Specify which modem types are supported by a T.30 context. - \brief Specify supported modems. - \param s The T.30 context. - \param supported_modems Bit field list of the supported modems. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_supported_modems(t30_state_t *s, int supported_modems); - -/*! Specify which compression types are supported by a T.30 context. - \brief Specify supported compression types. - \param s The T.30 context. - \param supported_compressions Bit field list of the supported compression types. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_compressions); - -/*! 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_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. - \param s The T.30 context. - \param supported_image_sizes Bit field list of the supported widths and lengths. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_supported_image_sizes(t30_state_t *s, int supported_image_sizes); - -/*! Specify which special T.30 features are supported by a T.30 context. - \brief Specify supported T.30 features. - \param s The T.30 context. - \param supported_t30_features Bit field list of the supported features. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_supported_t30_features(t30_state_t *s, int supported_t30_features); - -/*! Set T.30 status. This may be used to adjust the status from within - the phase B and phase D callbacks. - \brief Set T.30 status. - \param s The T.30 context. - \param status The new status. */ -SPAN_DECLARE(void) t30_set_status(t30_state_t *s, int status); - -/*! Specify a period of responding with receiver not ready. - \brief Specify a period of responding with receiver not ready. - \param s The T.30 context. - \param count The number of times to report receiver not ready. - \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_receiver_not_ready(t30_state_t *s, int count); - -/*! Set a callback function for T.30 phase B handling. - \brief Set a callback function for T.30 phase B handling. - \param s The T.30 context. - \param handler The callback function. - \param user_data An opaque pointer passed to the callback function. */ -SPAN_DECLARE(void) t30_set_phase_b_handler(t30_state_t *s, t30_phase_b_handler_t handler, void *user_data); - -/*! Set a callback function for T.30 phase D handling. - \brief Set a callback function for T.30 phase D handling. - \param s The T.30 context. - \param handler The callback function. - \param user_data An opaque pointer passed to the callback function. */ -SPAN_DECLARE(void) t30_set_phase_d_handler(t30_state_t *s, t30_phase_d_handler_t handler, void *user_data); - -/*! Set a callback function for T.30 phase E handling. - \brief Set a callback function for T.30 phase E handling. - \param s The T.30 context. - \param handler The callback function. - \param user_data An opaque pointer passed to the callback function. */ -SPAN_DECLARE(void) t30_set_phase_e_handler(t30_state_t *s, t30_phase_e_handler_t handler, void *user_data); - -/*! Set a callback function for T.30 end of document handling. - \brief Set a callback function for T.30 end of document handling. - \param s The T.30 context. - \param handler The callback function. - \param user_data An opaque pointer passed to the callback function. */ -SPAN_DECLARE(void) t30_set_document_handler(t30_state_t *s, t30_document_handler_t handler, void *user_data); - -/*! Set a callback function for T.30 frame exchange monitoring. This is called from the heart - of the signal processing, so don't take too long in the handler routine. - \brief Set a callback function for T.30 frame exchange monitoring. - \param s The T.30 context. - \param handler The callback function. - \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. - \return A pointer to the logging context, or NULL. -*/ -SPAN_DECLARE(logging_state_t *) t30_get_logging_state(t30_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t30_fcf.h b/libs/spandsp/src/spandsp/t30_fcf.h deleted file mode 100644 index 763627e435..0000000000 --- a/libs/spandsp/src/spandsp/t30_fcf.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_fcf.h - ITU T.30 fax control field definitions - * - * 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 */ - -#if !defined(_SPANDSP_T30_FCF_H_) -#define _SPANDSP_T30_FCF_H_ - -enum -{ - /*! Initial identification messages */ - /*! From the called to the calling terminal. */ - T30_DIS = 0x80, /*! [0000 0001] Digital identification signal */ - T30_CSI = 0x40, /*! [0000 0010] Called subscriber identification */ - T30_NSF = 0x20, /*! [0000 0100] Non-standard facilities */ - - /*! Commands to send */ - /*! From a calling terminal wishing to be a receiver, to a called terminal - which is capable of transmitting. */ - T30_DTC = 0x81, /*! [1000 0001] Digital transmit command */ - T30_CIG = 0x41, /*! [1000 0010] Calling subscriber identification */ - T30_NSC = 0x21, /*! [1000 0100] Non-standard facilities command */ - T30_PWD = 0xC1, /*! [1000 0011] Password */ - T30_SEP = 0xA1, /*! [1000 0101] Selective polling */ - T30_PSA = 0x61, /*! [1000 0110] Polled subaddress */ - T30_CIA = 0xE1, /*! [1000 0111] Calling subscriber internet address */ - T30_ISP = 0x11, /*! [1000 1000] Internet selective polling address */ - - /*! Commands to receive */ - /*! From a calling terminal wishing to be a transmitter, to a called terminal - which is capable of receiving. */ - T30_DCS = 0x82, /*! [X100 0001] Digital command signal */ - T30_TSI = 0x42, /*! [X100 0010] Transmitting subscriber information */ - T30_NSS = 0x22, /*! [X100 0100] Non-standard facilities set-up */ - T30_SUB = 0xC2, /*! [X100 0011] Sub-address */ - T30_SID = 0xA2, /*! [X100 0101] Sender identification */ - /*! T30_TCF - Training check is a burst of 1.5s of zeros sent using the image modem */ - T30_CTC = 0x12, /*! [X100 1000] Continue to correct */ - T30_TSA = 0x62, /*! [X100 0110] Transmitting subscriber internet address */ - T30_IRA = 0xE2, /*! [X100 0111] Internet routing address */ - - /*! Pre-message response signals */ - /*! From the receiver to the transmitter. */ - T30_CFR = 0x84, /*! [X010 0001] Confirmation to receive */ - T30_FTT = 0x44, /*! [X010 0010] Failure to train */ - T30_CTR = 0xC4, /*! [X010 0011] Response for continue to correct */ - T30_CSA = 0x24, /*! [X010 0100] Called subscriber internet address */ - - /*! Post-message commands */ - T30_EOM = 0x8E, /*! [X111 0001] End of message */ - T30_MPS = 0x4E, /*! [X111 0010] Multipage signal */ - T30_EOP = 0x2E, /*! [X111 0100] End of procedure */ - T30_PRI_EOM = 0x9E, /*! [X111 1001] Procedure interrupt - end of procedure */ - T30_PRI_MPS = 0x5E, /*! [X111 1010] Procedure interrupt - multipage signal */ - T30_PRI_EOP = 0x3E, /*! [X111 1100] Procedure interrupt - end of procedure */ - T30_EOS = 0x1E, /*! [X111 1000] End of selection */ - T30_PPS = 0xBE, /*! [X111 1101] Partial page signal */ - T30_EOR = 0xCE, /*! [X111 0011] End of retransmission */ - T30_RR = 0x6E, /*! [X111 0110] Receiver ready */ - - /*! Post-message responses */ - T30_MCF = 0x8C, /*! [X011 0001] Message confirmation */ - T30_RTP = 0xCC, /*! [X011 0011] Retrain positive */ - T30_RTN = 0x4C, /*! [X011 0010] Retrain negative */ - T30_PIP = 0xAC, /*! [X011 0101] Procedure interrupt positive */ - T30_PIN = 0x2C, /*! [X011 0100] Procedure interrupt negative */ - T30_PPR = 0xBC, /*! [X011 1101] Partial page request */ - T30_RNR = 0xEC, /*! [X011 0111] Receive not ready */ - T30_ERR = 0x1C, /*! [X011 1000] Response for end of retransmission */ - T30_FDM = 0xFC, /*! [X011 1111] File diagnostics message */ - - /*! Other line control signals */ - T30_DCN = 0xFA, /*! [X101 1111] Disconnect */ - T30_CRP = 0x1A, /*! [X101 1000] Command repeat */ - T30_FNV = 0xCA, /*! [X101 0011] Field not valid */ - T30_TNR = 0xEA, /*! [X101 0111] Transmitter not ready */ - T30_TR = 0x6A, /*! [X101 0110] Transmitter ready */ - T30_TK = 0x4B, /*! [1101 0010] Transmitter keys */ - T30_RK = 0x4A, /*! [0101 0010] Receiver keys */ - T30_PSS = 0x1F, /*! [1111 1000] Present signature signal (used only as FCF2) */ - T30_DES = 0xA0, /*! [0000 0101] Digital extended signal */ - T30_DEC = 0x93, /*! [1100 1001] Digital extended command */ - T30_DER = 0x53, /*! [1100 1010] Digital extended request */ - T30_DTR = 0x11, /*! [1000 1000] Digital turnaround request (conflicts with ISP) */ - T30_DNK = 0x9A, /*! [X101 1001] Digital not acknowledge */ - T30_PID = 0x6C, /*! [X011 0110] Procedure interrupt disconnect */ - T30_SPI = 0x10, /*! [0000 1000] Security page indicator */ - T30_SPT = 0x80, /*! [0000 0001] Security page type */ - - /*! Something only use as a secondary value in error correcting mode */ - T30_NULL = 0x00, /*! [0000 0000] Nothing to say */ - - /*! Information frame types used for error correction mode, in T.4 */ - T4_FCD = 0x06, /*! [0110 0000] Facsimile coded data */ - T4_CCD = 0x46, /*! [0110 0010] Character coded data */ - T4_RCP = 0x86 /*! [0110 0001] Return to control for partial page */ -}; - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t30_logging.h b/libs/spandsp/src/spandsp/t30_logging.h deleted file mode 100644 index 7122b1c6eb..0000000000 --- a/libs/spandsp/src/spandsp/t30_logging.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_logging.h - definitions for T.30 fax processing - * - * 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 */ - -#if !defined(_SPANDSP_T30_LOGGING_H_) -#define _SPANDSP_T30_LOGGING_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Return a text name for a T.30 frame type. - \brief Return a text name for a T.30 frame type. - \param x The frametype octet. - \return A pointer to the text name for the frame type. If the frame type is - not value, the string "???" is returned. */ -SPAN_DECLARE(const char *) t30_frametype(uint8_t x); - -/*! Decode a DIS, DTC or DCS frame, and log the contents. - \brief Decode a DIS, DTC or DCS frame, and log the contents. - \param s The T.30 context. - \param dis A pointer to the frame to be decoded. - \param len The length of the frame. */ -SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *dis, int len); - -/*! Convert a phase E completion code to a short text description. - \brief Convert a phase E completion code to a short text description. - \param result The result code. - \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 - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t31.h b/libs/spandsp/src/spandsp/t31.h deleted file mode 100644 index 45237c4e7c..0000000000 --- a/libs/spandsp/src/spandsp/t31.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t31.h - A T.31 compatible class 1 FAX modem interface. - * - * 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_T31_H_) -#define _SPANDSP_T31_H_ - -/*! \page t31_page T.31 Class 1 FAX modem protocol handling -\section t31_page_sec_1 What does it do? -The T.31 class 1 FAX modem modules implements a class 1 interface to the FAX -modems in spandsp. - -\section t31_page_sec_2 How does it work? -*/ - -/*! - T.31 descriptor. This defines the working state for a single instance of - a T.31 FAX modem. -*/ -typedef struct t31_state_s t31_state_t; - -typedef int (*t31_modem_control_handler_t)(t31_state_t *s, void *user_data, int op, const char *num); - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(void) t31_call_event(t31_state_t *s, int event); - -/*! Return the amount of free space in the AT COMMAND BUFFER. - \brief Return the amount of free space in the AT COMMAND BUFFER. - \param s The T.31 modem context. - \return The number of bytes of free space. */ -SPAN_DECLARE(int) t31_at_rx_free_space(t31_state_t *s); - -SPAN_DECLARE(int) t31_at_rx(t31_state_t *s, const char *t, int len); - -/*! Process a block of received T.31 modem audio samples. - \brief Process a block of received T.31 modem audio samples. - \param s The T.31 modem context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) t31_rx(t31_state_t *s, int16_t amp[], int len); - -/*! Fake processing of a missing block of received T.31 modem audio samples - (e.g due to packet loss). - \brief Fake processing of a missing block of received T.31 modem audio samples. - \param s The T.31 modem context. - \param len The number of samples to fake. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) t31_rx_fillin(t31_state_t *s, int len); - -/*! Generate a block of T.31 modem audio samples. - \brief Generate a block of T.31 modem audio samples. - \param s The T.31 modem context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len); - -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. -*/ -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 used. -*/ -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 - to be paced. -*/ -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. -*/ -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. - \param s The T.31 context. - \return A pointer to the logging context, or NULL. -*/ -SPAN_DECLARE(logging_state_t *) t31_get_logging_state(t31_state_t *s); - -/*! Get a pointer to the AT interpreter context associated with a T.31 context. - \brief Get a pointer to the AT interpreter context associated with a T.31 context. - \param s The T.31 context. - \return A pointer to the AT interpreter context, or NULL. -*/ -SPAN_DECLARE(at_state_t *) t31_get_at_state(t31_state_t *s); - -/*! Get a pointer to the T.38 core context associated with a T.31 context. - \brief Get a pointer to the T.38 core context associated with a T.31 context. - \param s The T.31 context. - \return A pointer to the T.38 core context, or NULL. -*/ -SPAN_DECLARE(t38_core_state_t *) t31_get_t38_core_state(t31_state_t *s); - -/*! Initialise a T.31 context. This must be called before the first - use of the context, to initialise its contents. - \brief Initialise a T.31 context. - \param s The T.31 context. - \param at_tx_handler A callback routine to handle AT interpreter channel output. - \param at_tx_user_data An opaque pointer passed in called to at_tx_handler. - \param modem_control_handler A callback routine to handle control of the modem (off-hook, etc). - \param modem_control_user_data An opaque pointer passed in called to modem_control_handler. - \param tx_t38_packet_handler ??? - \param tx_t38_packet_user_data ??? - \return A pointer to the T.31 context. */ -SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data, - t31_modem_control_handler_t modem_control_handler, - void *modem_control_user_data, - t38_tx_packet_handler_t tx_t38_packet_handler, - void *tx_t38_packet_user_data); - -/*! Release a T.31 context. - \brief Release a T.31 context. - \param s The T.31 context. - \return 0 for OK */ -SPAN_DECLARE(int) t31_release(t31_state_t *s); - -/*! Free a T.31 context. - \brief Release a T.31 context. - \param s The T.31 context. - \return 0 for OK */ -SPAN_DECLARE(int) t31_free(t31_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t35.h b/libs/spandsp/src/spandsp/t35.h deleted file mode 100644 index fdef41fdf2..0000000000 --- a/libs/spandsp/src/spandsp/t35.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t35.h - ITU T.35 FAX non-standard facility processing. - * - * 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 */ - -#if !defined(_SPANDSP_T35_H_) -#define _SPANDSP_T35_H_ - -/*! \page t35_page T.35 manufacturer specific processing for FAX machines -\section t35_page_sec_1 What does it do? -???. - -\section t35_page_sec_2 How does it work? -???. -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Resolve a T.35 country code its probable likely real value, using heuristics to try to resolve issues - of broken bit order in the country code. - \brief Resolve a T.35 country code with bit reversal resolution. - \param country_code The country code. - \param country_code_extension The country code extension. - \return The true country code, or -1 for an invalid code. -*/ -SPAN_DECLARE(int) t35_real_country_code(int country_code, int country_code_extension); - -/*! Decode a T.35 country code to a country name, using heuristics to try to resolve issues of broken bit order - in the country code. - \brief Decode a T.35 country code to a country name, with bit reversal resolution. - \param country_code The country code. - \param country_code_extension The country code extension. - \return The country name, or NULL for an invalid country code. -*/ -SPAN_DECLARE(const char *) t35_real_country_code_to_str(int country_code, int country_code_extension); - -/*! Decode a T.35 country code to a country name. - \brief Decode a T.35 country code to a country name. - \param country_code The country code. - \param country_code_extension The country code extension. - \return The country name, or NULL for an invalid country code. -*/ -SPAN_DECLARE(const char *) t35_country_code_to_str(int country_code, int country_code_extension); - -SPAN_DECLARE(const char *) t35_vendor_to_str(const uint8_t *msg, int len); - -/*! Decode an NSF field to try to determine the make and model of the - remote machine. - \brief Decode an NSF field. - \param msg The NSF message. - \param len The length of the NSF message. - \param country A pointer which will be pointed to the identified country of origin. - If a NULL pointer is given, the country of origin will not be returned. - If the country of origin is not identified, NULL will be returned. - \param vendor A pointer which will be pointed to the identified vendor. - If a NULL pointer is given, the vendor ID will not be returned. - If the vendor is not identified, NULL will be returned. - \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. -*/ -SPAN_DECLARE(bool) t35_decode(const uint8_t *msg, int len, const char **country, const char **vendor, const char **model); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t38_core.h b/libs/spandsp/src/spandsp/t38_core.h deleted file mode 100644 index 3d3d83da51..0000000000 --- a/libs/spandsp/src/spandsp/t38_core.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_core.h - An implementation of T.38, less the packet exchange part - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_T38_CORE_H_) -#define _SPANDSP_T38_CORE_H_ - -/*! \page t38_core_page T.38 real time FAX over IP message handling -There are two ITU recommendations which address sending FAXes over IP networks. T.37 specifies a -method of encapsulating FAX images in e-mails, and transporting them to the recipient (an e-mail -box, or another FAX machine) in a store-and-forward manner. T.38 defines a protocol for -transmitting a FAX across an IP network in real time. The core T.38 modules implements the basic -message handling for the T.38, real time, FAX over IP (FoIP) protocol. - -The T.38 protocol can operate between: - - Internet-aware FAX terminals, which connect directly to an IP network. The T.38 terminal module - extends this module to provide a complete T.38 terminal. - - FAX gateways, which allow traditional PSTN FAX terminals to communicate through the Internet. - The T.38 gateway module extends this module to provide a T.38 gateway. - - A combination of terminals and gateways. - -T.38 is the only standardised protocol which exists for real-time FoIP. Reliably transporting a -FAX between PSTN FAX terminals, through an IP network, requires use of the T.38 protocol at FAX -gateways. VoIP connections are not robust for modem use, including FAX modem use. Most use low -bit rate codecs, which cannot convey the modem signals accurately. Even when high bit rate -codecs are used, VoIP connections suffer dropouts and timing adjustments, which modems cannot -tolerate. In a LAN environment the dropout rate may be very low, but the timing adjustments which -occur in VoIP connections still make modem operation unreliable. T.38 FAX gateways deal with the -delays, timing jitter, and packet loss experienced in packet networks, and isolate the PSTN FAX -terminals from these as far as possible. In addition, by sending FAXes as image data, rather than -digitised audio, they reduce the required bandwidth of the IP network. - -\section t38_core_page_sec_1 What does it do? - -\section t38_core_page_sec_2 How does it work? - -Timing differences and jitter between two T.38 entities can be a serious problem, if one of those -entities is a PSTN gateway. - -Flow control for non-ECM image data takes advantage of several features of the T.30 specification. -First, an unspecified number of 0xFF octets may be sent at the start of transmission. This means we -can add endless extra 0xFF bytes at this point, without breaking the T.30 spec. In practice, we -cannot add too many, or we will affect the timing tolerance of the T.30 protocol by delaying the -response at the end of each image. Secondly, just before an end of line (EOL) marker we can pad -with zero bits. Again, the number is limited only by need to avoid upsetting the timing of the -step following the non-ECM data. -*/ - -/*! T.38 indicator types */ -enum t30_indicator_types_e -{ - T38_IND_NO_SIGNAL = 0, - T38_IND_CNG, - T38_IND_CED, - T38_IND_V21_PREAMBLE, - T38_IND_V27TER_2400_TRAINING, - T38_IND_V27TER_4800_TRAINING, - T38_IND_V29_7200_TRAINING, - T38_IND_V29_9600_TRAINING, - T38_IND_V17_7200_SHORT_TRAINING, - T38_IND_V17_7200_LONG_TRAINING, - T38_IND_V17_9600_SHORT_TRAINING, - T38_IND_V17_9600_LONG_TRAINING, - T38_IND_V17_12000_SHORT_TRAINING, - T38_IND_V17_12000_LONG_TRAINING, - T38_IND_V17_14400_SHORT_TRAINING, - T38_IND_V17_14400_LONG_TRAINING, - T38_IND_V8_ANSAM, - T38_IND_V8_SIGNAL, - T38_IND_V34_CNTL_CHANNEL_1200, - T38_IND_V34_PRI_CHANNEL, - T38_IND_V34_CC_RETRAIN, - T38_IND_V33_12000_TRAINING, - T38_IND_V33_14400_TRAINING -}; - -/*! T.38 data types */ -enum t38_data_types_e -{ - T38_DATA_NONE = -1, - T38_DATA_V21 = 0, - T38_DATA_V27TER_2400, - T38_DATA_V27TER_4800, - T38_DATA_V29_7200, - T38_DATA_V29_9600, - T38_DATA_V17_7200, - T38_DATA_V17_9600, - T38_DATA_V17_12000, - T38_DATA_V17_14400, - T38_DATA_V8, - T38_DATA_V34_PRI_RATE, - T38_DATA_V34_CC_1200, - T38_DATA_V34_PRI_CH, - T38_DATA_V33_12000, - T38_DATA_V33_14400 -}; - -/*! T.38 data field types */ -enum t38_field_types_e -{ - T38_FIELD_HDLC_DATA = 0, - T38_FIELD_HDLC_SIG_END, - T38_FIELD_HDLC_FCS_OK, - T38_FIELD_HDLC_FCS_BAD, - T38_FIELD_HDLC_FCS_OK_SIG_END, - T38_FIELD_HDLC_FCS_BAD_SIG_END, - T38_FIELD_T4_NON_ECM_DATA, - T38_FIELD_T4_NON_ECM_SIG_END, - T38_FIELD_CM_MESSAGE, - T38_FIELD_JM_MESSAGE, - T38_FIELD_CI_MESSAGE, - T38_FIELD_V34RATE -}; - -/*! T.38 field classes */ -enum t38_field_classes_e -{ - T38_FIELD_CLASS_NONE = 0, - T38_FIELD_CLASS_HDLC, - T38_FIELD_CLASS_NON_ECM -}; - -/*! T.38 message types */ -enum t38_message_types_e -{ - T38_TYPE_OF_MSG_T30_INDICATOR = 0, - T38_TYPE_OF_MSG_T30_DATA -}; - -/*! T.38 transport types */ -enum t38_transport_types_e -{ - T38_TRANSPORT_UDPTL = 0, - T38_TRANSPORT_RTP, - T38_TRANSPORT_TCP, - T38_TRANSPORT_TCP_TPKT -}; - -/*! T.38 TCF management types */ -enum t38_data_rate_management_types_e -{ - T38_DATA_RATE_MANAGEMENT_LOCAL_TCF = 1, - T38_DATA_RATE_MANAGEMENT_TRANSFERRED_TCF = 2 -}; - -/*! T.38 Packet categories used for setting the redundancy level and packet repeat - counts on a packet by packet basis. */ -enum t38_packet_categories_e -{ - /*! \brief Indicator packet */ - T38_PACKET_CATEGORY_INDICATOR = 0, - /*! \brief Control data packet */ - T38_PACKET_CATEGORY_CONTROL_DATA = 1, - /*! \brief Terminating control data packet */ - T38_PACKET_CATEGORY_CONTROL_DATA_END = 2, - /*! \brief Image data packet */ - T38_PACKET_CATEGORY_IMAGE_DATA = 3, - /*! \brief Terminating image data packet */ - T38_PACKET_CATEGORY_IMAGE_DATA_END = 4 -}; - -#define T38_RX_BUF_LEN 2048 -#define T38_TX_BUF_LEN 16384 - -/*! T.38 data field */ -typedef struct -{ - /*! Field type */ - int field_type; - /*! Field contents */ - const uint8_t *field; - /*! Field length */ - int field_len; -} t38_data_field_t; - -/*! - Core T.38 state, common to all modes of T.38. -*/ -typedef struct t38_core_state_s t38_core_state_t; - -typedef int (*t38_tx_packet_handler_t)(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count); - -typedef int (*t38_rx_indicator_handler_t)(t38_core_state_t *s, void *user_data, int indicator); -typedef int (*t38_rx_data_handler_t)(t38_core_state_t *s, void *user_data, int data_type, int field_type, const uint8_t *buf, int len); -typedef int (*t38_rx_missing_handler_t)(t38_core_state_t *s, void *user_data, int rx_seq_no, int expected_seq_no); - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Convert the code for an indicator to a short text name. - \param indicator The type of indicator. - \return A pointer to a short text name for the indicator. */ -SPAN_DECLARE(const char *) t38_indicator_to_str(int indicator); - -/*! \brief Convert the code for a type of data to a short text name. - \param data_type The data type. - \return A pointer to a short text name for the data type. */ -SPAN_DECLARE(const char *) t38_data_type_to_str(int data_type); - -/*! \brief Convert the code for a type of data field to a short text name. - \param field_type The field type. - \return A pointer to a short text name for the field type. */ -SPAN_DECLARE(const char *) t38_field_type_to_str(int field_type); - -/*! \brief Convert the code for a CM profile code to text description. - \param profile The profile code from a CM message. - \return A pointer to a short text description of the profile. */ -SPAN_DECLARE(const char *) t38_cm_profile_to_str(int profile); - -/*! \brief Convert a JM message code to text description. - \param data The data field of the message. - \param len The length of the data field. - \return A pointer to a short text description of the profile. */ -SPAN_DECLARE(const char *) t38_jm_to_str(const uint8_t *data, int len); - -/*! \brief Convert a V34rate message to an actual bit rate. - \param data The data field of the message. - \param len The length of the data field. - \return The bit rate, or -1 for a bad message. */ -SPAN_DECLARE(int) t38_v34rate_to_bps(const uint8_t *data, int len); - -/*! \brief Send an indicator packet - \param s The T.38 context. - \param indicator The indicator to send. - \return The delay to allow after this indicator is sent. */ -SPAN_DECLARE(int) t38_core_send_indicator(t38_core_state_t *s, int indicator); - -/*! \brief Find the delay to allow for HDLC flags after sending an indicator - \param s The T.38 context. - \param indicator The indicator to check. - \return The delay to allow for initial HDLC flags after this indicator is sent. */ -SPAN_DECLARE(int) t38_core_send_flags_delay(t38_core_state_t *s, int indicator); - -/*! \brief Find the delay to allow for modem training after sending an indicator - \param s The T.38 context. - \param indicator The indicator to check. - \return The delay to allow for modem training after this indicator is sent. */ -SPAN_DECLARE(int) t38_core_send_training_delay(t38_core_state_t *s, int indicator); - -/*! \brief Send a data packet - \param s The T.38 context. - \param data_type The packet's data type. - \param field_type The packet's field type. - \param field The message data content for the packet. - \param field_len The length of the message data, in bytes. - \param category The category of the packet being sent. This should be one of the values defined for t38_packet_categories_e. - \return 0 for OK, else -1 */ -SPAN_DECLARE(int) t38_core_send_data(t38_core_state_t *s, int data_type, int field_type, const uint8_t field[], int field_len, int category); - -/*! \brief Send a data packet - \param s The T.38 context. - \param data_type The packet's data type. - \param field The list of fields. - \param fields The number of fields in the list. - \param category The category of the packet being sent. This should be one of the values defined for t38_packet_categories_e. - \return 0 for OK, else -1 */ -SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_type, const t38_data_field_t field[], int fields, int category); - -/*! \brief Process a received T.38 IFP packet from an unreliable packet stream (e.g. UDPTL or RTP). This processing includes - packet sequence number checking, missing packet recovery, and skipping repeat packets. - \param s The T.38 context. - \param buf The packet contents. - \param len The length of the packet contents. - \param seq_no The packet sequence number. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no); - -/*! \brief Process a received T.38 IFP packet from a reliable stream (e.g. TCP). - \param s The T.38 context. - \param buf The packet contents. - \param len The length of the packet contents. - \param seq_no The packet sequence number, used for logging purposes. - \return The length of the packet processed, or -1 if there is an error in the packet, or too few bytes of data to complete it. */ -SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no); - -/*! Set the method to be used for data rate management, as per the T.38 spec. - \param s The T.38 context. - \param method 1 for pass TCF across the T.38 link, 2 for handle TCF locally. -*/ -SPAN_DECLARE(void) t38_set_data_rate_management_method(t38_core_state_t *s, int method); - -/*! Set the data transport protocol. - \param s The T.38 context. - \param data_transport_protocol UDPTL, RTP or TPKT. -*/ -SPAN_DECLARE(void) t38_set_data_transport_protocol(t38_core_state_t *s, int data_transport_protocol); - -/*! 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. -*/ -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. -*/ -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. -*/ -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. - \param max_buffer_size The maximum buffer size. -*/ -SPAN_DECLARE(void) t38_set_max_buffer_size(t38_core_state_t *s, int max_buffer_size); - -/*! Set the maximum size of an IFP packet that is acceptable by the far end. - \param s The T.38 context. - \param max_datagram_size The maximum IFP packet length, in bytes. -*/ -SPAN_DECLARE(void) t38_set_max_datagram_size(t38_core_state_t *s, int max_datagram_size); - -/*! \brief Send a data packet - \param s The T.38 context. - \param category The category of the packet being sent. This should be one of the values defined for t38_packet_categories_e. - \param setting The repeat count for the category. This should be at least one for all categories other an indicator packets. - Zero is valid for indicator packets, as it suppresses the sending of indicator packets, as an application using - TCP for the transport would require. As the setting is passed through to the transmission channel, additional - information may be encoded in it, such as the redundancy depth for the particular packet category. */ -SPAN_DECLARE(void) t38_set_redundancy_control(t38_core_state_t *s, int category, int setting); - -SPAN_DECLARE(void) t38_set_pace_transmission(t38_core_state_t *s, int pace_transmission); - -SPAN_DECLARE(void) t38_set_fastest_image_data_rate(t38_core_state_t *s, int max_rate); - -SPAN_DECLARE(int) t38_get_fastest_image_data_rate(t38_core_state_t *s); - -/*! Set the T.38 version to be emulated. - \param s The T.38 context. - \param t38_version Version number, as in the T.38 spec. -*/ -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 - 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, bool check); - -/*! Set the TEP handling option. - \param s The T.38 context. - \param allow_for_tep True to allow for TEP playout. -*/ -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. - \param s The T.38 context. - \return A pointer to the logging context, or NULL. -*/ -SPAN_DECLARE(logging_state_t *) t38_core_get_logging_state(t38_core_state_t *s); - -/*! Restart a T.38 core context. - \brief Restart a T.38 core context. - \param s The T.38 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_core_restart(t38_core_state_t *s); - -/*! Initialise a T.38 core context. - \brief Initialise a T.38 core context. - \param s The T.38 context. - \param rx_indicator_handler Receive indicator handling routine. - \param rx_data_handler Receive data packet handling routine. - \param rx_rx_missing_handler Missing receive packet handling routine. - \param rx_packet_user_data An opaque pointer passed to the rx packet handling routines. - \param tx_packet_handler Packet transmit handling routine. - \param tx_packet_user_data An opaque pointer passed to the tx_packet_handler. - \return A pointer to the T.38 context, or NULL if there was a problem. */ -SPAN_DECLARE(t38_core_state_t *) t38_core_init(t38_core_state_t *s, - t38_rx_indicator_handler_t rx_indicator_handler, - t38_rx_data_handler_t rx_data_handler, - t38_rx_missing_handler_t rx_missing_handler, - void *rx_user_data, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data); - -/*! Release a signaling tone transmitter context. - \brief Release a signaling tone transmitter context. - \param s The T.38 context. - \return 0 for OK */ -SPAN_DECLARE(int) t38_core_release(t38_core_state_t *s); - -/*! Free a signaling tone transmitter context. - \brief Free a signaling tone transmitter context. - \param s The T.38 context. - \return 0 for OK */ -SPAN_DECLARE(int) t38_core_free(t38_core_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t38_gateway.h b/libs/spandsp/src/spandsp/t38_gateway.h deleted file mode 100644 index c6f4a876f3..0000000000 --- a/libs/spandsp/src/spandsp/t38_gateway.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_gateway.h - A T.38, less the packet exchange part - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2007 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_T38_GATEWAY_H_) -#define _SPANDSP_T38_GATEWAY_H_ - -/*! \page t38_gateway_page T.38 real time FAX over IP PSTN gateway -\section t38_gateway_page_sec_1 What does it do? - -The T.38 gateway facility provides a robust interface between T.38 IP packet streams and -and 8k samples/second audio streams. It provides the buffering and flow control features needed -to maximum the tolerance of jitter and packet loss on the IP network. - -\section t38_gateway_page_sec_2 How does it work? -*/ - -/*! The maximum number of bytes to be zapped, in order to corrupt NSF, - NSS and NSC messages, so the receiver does not recognise them. */ -#define MAX_NSX_SUPPRESSION 10 - -typedef struct t38_gateway_state_s t38_gateway_state_t; - -/*! - T.38 gateway real time frame handler. - \brief T.38 gateway real time frame handler. - \param user_data An opaque pointer. - \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)(void *user_data, - bool incoming, - const uint8_t *msg, - int len); - -/*! - T.38 gateway results. - */ -typedef struct -{ - /*! \brief The current bit rate for image transfer. */ - int bit_rate; - /*! \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; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Initialise a gateway mode T.38 context. - \param s The T.38 context. - \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_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data); - -/*! Release a gateway mode T.38 context. - \brief Release a T.38 context. - \param s The T.38 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_gateway_release(t38_gateway_state_t *s); - -/*! Free a gateway mode T.38 context. - \brief Free a T.38 context. - \param s The T.38 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_gateway_free(t38_gateway_state_t *s); - -/*! Process a block of received FAX audio samples. - \brief Process a block of received FAX audio samples. - \param s The T.38 context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len); - -/*! Apply fake processing when a block of audio samples is missing (e.g due - to packet loss). - \brief Apply fake received audio processing. - \param s The T.38 context. - \param len The number of samples to fake. - \return The number of samples unprocessed. This should only be non-zero if - the software has reached the end of the FAX call. -*/ -SPAN_DECLARE(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len); - -/*! Generate a block of FAX audio samples. - \brief Generate a block of FAX audio samples. - \param s The T.38 context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len); - -/*! 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. -*/ -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. -*/ -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. - \param s The T.38 context. - \param supported_modems Bit field list of the supported modems. -*/ -SPAN_DECLARE(void) t38_gateway_set_supported_modems(t38_gateway_state_t *s, int supported_modems); - -/*! Select whether NSC, NSF, and NSS should be suppressed. It selected, the contents of - these messages are forced to zero for all octets beyond the message type. This makes - them look like manufacturer specific messages, from a manufacturer which does not exist. - \brief Select whether NSC, NSF, and NSS should be suppressed. - \param s The T.38 context. - \param from_t38 A string of bytes to overwrite the header of any NSC, NSF, and NSS - frames passing through the gateway from T.38 the the modem. - \param from_t38_len The length of the overwrite string. - \param from_modem A string of bytes to overwrite the header of any NSC, NSF, and NSS - frames passing through the gateway from the modem to T.38. - \param from_modem_len The length of the overwrite string. -*/ -SPAN_DECLARE(void) t38_gateway_set_nsx_suppression(t38_gateway_state_t *s, - const uint8_t *from_t38, - int from_t38_len, - const uint8_t *from_modem, - int from_modem_len); - -/*! 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. -*/ -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. -*/ -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. - \param s The T.38 context. - \param t A pointer to a buffer for the statistics. */ -SPAN_DECLARE(void) t38_gateway_get_transfer_statistics(t38_gateway_state_t *s, t38_stats_t *t); - -/*! Get a pointer to the T.38 core IFP packet engine associated with a - gateway mode T.38 context. - \brief Get a pointer to the T.38 core IFP packet engine associated - with a T.38 context. - \param s The T.38 context. - \return A pointer to the T.38 core context, or NULL. -*/ -SPAN_DECLARE(t38_core_state_t *) t38_gateway_get_t38_core_state(t38_gateway_state_t *s); - -/*! 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. - \param s The T.38 context. - \return A pointer to the logging context, or NULL. -*/ -SPAN_DECLARE(logging_state_t *) t38_gateway_get_logging_state(t38_gateway_state_t *s); - -/*! Set a callback function for T.30 frame exchange monitoring. This is called from the heart - of the signal processing, so don't take too long in the handler routine. - \brief Set a callback function for T.30 frame exchange monitoring. - \param s The T.30 context. - \param handler The callback function. - \param user_data An opaque pointer passed to the callback function. */ -SPAN_DECLARE(void) t38_gateway_set_real_time_frame_handler(t38_gateway_state_t *s, - t38_gateway_real_time_frame_handler_t handler, - void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h deleted file mode 100644 index a841177d60..0000000000 --- a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_non_ecm_buffer.h - A rate adapting buffer for T.38 non-ECM image - * and TCF data - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2007, 2008 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_T38_NON_ECM_BUFFER_H_) -#define _SPANDSP_T38_NON_ECM_BUFFER_H_ - -/*! \page t38_non_ecm_buffer_page T.38 rate adapting non-ECM image data buffer -\section t38_non_ecm_buffer_page_sec_1 What does it do? - -The T.38 rate adapting non-ECM image data buffer is used to buffer TCF and non-ECM -FAX image data being gatewayed from a T.38 link to an analogue FAX modem link. - -As well as rate adapting, the buffer has the ability to impose a minimum on the number -of bits per row of image data. This allows any row padding zeros to be stripped from -the data stream, to minimise the data sent as T.38 packets, and be reinserted before -the data is sent to its final destination. Not all T.38 implementations support this -feature, so it's use must be negotiated. - -\section t38_non_ecm_buffer_page_sec_2 How does it work? - -When inserting padding bits, whether to ensure a minimum row time or for flow control, -it is important the right value is inserted at the right point in the data sequence. -If we are in the optional initial period of all ones, we can insert a byte of extra -ones at any time. Once we pass that initial stage, TCF and image data need separate -handling. - -TCF data is all zeros. Once the period of all zeros has begun it is OK to insert -additional bytes of zeros at any point. - -Image data consists of rows, separated by EOL (end of line) markers. Inserting -zeros at arbitrary times would corrupt the image. However, it is OK to insert a -considerable number of extra zeros just before an EOL. Therefore we track where the -EOL markers occur as we fill the buffer. As we empty the buffer stop outputting real -data, and start outputting bytes of zero, if we reach this last EOL marker location. -The EOL marker is 11 zeros following by 1 (1D mode) or 2 (2D mode) ones. Therefore, it -always spills across 2 bytes in the buffer, and there is always a point where we can -insert our extra zeros between bytes. - -Padding between the group of successive EOL markers which for the RTC (return to control) -marker that ends an image causes some FAX machines not to recognise them as an RTC condition. -Therefore, our padding applies special protection so padding never occurs between two -successive EOL markers, with no pixel data between them. -*/ - -/*! The buffer length much be a power of two. The chosen length is big enough for - over 9s of data at the V.17 14,400bps rate. */ -#define T38_NON_ECM_TX_BUF_LEN 16384 - -/*! \brief A flow controlled non-ECM image data buffer, for buffering T.38 to analogue - modem data. -*/ -typedef struct t38_non_ecm_buffer_state_s t38_non_ecm_buffer_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Initialise a T.38 rate adapting non-ECM buffer context. - \param s The buffer context. - \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, bool image_mode, int min_row_bits); - -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); - -/*! \brief Set the mode of a T.38 rate adapting non-ECM buffer context. - \param s The buffer context. - \param mode True for image data mode, or false for TCF mode. - \param bits The minimum number of bits per FAX image row. */ -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. - \param buf The data buffer to be injected. - \param len The length of the data to be injected. */ -SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, const uint8_t *buf, int len); - -/*! \brief Inform a T.38 rate adapting non-ECM buffer context that the incoming data has finished, - and the contents of the buffer should be played out as quickly as possible. - \param s The buffer context. */ -SPAN_DECLARE(void) t38_non_ecm_buffer_push(t38_non_ecm_buffer_state_t *s); - -/*! \brief Report the input status of a T.38 rate adapting non-ECM buffer context to the specified - logging context. - \param s The buffer context. - \param logging The logging context. */ -SPAN_DECLARE(void) t38_non_ecm_buffer_report_input_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging); - -/*! \brief Report the output status of a T.38 rate adapting non-ECM buffer context to the specified - logging context. - \param s The buffer context. - \param logging The logging context. */ -SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging); - -/*! \brief Get the next bit of data from a T.38 rate adapting non-ECM buffer context. - \param user_data The buffer context, cast to a void pointer. - \return The next bit, or one of the values indicating a change of modem status. */ -SPAN_DECLARE(int) t38_non_ecm_buffer_get_bit(void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t38_terminal.h b/libs/spandsp/src/spandsp/t38_terminal.h deleted file mode 100644 index 630fbb80bc..0000000000 --- a/libs/spandsp/src/spandsp/t38_terminal.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_terminal.h - T.38 termination, less the packet exchange part - * - * 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. - */ - -/*! \file */ - -#if !defined(_SPANDSP_T38_TERMINAL_H_) -#define _SPANDSP_T38_TERMINAL_H_ - -/*! \page t38_terminal_page T.38 real time FAX over IP termination -\section t38_terminal_page_sec_1 What does it do? - -\section t38_terminal_page_sec_2 How does it work? -*/ - -/* Make sure the HDLC frame buffers are big enough for ECM frames. */ -#define T38_MAX_HDLC_LEN 260 - -enum -{ - /*! This option enables the continuous streaming of FAX data, with no allowance for - FAX machine speeds. This is usually used with TCP/TPKT transmission of T.38 FAXes */ - T38_TERMINAL_OPTION_NO_PACING = 0x01, - /*! This option enables the regular repeat transmission of indicator signals, - during periods when no FAX signal transmission occurs. */ - T38_TERMINAL_OPTION_REGULAR_INDICATORS = 0x02, - /*! This option enables the regular repeat transmission of indicator signals for the - first 2s, during periods when no FAX signal transmission occurs. */ - T38_TERMINAL_OPTION_2S_REPEATING_INDICATORS = 0x04, - /*! This option suppresses the transmission of indicators. This is usually used with - TCP/TPKT transmission of T.38 FAXes */ - T38_TERMINAL_OPTION_NO_INDICATORS = 0x08 -}; - -typedef struct t38_terminal_state_s t38_terminal_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(int) t38_terminal_send_timeout(t38_terminal_state_t *s, int samples); - -/*! Set configuration options. - \brief Set configuration options. - \param s The T.38 context. - \param config A combinations of T38_TERMINAL_OPTION_* bits. -*/ -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. -*/ -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. -*/ -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. - \param s The T.38 context. - \return A pointer to the T.30 context, or NULL. -*/ -SPAN_DECLARE(t30_state_t *) t38_terminal_get_t30_state(t38_terminal_state_t *s); - -/*! Get a pointer to the T.38 core IFP packet engine associated with a - termination mode T.38 context. - \brief Get a pointer to the T.38 core IFP packet engine associated - with a T.38 context. - \param s The T.38 context. - \return A pointer to the T.38 core context, or NULL. -*/ -SPAN_DECLARE(t38_core_state_t *) t38_terminal_get_t38_core_state(t38_terminal_state_t *s); - -/*! 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. - \param s The T.38 context. - \return A pointer to the logging context, or NULL. -*/ -SPAN_DECLARE(logging_state_t *) t38_terminal_get_logging_state(t38_terminal_state_t *s); - -/*! \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 - context is for an answering party. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_terminal_restart(t38_terminal_state_t *s, - 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 - 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, - bool calling_party, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data); - -/*! Release a termination mode T.38 context. - \brief Release a T.38 context. - \param s The T.38 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_terminal_release(t38_terminal_state_t *s); - -/*! Free a a termination mode T.38 context. - \brief Free a T.38 context. - \param s The T.38 context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_terminal_free(t38_terminal_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t42.h b/libs/spandsp/src/spandsp/t42.h deleted file mode 100644 index 26c4b8e299..0000000000 --- a/libs/spandsp/src/spandsp/t42.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t42.h - ITU T.42 JPEG for 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_T42_H_) -#define _SPANDSP_T42_H_ - -/*! \page t42_page T.42 (JPEG for FAX) image compression and decompression - -\section t42_page_sec_1 What does it do? - -\section t42_page_sec_1 How does it work? -*/ - -/*! State of a working instance of the T.42 encoder */ -typedef struct t42_encode_state_s t42_encode_state_t; - -/*! State of a working instance of the T.42 decoder */ -typedef struct t42_decode_state_s t42_decode_state_t; - -typedef struct lab_params_s lab_params_t; - -#if defined(__cplusplus) -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); - -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_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) 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(bool) t42_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len); - -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); - -/*! \brief Check if we are at the end of the current document page. - \param s The T.42 context. - \return 0 for more data to come. SIG_STATUS_END_OF_DATA for no more data. */ -SPAN_DECLARE(int) t42_encode_image_complete(t42_encode_state_t *s); - -SPAN_DECLARE(int) t42_encode_get(t42_encode_state_t *s, uint8_t buf[], size_t max_len); - -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); - -/*! Get the logging context associated with a T.42 encode context. - \brief Get the logging context associated with a T.42 encode context. - \param s The T.42 encode context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t42_encode_get_logging_state(t42_encode_state_t *s); - -/*! \brief Restart a T.42 encode context. - \param s The T.42 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) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width, uint32_t image_length); - -/*! \brief Prepare to encode an image in T.42 format. - \param s The T.42 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(t42_encode_state_t *) t42_encode_init(t42_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.42 encode context. - \param s The T.42 encode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t42_encode_release(t42_encode_state_t *s); - -/*! \brief Free a T.42 encode context. - \param s The T.42 encode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t42_encode_free(t42_encode_state_t *s); - -SPAN_DECLARE(void) t42_decode_rx_status(t42_decode_state_t *s, int status); - -/*! \brief Decode a chunk of T.42 data. - \param s The T.42 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) t42_decode_put(t42_decode_state_t *s, const uint8_t data[], size_t len); - -/*! \brief Set the row handler routine. - \param s The T.42 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) t42_decode_set_row_write_handler(t42_decode_state_t *s, - t4_row_write_handler_t handler, - void *user_data); - -/*! \brief Set the comment handler routine. - \param s The T.42 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) t42_decode_set_comment_handler(t42_decode_state_t *s, - uint32_t max_comment_len, - 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); - -/*! \brief Get the width of the image. - \param s The T.42 context. - \return The width of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t42_decode_get_image_width(t42_decode_state_t *s); - -/*! \brief Get the length of the image. - \param s The T.42 context. - \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. - \brief Get the logging context associated with a T.42 decode context. - \param s The T.42 decode context. - \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. - \param s The T.42 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(t42_decode_state_t *) t42_decode_init(t42_decode_state_t *s, - t4_row_write_handler_t handler, - void *user_data); - -/*! \brief Release a T.42 decode context. - \param s The T.42 decode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t42_decode_release(t42_decode_state_t *s); - -/*! \brief Free a T.42 decode context. - \param s The T.42 decode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t42_decode_free(t42_decode_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t43.h b/libs/spandsp/src/spandsp/t43.h deleted file mode 100644 index ecc0f2a224..0000000000 --- a/libs/spandsp/src/spandsp/t43.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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 deleted file mode 100644 index de6698517e..0000000000 --- a/libs/spandsp/src/spandsp/t4_rx.h +++ /dev/null @@ -1,534 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_rx.h - definitions for T.4 FAX receive processing - * - * 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 */ - -#if !defined(_SPANDSP_T4_RX_H_) -#define _SPANDSP_T4_RX_H_ - -/*! \page t4_page T.4 image compression and decompression - -\section t4_page_sec_1 What does it do? -The T.4 image compression and decompression routines implement the 1D and 2D -encoding methods defined in ITU specification T.4. They also implement the pure -2D encoding method defined in T.6. These are image compression algorithms used -for FAX transmission. - -\section t4_page_sec_1 How does it work? -*/ - -/*! This function is a callback from the image decoders, to write the decoded bi-level image, - row by row. It is called for each row, with len set to the number of bytes per row. At the - end of the image it is called with len set to zero, to indicate the end of image condition. - \return 0 for OK, or non-zero for a problem that requires the image be interrupted. */ -typedef int (*t4_row_write_handler_t)(void *user_data, const uint8_t buf[], size_t len); - -/*! Supported compression modes. */ -typedef enum -{ - /*! No compression */ - T4_COMPRESSION_NONE = 0x01, - /*! T.4 1D compression */ - T4_COMPRESSION_T4_1D = 0x02, - /*! T.4 2D compression */ - T4_COMPRESSION_T4_2D = 0x04, - /*! T.6 2D compression */ - T4_COMPRESSION_T6 = 0x08, - /*! T.85 monochrome JBIG coding with L0 fixed. */ - T4_COMPRESSION_T85 = 0x10, - /*! T.85 monochrome JBIG coding with L0 variable. */ - T4_COMPRESSION_T85_L0 = 0x20, - /*! T.43 gray-scale/colour JBIG coding */ - T4_COMPRESSION_T43 = 0x40, - /*! T.45 run length colour compression */ - T4_COMPRESSION_T45 = 0x80, - /*! T.42 + T.81 + T.30 Annex E colour JPEG coding */ - T4_COMPRESSION_T42_T81 = 0x100, - /*! T.42 + T.81 + T.30 Annex K colour sYCC-JPEG coding */ - 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, - /* 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_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_400 = 15748, - T4_X_RESOLUTION_R16 = 16080, - T4_X_RESOLUTION_600 = 23622, - T4_X_RESOLUTION_1200 = 47244 -} t4_image_x_resolution_t; - -/*! Supported Y resolutions, in pixels per metre. */ -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, - 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: - The A4 widths also apply to North American letter and legal. - 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 - - 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_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_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, - T4_WIDTH_1200_A4 = 10368, - T4_WIDTH_1200_B4 = 12288, - 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 (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 - variety of maximum row counts are used in the real world. It is important not to - set our sending limit too high, or a receiving machine might split pages. It is - important not to set it too low, or we might clip pages. - - 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. 1143 pixels at 3.85/mm is 296.9mm, and an A4 page is 297mm long. -*/ -typedef enum -{ - /* A4 is 297mm long */ - T4_LENGTH_STANDARD_A4 = 1143, - T4_LENGTH_FINE_A4 = 2286, - T4_LENGTH_300_A4 = 4665, - T4_LENGTH_SUPERFINE_A4 = 4573, - T4_LENGTH_600_A4 = 6998, - T4_LENGTH_800_A4 = 9330, - T4_LENGTH_1200_A4 = 13996, - /* 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 = 3300, - T4_LENGTH_SUPERFINE_US_LETTER = 4302, - 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 = 4200, - T4_LENGTH_SUPERFINE_US_LEGAL = 5476, - 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 -{ - /*! More image data is needed */ - T4_DECODE_MORE_DATA = 0, - /*! Image completed successfully */ - T4_DECODE_OK = -1, - /*! The decoder has interrupted */ - T4_DECODE_INTERRUPT = -2, - /*! An abort was found in the image data */ - T4_DECODE_ABORTED = -3, - /*! A memory allocation error occurred */ - T4_DECODE_NOMEM = -4, - /*! The image data is invalid. */ - T4_DECODE_INVALID_DATA = -5 -} t4_decoder_status_t; - -/*! - T.4 FAX compression/decompression descriptor. This defines the working state - for a single instance of a T.4 FAX compression or decompression channel. -*/ -typedef struct t4_rx_state_s t4_rx_state_t; - -/*! - T.4 FAX compression/decompression statistics. -*/ -typedef struct -{ - /*! \brief The number of pages transferred so far. */ - int pages_transferred; - /*! \brief The number of pages in the file (<0 if unknown). */ - int pages_in_file; - /*! \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. */ - int longest_bad_row_run; - /*! \brief The type of image in the file page */ - int image_type; - /*! \brief The horizontal resolution of the file page in pixels per metre */ - int image_x_resolution; - /*! \brief The vertical resolution of the file page in pixels per metre */ - int image_y_resolution; - /*! \brief The number of horizontal pixels in the file page. */ - int image_width; - /*! \brief The number of vertical pixels in the file page. */ - int image_length; - /*! \brief The type of image in the exchanged page */ - int type; - /*! \brief The horizontal resolution of the exchanged page in pixels per metre */ - int x_resolution; - /*! \brief The vertical resolution of the exchanged page in pixels per metre */ - int y_resolution; - /*! \brief The number of horizontal pixels in the exchanged page. */ - int width; - /*! \brief The number of vertical pixels in the exchanged page. */ - int length; - /*! \brief The type of compression used between the FAX machines */ - int compression; - /*! \brief The size of the image on the line, in bytes */ - int line_image_size; -} t4_stats_t; - -#if defined(__cplusplus) -extern "C" { -#endif - -/*! \brief Prepare to receive the next page of the current document. - \param s The T.4 context. - \return zero for success, -1 for failure. */ -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 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 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. - \param s The T.4 receive context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_rx_end_page(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. - \param user_data An opaque pointer passed to the handler routine. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_handler_t handler, void *user_data); - -/*! \brief Set the encoding for the received data. - \param s The T.4 context. - \param encoding The encoding. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding); - -/*! \brief Set the expected width of the received image, in pixel columns. - \param s The T.4 context. - \param width The number of pixels across the image. */ -SPAN_DECLARE(void) t4_rx_set_image_width(t4_rx_state_t *s, int width); - -/*! \brief Set the row-to-row (y) resolution to expect for a received image. - \param s The T.4 context. - \param resolution The resolution, in pixels per metre. */ -SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_rx_state_t *s, int resolution); - -/*! \brief Set the column-to-column (x) resolution to expect for a received image. - \param s The T.4 context. - \param resolution The resolution, in pixels per metre. */ -SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_rx_state_t *s, int resolution); - -/*! \brief Set the DCS information of the fax, for inclusion in the file. - \param s The T.4 context. - \param dcs The DCS information, formatted as an ASCII string. */ -SPAN_DECLARE(void) t4_rx_set_dcs(t4_rx_state_t *s, const char *dcs); - -/*! \brief Set the sub-address of the fax, for inclusion in the file. - \param s The T.4 context. - \param sub_address The sub-address string. */ -SPAN_DECLARE(void) t4_rx_set_sub_address(t4_rx_state_t *s, const char *sub_address); - -/*! \brief Set the identity of the remote machine, for inclusion in the file. - \param s The T.4 context. - \param ident The identity string. */ -SPAN_DECLARE(void) t4_rx_set_far_ident(t4_rx_state_t *s, const char *ident); - -/*! \brief Set the vendor of the remote machine, for inclusion in the file. - \param s The T.4 context. - \param vendor The vendor string, or NULL. */ -SPAN_DECLARE(void) t4_rx_set_vendor(t4_rx_state_t *s, const char *vendor); - -/*! \brief Set the model of the remote machine, for inclusion in the file. - \param s The T.4 context. - \param model The model string, or NULL. */ -SPAN_DECLARE(void) t4_rx_set_model(t4_rx_state_t *s, const char *model); - -/*! Get the current image transfer statistics. - \brief Get the current transfer statistics. - \param s The T.4 context. - \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 a compression format. - \brief Get the short text name of an encoding format. - \param compression The compression type. - \return A pointer to the string. */ -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 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 - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t4_t6_decode.h b/libs/spandsp/src/spandsp/t4_t6_decode.h deleted file mode 100644 index aa50e5ee60..0000000000 --- a/libs/spandsp/src/spandsp/t4_t6_decode.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_t6_decode.h - definitions for T.4/T.6 fax decoding - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2009 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_T4_T6_DECODE_H_) -#define _SPANDSP_T4_T6_DECODE_H_ - -/*! \page t4_t6_decode_page T.4 and T.6 FAX image decompression - -\section t4_t6_decode_page_sec_1 What does it do? -The T.4 image compression and decompression routines implement the 1D and 2D -encoding methods defined in ITU specification T.4. They also implement the pure -2D encoding method defined in T.6. These are image compression algorithms used -for FAX transmission. - -\section t4_t6_decode_page_sec_1 How does it work? -*/ - -typedef struct t4_t6_decode_state_s t4_t6_decode_state_t; - -#if defined(__cplusplus) -extern "C" { -#endif - -/*! \brief Put a bit of the current document page. - \param s The T.4/T.6 context. - \param bit The data bit. - \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. - \param s The T.4/T.6 context. - \param buf The buffer containing the chunk. - \param len The length of the chunk. - \return T4_DECODE_MORE_DATA when the image is still in progress. T4_DECODE_OK when the image is complete. */ -SPAN_DECLARE(int) t4_t6_decode_put(t4_t6_decode_state_t *s, const uint8_t buf[], size_t len); - -/*! \brief Set the row write handler for a T.4/T.6 decode context. - \param s The T.4/T.6 context. - \param handler A pointer to the handler routine. - \param user_data An opaque pointer passed to the handler routine. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_t6_decode_set_row_write_handler(t4_t6_decode_state_t *s, t4_row_write_handler_t handler, void *user_data); - -/*! \brief Set the encoding for the encoded data. - \param s The T.4/T.6 context. - \param encoding The encoding. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_t6_decode_set_encoding(t4_t6_decode_state_t *s, int encoding); - -/*! \brief Get the width of the image. - \param s The T.4/T.6 context. - \return The width of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_width(t4_t6_decode_state_t *s); - -/*! \brief Get the length of the image. - \param s The T.4/T.6 context. - \return The length of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_length(t4_t6_decode_state_t *s); - -/*! \brief Get the size of the compressed image, in bits. - \param s The T.4/T.6 context. - \return The size of the compressed image, in bits. */ -SPAN_DECLARE(int) t4_t6_decode_get_compressed_image_size(t4_t6_decode_state_t *s); - -/*! Get the logging context associated with a T.4 or T.6 decode context. - \brief Get the logging context associated with a T.4 or T.6 decode context. - \param s The T.4/T.6 context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t4_t6_decode_get_logging_state(t4_t6_decode_state_t *s); - -SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width); - -/*! \brief Prepare to decode 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 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_decode_state_t *) t4_t6_decode_init(t4_t6_decode_state_t *s, - int encoding, - int image_width, - t4_row_write_handler_t handler, - void *user_data); - -SPAN_DECLARE(int) t4_t6_decode_release(t4_t6_decode_state_t *s); - -SPAN_DECLARE(int) t4_t6_decode_free(t4_t6_decode_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t4_t6_encode.h b/libs/spandsp/src/spandsp/t4_t6_encode.h deleted file mode 100644 index 81c6ddb3e4..0000000000 --- a/libs/spandsp/src/spandsp/t4_t6_encode.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_t6_encode.h - definitions for T.4/T.6 fax encoding - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2009 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_T4_T6_ENCODE_H_) -#define _SPANDSP_T4_T6_ENCODE_H_ - -typedef struct t4_t6_encode_state_s t4_t6_encode_state_t; - -#if defined(__cplusplus) -extern "C" { -#endif - -/*! \brief Return the next bit of the current document page, without actually - moving forward in the buffer. The document will be padded for the - current minimum scan line time. - \param s The T.4/T.6 context. - \return 0 for more data to come. SIG_STATUS_END_OF_DATA for no more data. */ -SPAN_DECLARE(int) t4_t6_encode_image_complete(t4_t6_encode_state_t *s); - -/*! \brief Get the next bit of the current image. The image will - be padded for the current minimum scan line time. - \param s The T.4/T.6 context. - \return The next bit (i.e. 0 or 1). SIG_STATUS_END_OF_DATA for no more data. */ -SPAN_DECLARE(int) t4_t6_encode_get_bit(t4_t6_encode_state_t *s); - -/*! \brief Get the next chunk of the current document page. The document will - be padded for the current minimum scan line time. - \param s The T.4/T.6 context. - \param buf The buffer into which the chunk is to written. - \param max_len The maximum length of the chunk. - \return The actual length of the chunk. If this is less than max_len it - indicates that the end of the document has been reached. */ -SPAN_DECLARE(int) t4_t6_encode_get(t4_t6_encode_state_t *s, uint8_t buf[], int max_len); - -/*! \brief Set the row read handler for a T.4/T.6 encode context. - \param s The T.4/T.6 context. - \param handler A pointer to the handler routine. - \param user_data An opaque pointer passed to the handler routine. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_t6_encode_set_row_read_handler(t4_t6_encode_state_t *s, - t4_row_read_handler_t handler, - void *user_data); - -/*! \brief Set the encoding for the encoded data. - \param s The T.4/T.6 context. - \param encoding The encoding. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_t6_encode_set_encoding(t4_t6_encode_state_t *s, int encoding); - -/*! \brief Set the width of the image. - \param s The T.4/T.6 context. - \param image_width The image width, in pixels. - \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. */ -SPAN_DECLARE(uint32_t) t4_t6_encode_get_image_width(t4_t6_encode_state_t *s); - -/*! \brief Get the length of the image. - \param s The T.4/T.6 context. - \return The length of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t4_t6_encode_get_image_length(t4_t6_encode_state_t *s); - -/*! \brief Get the size of the compressed image, in bits. - \param s The T.4/T.6 context. - \return The size of the compressed image, in bits. */ -SPAN_DECLARE(int) t4_t6_encode_get_compressed_image_size(t4_t6_encode_state_t *s); - -/*! \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 - time specified by a remote receiving machine. - \param s The T.4/T.6 context. - \param bits The minimum number of bits per row. */ -SPAN_DECLARE(void) t4_t6_encode_set_min_bits_per_row(t4_t6_encode_state_t *s, int bits); - -/*! \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/T.6 context. - \param max The "K" parameter defined in the T.4 specification. This means the value is one - greater than the maximum number of 2D rows between each 1D row. */ -SPAN_DECLARE(void) t4_t6_encode_set_max_2d_rows_per_1d_row(t4_t6_encode_state_t *s, int max); - -/*! Get the logging context associated with a T.4 or T.6 encode context. - \brief Get the logging context associated with a T.4 or T.6 encode context. - \param s The T.4/T.6 context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t4_t6_encode_get_logging_state(t4_t6_encode_state_t *s); - -/*! \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_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, 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_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); - -SPAN_DECLARE(int) t4_t6_encode_release(t4_t6_encode_state_t *s); - -SPAN_DECLARE(int) t4_t6_encode_free(t4_t6_encode_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t4_tx.h b/libs/spandsp/src/spandsp/t4_tx.h deleted file mode 100644 index 2e019e9dc5..0000000000 --- a/libs/spandsp/src/spandsp/t4_tx.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_tx.h - definitions for T.4 FAX transmit processing - * - * 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 */ - -#if !defined(_SPANDSP_T4_TX_H_) -#define _SPANDSP_T4_TX_H_ - -/*! This function is a callback from the image decoders, to read the unencoded bi-level image, - row by row. It is called for each row, with len set to the number of bytes per row expected. - \return len for OK, or zero to indicate the end of the image data. */ -typedef int (*t4_row_read_handler_t)(void *user_data, uint8_t buf[], size_t len); - -/*! - T.4 FAX compression/decompression descriptor. This defines the working state - for a single instance of a T.4 FAX compression or decompression channel. -*/ -typedef struct t4_tx_state_s t4_tx_state_t; - -/* TIFF-FX related extensions to the TIFF tag set */ - -/* -Indexed(346) = 0, 1. SHORT - 0: not a palette-color image. - 1: palette-color image. - This field is used to indicate that each sample value is an index - into an array of color values specified in the image data stream. - Because the color map is embedded in the image data stream, the - ColorMap field is not used in Profile L. Lossless color fax - profile supports palette-color images with the ITULAB encoding. - The SamplesPerPixel value must be 1. - -GlobalParametersIFD (400) IFD/LONG - An IFD containing global parameters. It is recommended that a TIFF - writer place this field in the first IFD, where a TIFF reader would - find it quickly. - - Each field in the GlobalParametersIFD is a TIFF field that is legal - in any IFD. Required baseline fields should not be located in the - GlobalParametersIFD, but should be in each image IFD. If a conflict - exists between fields in the GlobalParametersIFD and in the image - IFDs, then the data in the image IFD shall prevail. - - Among the GlobalParametersIFD entries is a new ProfileType field - which generally describes information in this IFD and in the TIFF - file. - -ProfileType(401) LONG - The type of image data stored in this IFD. - 0 = Unspecified - 1 = Group 3 fax - No default - - The following new global fields are defined in this document as IFD - entries for use with fax applications. - -FaxProfile(402) = 0 - 6. BYTE - The profile that applies to this file; a profile is subset of the - full set of permitted fields and field values of TIFF for facsimile. - The currently defined values are: - 0: does not conform to a profile defined for TIFF for facsimile - 1: minimal black & white lossless, Profile S - 2: extended black & white lossless, Profile F - 3: lossless JBIG black & white, Profile J - 4: lossy color and grayscale, Profile C - 5: lossless color and grayscale, Profile L - 6: Mixed Raster Content, Profile M - -CodingMethods(403) LONG - This field indicates which coding methods are used in the file. A - bit value of 1 indicates which of the following coding methods is - used: - Bit 0: unspecified compression, - Bit 1: 1-dimensional coding, ITU-T Rec. T.4 (MH - Modified Huffman), - Bit 2: 2-dimensional coding, ITU-T Rec. T.4 (MR - Modified Read), - Bit 3: 2-dimensional coding, ITU-T Rec. T.6 (MMR - Modified MR), - Bit 4: ITU-T Rec. T.82 coding, using ITU-T Rec. T.85 (JBIG), - Bit 5: ITU-T Rec. T.81 (Baseline JPEG), - Bit 6: ITU-T Rec. T.82 coding, using ITU-T Rec. T.43 (JBIG color), - Bits 7-31: reserved for future use - Note: There is a limit of 32 compression types to identify standard - compression methods. - -VersionYear(404) BYTE - Count: 4 - The year of the standard specified by the FaxProfile field, given as - 4 characters, e.g. '1997'; used in lossy and lossless color modes. - -ModeNumber (405) BYTE - The mode of the standard specified by the FaxProfile field. A - value of 0 indicates Mode 1.0; used in Mixed Raster Content mode. - -Decode(433) SRATIONAL - Count = 2 * SamplesPerPixel - Describes how to map image sample values into the range of values - appropriate for the current color space. In general, the values - are taken in pairs and specify the minimum and maximum output - value for each color component. For the base color fax profile, - Decode has a count of 6 values and maps the unsigned ITULAB- - encoded sample values (Lsample, asample, bsample) to signed L*a*b* - values, as follows: - L* = Decode[0] + Lsample x (Decode[1]-Decode[0])/(2^n -1) - a* = Decode[2] + asample x (Decode[3]-Decode[2])/(2^n -1) - b* = Decode[4] + bsample x (Decode[5]-Decode[4])/(2^n -1) - where Decode[0], Decode[2] and Decode[4] are the minimum values - for L*, a*, and b*; Decode[1], Decode[3] and Decode[5] are the - maximum values for L*, a*, and b*; and n is the BitsPerSample. - When n=8,=20 L*=Decode[0] when Lsample=0 and L*=Decode[1] when - Lsample=255. - -ImageBaseColor(434) SHORT - Count = SamplesPerPixel - In areas of an image layer where no image data is available (i.e., - where no strips are defined, or where the StripByteCounts entry for - a given strip is 0), the color specified by ImageBaseColor will be - used. - -StripRowCounts(559) LONG - Count = number of strips. - The number of scanlines stored in a strip. Profile M allows each - fax strip to store a different number of scanlines. For strips - with more than one layer, the maximum strip size is either 256 - scanlines or full page size. The 256 maximum SHOULD be used - unless the capability to receive longer strips has been - negotiated. This field replaces RowsPerStrip for IFDs with - variable-size strips. Only one of the two fields, StripRowCounts - and RowsPerStrip, may be used in an IFD. - -ImageLayer(34732) LONG - Count = 2. - Image layers are defined such that layer 1 is the Background - layer, layer 3 is the Foreground layer, and layer 2 is the Mask - layer, which selects pixels from the Background and Foreground - layers. The ImageLayer tag contains two values, which describe - the layer to which the image belongs and the order in which it is - imaged. - - ImageLayer[0] = 1, 2, 3. - 1: Image is a Background image, i.e. the image that will appear - whenever the Mask contains a value of 0. Background images - typically contain low-resolution, continuous-tone imagery. - 2: Image is the Mask layer. In MRC, if the Mask layer is present, - it must be the Primary IFD and be full page in extent. - 3: Image is a Foreground image, i.e. the image that will appear - whenever the Mask contains a value of 1. The Foreground image - generally defines the color of text or lines but may also - contain high-resolution imagery. - - ImageLayer[1]: - 1: first image to be imaged in this layer - 2: second image to be imaged in this layer - 3: ... -*/ - -/* Define the TIFF/FX tags to extend libtiff, when using a version of libtiff where this - 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 -#define TIFFTAG_PROFILETYPE 401 -#define PROFILETYPE_UNSPECIFIED 0 -#define PROFILETYPE_G3_FAX 1 -#define TIFFTAG_FAXPROFILE 402 -#define FAXPROFILE_S 1 -#define FAXPROFILE_F 2 -#define FAXPROFILE_J 3 -#define FAXPROFILE_C 4 -#define FAXPROFILE_L 5 -#define FAXPROFILE_M 6 -#define TIFFTAG_CODINGMETHODS 403 -#define CODINGMETHODS_T4_1D (1 << 1) -#define CODINGMETHODS_T4_2D (1 << 2) -#define CODINGMETHODS_T6 (1 << 3) -#define CODINGMETHODS_T85 (1 << 4) -#define CODINGMETHODS_T42 (1 << 5) -#define CODINGMETHODS_T43 (1 << 6) -#define TIFFTAG_VERSIONYEAR 404 -#define TIFFTAG_MODENUMBER 405 -#define TIFFTAG_DECODE 433 -#define TIFFTAG_IMAGEBASECOLOR 434 -#define TIFFTAG_T82OPTIONS 435 -#define TIFFTAG_STRIPROWCOUNTS 559 -#define TIFFTAG_IMAGELAYER 34732 -#endif - -#if !defined(COMPRESSION_T85) -#define COMPRESSION_T85 9 -#endif -#if !defined(COMPRESSION_T43) -#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 - -#if defined(SPANDSP_SUPPORT_TIFF_FX) -/*! \brief Configure libtiff so it recognises the extended tag set for TIFF-FX. */ -SPAN_DECLARE(void) TIFF_FX_init(void); -#endif - -/*! \brief Prepare to send the next page of the current document. - \param s The T.4 context. - \return zero for success, -1 for failure. */ -SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s); - -/*! \brief Prepare the current page for a resend. - \param s The T.4 context. - \return zero for success, -1 for failure. */ -SPAN_DECLARE(int) t4_tx_restart_page(t4_tx_state_t *s); - -/*! \brief Check for the existance of the next page, and whether its format is like the - current one. This information can be needed before it is determined that the current - page is finished with. - \param s The T.4 context. - \return 0 for next page found with the same format as the current page. - 1 for next page found with different format from the current page. - -1 for no page found, or file failure. */ -SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_tx_state_t *s); - -/*! \brief Complete the sending of a page. - \param s The T.4 context. - \return zero for success, -1 for failure. */ -SPAN_DECLARE(int) t4_tx_end_page(t4_tx_state_t *s); - -/*! \brief Return the next bit of the current document page, without actually - moving forward in the buffer. The document will be padded for the - current minimum scan line time. - \param s The T.4 context. - \return 0 for more data to come. SIG_STATUS_END_OF_DATA for no more data. */ -SPAN_DECLARE(int) t4_tx_image_complete(t4_tx_state_t *s); - -/*! \brief Get the next bit of the current document page. The document will - be padded for the current minimum scan line time. - \param s The T.4 context. - \return The next bit (i.e. 0 or 1). SIG_STATUS_END_OF_DATA for no more data. */ -SPAN_DECLARE(int) t4_tx_get_bit(t4_tx_state_t *s); - -/*! \brief Get the next chunk of the current document page. The document will - be padded for the current minimum scan line time. - \param s The T.4 context. - \param buf The buffer into which the chunk is to written. - \param max_len The maximum length of the chunk. - \return The actual length of the chunk. If this is less than max_len it - 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 Get the compression for the encoded data. - \param s The T.4 context. - \return the chosen compression for success, otherwise -1. */ -SPAN_DECLARE(int) t4_tx_get_tx_compression(t4_tx_state_t *s); - -/*! \brief Get the image type of the encoded data. - \param s The T.4 context. - \return the chosen image type for success, otherwise -1. */ -SPAN_DECLARE(int) t4_tx_get_tx_image_type(t4_tx_state_t *s); - -/*! \brief Get the X and Y resolution code of the current page. - \param s The T.4 context. - \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 - time specified by a remote receiving machine. - \param s The T.4 context. - \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 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. - \param max The maximum number of 2D rows. */ -SPAN_DECLARE(void) t4_tx_set_max_2d_rows_per_1d_row(t4_tx_state_t *s, int max); - -/*! \brief Set the identity of the local machine, for inclusion in page headers. - \param s The T.4 context. - \param ident The identity string. */ -SPAN_DECLARE(void) t4_tx_set_local_ident(t4_tx_state_t *s, const char *ident); - -/*! Set the info field, included in the header line included in each page of an encoded - FAX. This is a string of up to 50 characters. Other information (date, local ident, etc.) - are automatically included in the header. If the header info is set to NULL or a zero - length string, no header lines will be added to the encoded FAX. - \brief Set the header info. - \param s The T.4 context. - \param info A string, of up to 50 bytes, which will form the info field. */ -SPAN_DECLARE(void) t4_tx_set_header_info(t4_tx_state_t *s, const char *info); - -/*! Set the time zone for the time stamp in page header lines. If this function is not used - the current time zone of the program's environment is used. - \brief Set the header timezone. - \param s The T.4 context. - \param tz A time zone descriptor. */ -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 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. - \param handler A pointer to the handler routine. - \param user_data An opaque pointer passed to the handler routine. - \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 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. */ -SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_tx_state_t *s); - -/*! \brief Get the currnet page number in the file. - \param s The T.4 context. - \return The page number, or -1 if there is an error. */ -SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_tx_state_t *s); - -/*! Get the current image transfer statistics. - \brief Get the current transfer statistics. - \param s The T.4 context. - \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 - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t81_t82_arith_coding.h b/libs/spandsp/src/spandsp/t81_t82_arith_coding.h deleted file mode 100644 index e5b4ec4567..0000000000 --- a/libs/spandsp/src/spandsp/t81_t82_arith_coding.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t81_t82_arith_coding.h - ITU T.81 and T.82 QM-coder arithmetic encoding - * and decoding - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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_T81_T82_ARITH_CODING_H_) -#define _SPANDSP_T81_T82_ARITH_CODING_H_ - -/*! \page t81_t82_arith_coding_page T.81 and T.82 QM-coder arithmetic encoding and decoding - -\section t81_t82_arith_coding_page_sec_1 What does it do? -A similar arithmetic coder, called the QM-coder, is used by several image compression -schemes. These routines implement this coder in a (hopefully) reusable way. - -\section t81_t82_arith_coding_page_sec_1 How does it work? -*/ - -/* State of a working instance of the arithmetic encoder */ -typedef struct t81_t82_arith_encode_state_s t81_t82_arith_encode_state_t; - -/* State of a working instance of the arithmetic decoder */ -typedef struct t81_t82_arith_decode_state_s t81_t82_arith_decode_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(t81_t82_arith_encode_state_t *) t81_t82_arith_encode_init(t81_t82_arith_encode_state_t *s, - void (*output_byte_handler)(void *, int), - void *user_data); - -SPAN_DECLARE(int) t81_t82_arith_encode_restart(t81_t82_arith_encode_state_t *s, int reuse_st); - -SPAN_DECLARE(int) t81_t82_arith_encode_release(t81_t82_arith_encode_state_t *s); - -SPAN_DECLARE(int) t81_t82_arith_encode_free(t81_t82_arith_encode_state_t *s); - -SPAN_DECLARE(void) t81_t82_arith_encode(t81_t82_arith_encode_state_t *s, int cx, int pix); - -SPAN_DECLARE(void) t81_t82_arith_encode_flush(t81_t82_arith_encode_state_t *s); - -SPAN_DECLARE(t81_t82_arith_decode_state_t *) t81_t82_arith_decode_init(t81_t82_arith_decode_state_t *s); - -SPAN_DECLARE(int) t81_t82_arith_decode_restart(t81_t82_arith_decode_state_t *s, int reuse_st); - -SPAN_DECLARE(int) t81_t82_arith_decode_release(t81_t82_arith_decode_state_t *s); - -SPAN_DECLARE(int) t81_t82_arith_decode_free(t81_t82_arith_decode_state_t *s); - -SPAN_DECLARE(int) t81_t82_arith_decode(t81_t82_arith_decode_state_t *s, int cx); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t85.h b/libs/spandsp/src/spandsp/t85.h deleted file mode 100644 index c6d6f0b47a..0000000000 --- a/libs/spandsp/src/spandsp/t85.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t85.h - ITU T.85 JBIG for FAX image processing - * - * Written by Steve Underwood - * - * Copyright (C) 2008, 2009 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_T85_H_) -#define _SPANDSP_T85_H_ - -/*! \page t85_page T.85 (JBIG for FAX) image compression and decompression - -\section t85_page_sec_1 What does it do? -The T.85 image compression and decompression routines implement the variant of the -JBIG encoding method defined in ITU specification T.85. This is an image compression -algorithm used for black and white FAX transmission. T.85 defines a subset of the -full JBIG spec (T.82), which only handled a single progressively scanned bit plane. -This results in a great deal of simplification, and results in the ability to -compress or decompress progressively, while only buffering the latest 3 pixel rows -of the image. - -\section t85_page_sec_1 How does it work? -*/ - -/*! Bits in the option byte of the T.82 BIH which are valid for T.85 */ -enum -{ - /*! Enable typical prediction (bottom) */ - T85_TPBON = 0x08, - /*! Variable length image */ - T85_VLENGTH = 0x20, - /*! Lowest-resolution-layer is a two-line template */ - T85_LRLTWO = 0x40 -}; - -/*! State of a working instance of the T.85 encoder */ -typedef struct t85_encode_state_s t85_encode_state_t; - -/*! State of a working instance of the T.85 decoder */ -typedef struct t85_decode_state_s t85_decode_state_t; - -#if defined(__cplusplus) -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. */ -SPAN_DECLARE(int) t85_encode_image_complete(t85_encode_state_t *s); - -/*! \brief Get the next chunk of the current document page. The document will - be padded for the current minimum scan line time. - \param s The T.85 context. - \param buf The buffer into which the chunk is to written. - \param max_len The maximum length of the chunk. - \return The actual length of the chunk. If this is less than max_len it - indicates that the end of the document has been reached. */ -SPAN_DECLARE(int) t85_encode_get(t85_encode_state_t *s, uint8_t buf[], size_t max_len); - -/*! \brief Set the row read handler for a T.85 encode context. - \param s The T.85 context. - \param handler A pointer to the handler routine. - \param user_data An opaque pointer passed to the handler routine. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t85_encode_set_row_read_handler(t85_encode_state_t *s, - t4_row_read_handler_t handler, - void *user_data); - -/*! Get the logging context associated with a T.85 encode context. - \brief Get the logging context associated with a T.85 encode context. - \param s The T.85 encode context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t85_encode_get_logging_state(t85_encode_state_t *s); - -/*! \brief Set the T.85 options - \param s The T.85 context. - \brief l0 ??? - \brief mx ??? - \brief options ???. */ -SPAN_DECLARE(void) t85_encode_set_options(t85_encode_state_t *s, - uint32_t l0, - int mx, - int options); - -/*! \brief Insert a comment in the encoded file. - \param s The T.85 context. - \param comment The comment. Note that this is not a C string, and may contain any bytes. - \param len The length of the comment. */ -SPAN_DECLARE(void) t85_encode_comment(t85_encode_state_t *s, - const uint8_t comment[], - size_t len); - -/*! \brief Set the image width. - \param s The T.85 context. - \param image_width The width of the image. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t85_encode_set_image_width(t85_encode_state_t *s, uint32_t image_width); - -/*! \brief Alter the length of a T.85 encoded image. The new length cannot be greater than the - originally specified length. If the new length is less than the current length it - will be silently adjusted to the current length. Therefore, adjust the length to 1 - will make the currently encoded length the final length. - \param s The T.85 context. - \param image_length The new image length, in pixels. - \return 0 if OK, or -1 if the request was not valid. */ -SPAN_DECLARE(int) t85_encode_set_image_length(t85_encode_state_t *s, uint32_t image_length); - -/*! \brief Get the width of the image. - \param s The T.85 context. - \return The width of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t85_encode_get_image_width(t85_encode_state_t *s); - -/*! \brief Get the length of the image. - \param s The T.85 context. - \return The length of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t85_encode_get_image_length(t85_encode_state_t *s); - -/*! \brief Get the size of the compressed image, in bits. - \param s The T.85 context. - \return The size of the compressed image, in bits. */ -SPAN_DECLARE(int) t85_encode_get_compressed_image_size(t85_encode_state_t *s); - -/*! \brief Stop image encoding prematurely. - \param s The T.85 context. */ -SPAN_DECLARE(void) t85_encode_abort(t85_encode_state_t *s); - -/*! \brief Restart a T.85 encode context. - \param s The T.85 context. - \param image_width The image width, in pixels. - \param image_length The image length, in pixels. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t85_encode_restart(t85_encode_state_t *s, - uint32_t image_width, - uint32_t image_length); - -/*! \brief Prepare to encode an image in T.85 format. - \param s The T.85 context. - \param image_width The image width, in pixels. - \param image_length The 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(t85_encode_state_t *) t85_encode_init(t85_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.85 encode context. - \param s The T.85 encode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t85_encode_release(t85_encode_state_t *s); - -/*! \brief Free a T.85 encode context. - \param s The T.85 encode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t85_encode_free(t85_encode_state_t *s); - -/*! Get the logging context associated with a T.85 decode context. - \brief Get the logging context associated with a T.85 decode context. - \param s The T.85 decode context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t85_decode_get_logging_state(t85_decode_state_t *s); - -/*! \brief Get the width of the image. - \param s The T.85 context. - \return The width of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t85_decode_get_image_width(t85_decode_state_t *s); - -/*! \brief Get the length of the image. - \param s The T.85 context. - \return The length of the image, in pixels. */ -SPAN_DECLARE(uint32_t) t85_decode_get_image_length(t85_decode_state_t *s); - -/*! \brief Get the size of the compressed image, in bits. - \param s The T.85 context. - \return The size of the compressed image, in bits. */ -SPAN_DECLARE(int) t85_decode_get_compressed_image_size(t85_decode_state_t *s); - -SPAN_DECLARE(int) t85_decode_new_plane(t85_decode_state_t *s); - -/*! \brief Set the row handler routine. - \param s The T.85 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) t85_decode_set_row_write_handler(t85_decode_state_t *s, - t4_row_write_handler_t handler, - void *user_data); - -/*! \brief Set the comment handler routine. - \param s The T.85 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) t85_decode_set_comment_handler(t85_decode_state_t *s, - uint32_t max_comment_len, - t4_row_write_handler_t handler, - void *user_data); - -/*! A maliciously constructed T.85 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.85 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) t85_decode_set_image_size_constraints(t85_decode_state_t *s, - uint32_t max_xd, - uint32_t max_yd); - -/*! After the final BIE byte has been delivered to t85_decode_put_xx(), it may still - return T85_MORE_DATA when the T85_VLENGTH option was used, and no NEWLEN - marker section has appeared yet. This is because such a BIE is not - self-terminating (i.e. there could still be a NEWLEN followed by an SDNORM - or SDRST at the very end of the final stripe, which needs to be processed - before the final row is output. See ITU-T Recommendation T.85, Appendix I). - Therefore, after the last byte has been delivered, call this routine to - signal the end of the BIE. This is necessary to allow the routine to finish - processing BIEs with option T85_VLENGTH that do not actually contain any - NEWLEN marker section. - \brief Inform the T.85 decode engine of a status change in the signal source (end - of tx, rx signal change, etc.). - \param s The T.85 context. - \param status The type of status change which occured. */ -SPAN_DECLARE(void) t85_decode_rx_status(t85_decode_state_t *s, int status); - -/*! \brief Decode a chunk of T.85 data. - \param s The T.85 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) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], size_t len); - -SPAN_DECLARE(int) t85_decode_restart(t85_decode_state_t *s); - -/*! \brief Prepare to decode an image in T.85 format. - \param s The T.85 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(t85_decode_state_t *) t85_decode_init(t85_decode_state_t *s, - t4_row_write_handler_t handler, - void *user_data); - -/*! \brief Release a T.85 decode context. - \param s The T.85 decode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t85_decode_release(t85_decode_state_t *s); - -/*! \brief Free a T.85 decode context. - \param s The T.85 decode context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t85_decode_free(t85_decode_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/telephony.h b/libs/spandsp/src/spandsp/telephony.h deleted file mode 100644 index fb338e48e2..0000000000 --- a/libs/spandsp/src/spandsp/telephony.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * telephony.h - some very basic telephony definitions - * - * 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_TELEPHONY_H_) -#define _SPANDSP_TELEPHONY_H_ - -#if defined(_M_IX86) || defined(_M_X64) -#if defined(LIBSPANDSP_EXPORTS) -#define SPAN_DECLARE(type) __declspec(dllexport) type -#define SPAN_DECLARE_DATA __declspec(dllexport) -#else -#define SPAN_DECLARE(type) __declspec(dllimport) type -#define SPAN_DECLARE_DATA __declspec(dllimport) -#endif -#elif defined(SPANDSP_USE_EXPORT_CAPABILITY) && (defined(__GNUC__) || defined(__SUNCC__)) -#define SPAN_DECLARE(type) __attribute__((visibility("default"))) type -#define SPAN_DECLARE_DATA __attribute__((visibility("default"))) -#else -#define SPAN_DECLARE(type) /**/ type -#define SPAN_DECLARE_DATA /**/ -#endif - -#define span_container_of(ptr, type, member) ({ \ - const typeof(((type *) 0)->member) *__mptr = (ptr); \ - (type *) ((char *) __mptr - offsetof(type, member));}) - -#define SAMPLE_RATE 8000 - -/* This is based on A-law, but u-law is only 0.03dB different */ -#define DBM0_MAX_POWER (3.14f + 3.02f) -#define DBM0_MAX_SINE_POWER (3.14f) -/* This is based on the ITU definition of dbOv in G.100.1 */ -#define DBOV_MAX_POWER (0.0f) -#define DBOV_MAX_SINE_POWER (-3.02f) - -/*! \brief A handler for pure receive. The buffer cannot be altered. */ -typedef int (*span_rx_handler_t)(void *s, const int16_t amp[], int len); - -/*! \brief A handler for receive, where the buffer can be altered. */ -typedef int (*span_mod_handler_t)(void *s, int16_t amp[], int len); - -/*! \brief A handler for missing receive data fill-in. */ -typedef int (*span_rx_fillin_handler_t)(void *s, int len); - -/*! \brief A handler for transmit, where the buffer will be filled. */ -typedef int (*span_tx_handler_t)(void *s, int16_t amp[], int max_len); - -#define seconds_to_samples(t) ((t)*SAMPLE_RATE) -#define milliseconds_to_samples(t) ((t)*(SAMPLE_RATE/1000)) -#define microseconds_to_samples(t) ((t)/(1000000/SAMPLE_RATE)) - -#define ms_to_samples(t) ((t)*(SAMPLE_RATE/1000)) -#define us_to_samples(t) ((t)/(1000000/SAMPLE_RATE)) - -/* Fixed point constant macros for 16 bit values */ -#define FP_Q16_0(x) ((int16_t) (1.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q15_1(x) ((int16_t) (2.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q14_2(x) ((int16_t) (4.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q13_3(x) ((int16_t) (8.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q12_4(x) ((int16_t) (16.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q11_5(x) ((int16_t) (32.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q10_6(x) ((int16_t) (64.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q9_7(x) ((int16_t) (128.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q8_8(x) ((int16_t) (256.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q7_9(x) ((int16_t) (512.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q6_10(x) ((int16_t) (1024.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q5_11(x) ((int16_t) (2048.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q4_12(x) ((int16_t) (4096.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q3_13(x) ((int16_t) (8192.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q2_14(x) ((int16_t) (16384.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q1_15(x) ((int16_t) (32768.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) - -/* Fixed point constant macros for 32 bit values */ -#define FP_Q32_0(x) ((int32_t) (1.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q31_1(x) ((int32_t) (2.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q30_2(x) ((int32_t) (4.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q29_3(x) ((int32_t) (8.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q28_4(x) ((int32_t) (16.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q27_5(x) ((int32_t) (32.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q26_6(x) ((int32_t) (64.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q25_7(x) ((int32_t) (128.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q24_8(x) ((int32_t) (256.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q23_9(x) ((int32_t) (512.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q22_10(x) ((int32_t) (1024.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q21_11(x) ((int32_t) (2048.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q20_12(x) ((int32_t) (4096.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q19_13(x) ((int32_t) (8192.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q18_14(x) ((int32_t) (16384.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q17_15(x) ((int32_t) (32768.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q16_16(x) ((int32_t) (65536.0*1.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q15_17(x) ((int32_t) (65536.0*2.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q14_18(x) ((int32_t) (65536.0*4.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q13_19(x) ((int32_t) (65536.0*8.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q12_20(x) ((int32_t) (65536.0*16.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q11_21(x) ((int32_t) (65536.0*32.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q10_22(x) ((int32_t) (65536.0*64.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q9_23(x) ((int32_t) (65536.0*128.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q8_24(x) ((int32_t) (65536.0*256.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q7_25(x) ((int32_t) (65536.0*512.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q6_26(x) ((int32_t) (65536.0*1024.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q5_27(x) ((int32_t) (65536.0*2048.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q4_28(x) ((int32_t) (65536.0*4096.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q3_29(x) ((int32_t) (65536.0*8192.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q2_30(x) ((int32_t) (65536.0*16384.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) -#define FP_Q1_31(x) ((int32_t) (65536.0*32768.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5))) - -#if defined(__cplusplus) -/* C++ doesn't seem to have sane rounding functions/macros yet */ -#if !defined(WIN32) -#define lrint(x) ((long int) (x)) -#define lrintf(x) ((long int) (x)) -#endif -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/time_scale.h b/libs/spandsp/src/spandsp/time_scale.h deleted file mode 100644 index 35e8e00fe7..0000000000 --- a/libs/spandsp/src/spandsp/time_scale.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * time_scale.h - Time scaling for linear speech data - * - * 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. - */ - -#if !defined(_SPANDSP_TIME_SCALE_H_) -#define _SPANDSP_TIME_SCALE_H_ - -/*! \page time_scale_page Time scaling speech -\section time_scale_page_sec_1 What does it do? -The time scaling module allows speech files to be played back at a -different speed from the speed at which they were recorded. If this -were done by simply speeding up or slowing down replay, the pitch of -the voice would change, and sound very odd. This module keeps the pitch -of the voice at its original level. - -The speed of the voice may be altered over a wide range. However, the practical -useful rates are between about half normal speed and twice normal speed. - -\section time_scale_page_sec_2 How does it work? -The time scaling module is based on the Pointer Interval Controlled -OverLap and Add (PICOLA) method, developed by Morita Naotaka. -Mikio Ikeda has an excellent web page on this subject at -http://keizai.yokkaichi-u.ac.jp/~ikeda/research/picola.html -There is also working code there. This implementation uses -exactly the same algorithms, but the code is a complete rewrite. -Mikio's code batch processes files. This version works incrementally -on streams, and allows multiple streams to be processed concurrently. - -\section time_scale_page_sec_3 How do I used it? -The output buffer must be big enough to hold the maximum number of samples which -could result from the data in the input buffer, which is: - - input_len*playout_rate + sample_rate/TIME_SCALE_MIN_PITCH + 1 -*/ - -/*! Audio time scaling descriptor. */ -typedef struct time_scale_state_s time_scale_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Change the time scale rate. - \brief Change the time scale rate. - \param s The time scale context. - \param playout_rate The ratio between the output speed and the input speed. - \return 0 if changed OK, else -1. */ -SPAN_DECLARE(int) time_scale_rate(time_scale_state_t *s, float playout_rate); - -/*! Find the maximum possible samples which could result from scaling the specified - number of input samples, at the current playback rate. - \brief Find the maximum possible output samples. - \param s The time scale context. - \param input_len The number of input samples. - \return The maximum possible output samples. */ -SPAN_DECLARE(int) time_scale_max_output_len(time_scale_state_t *s, int input_len); - -/*! Time scale a chunk of audio samples. - \brief Time scale a chunk of audio samples. - \param s The time scale context. - \param out The output audio sample buffer. This must be large enough to accept - the longest possible result from processing the input data. See the - algorithm documentation for how the longest possible result may be calculated. - \param in The input audio sample buffer. - \param len The number of input samples. - \return The number of output samples. -*/ -SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], int len); - -SPAN_DECLARE(int) time_scale_flush(time_scale_state_t *s, int16_t out[]); - -/*! Initialise a time scale context. This must be called before the first - use of the context, to initialise its contents. - \brief Initialise a time scale context. - \param s The time scale context. - \param sample_rate The sample rate of the signal. - \param playout_rate The ratio between the output speed and the input speed. - \return A pointer to the context, or NULL if there was a problem. */ -SPAN_DECLARE(time_scale_state_t *) time_scale_init(time_scale_state_t *s, int sample_rate, float playout_rate); - -/*! \brief Release a time scale context. - \param s The time scale context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) time_scale_release(time_scale_state_t *s); - -/*! \brief Free a time scale context. - \param s The time scale context. - \return 0 for OK, else -1. */ -SPAN_DECLARE(int) time_scale_free(time_scale_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/timezone.h b/libs/spandsp/src/spandsp/timezone.h deleted file mode 100644 index 923f5e0d35..0000000000 --- a/libs/spandsp/src/spandsp/timezone.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * timezone.h - Timezone handling for time interpretation - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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_TIMEZONE_H_) -#define _SPANDSP_TIMEZONE_H_ - -/*! \page timezone_page Timezone handling - -\section timezone_sec_1 What does it do? - -\section timezone_sec_2 How does it work? - -*/ - -typedef struct tz_s tz_t; - -enum -{ - TM_SUNDAY = 0, - TM_MONDAY, - TM_TUESDAY, - TM_WEDNESDAY, - TM_THURSDAY, - TM_FRIDAY, - TM_SATURDAY -}; - -enum -{ - TM_JANUARY = 0, - TM_FEBRUARY, - TM_MARCH, - TM_APRIL, - TM_MAY, - TM_JUNE, - TM_JULY, - TM_AUGUST, - TM_SEPTEMBER, - TM_OCTOBER, - TM_NOVEMBER, - TM_DECEMBER -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring); - -SPAN_DECLARE(int) tz_release(tz_t *tz); - -SPAN_DECLARE(int) tz_free(tz_t *tz); - -SPAN_DECLARE(int) tz_localtime(tz_t *tz, struct tm *tm, time_t t); - -SPAN_DECLARE(const char *) tz_tzname(tz_t *tz, int isdst); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/timing.h b/libs/spandsp/src/spandsp/timing.h deleted file mode 100644 index 01e7c99146..0000000000 --- a/libs/spandsp/src/spandsp/timing.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * timing.h - Provide access to the Pentium/Athlon TSC timer register - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_TIMING_H_) -#define _SPANDSP_TIMING_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined(__MSVC__) -__declspec(naked) unsigned __int64 __cdecl rdtscll(void) -{ - __asm - { - rdtsc - ret ; return value at EDX:EAX - } -} -/*- End of function --------------------------------------------------------*/ -#elif defined(__GNUC__) -#if defined(__i386__) -static __inline__ uint64_t rdtscll(void) -{ - uint64_t now; - - __asm__ __volatile__(" rdtsc\n" : "=A" (now)); - return now; -} -/*- End of function --------------------------------------------------------*/ -#elif defined(__x86_64__) -static __inline__ uint64_t rdtscll(void) -{ - uint32_t a; - uint32_t d; - - /* For x86_64 we need to merge the result in 2 32 bit registers - into one clean 64 bit result. */ - __asm__ __volatile__(" rdtsc\n" : "=a" (a), "=d" (d)); - return ((uint64_t) a) | (((uint64_t) d) << 32); -} -/*- End of function --------------------------------------------------------*/ -#else -static __inline__ uint64_t rdtscll(void) -{ - /* This architecture doesn't have a suitable timer */ - return 0llu; -} -/*- End of function --------------------------------------------------------*/ -#endif -#endif - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/tone_detect.h b/libs/spandsp/src/spandsp/tone_detect.h deleted file mode 100644 index 7df69468bf..0000000000 --- a/libs/spandsp/src/spandsp/tone_detect.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tone_detect.h - General telephony tone detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 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_TONE_DETECT_H_) -#define _SPANDSP_TONE_DETECT_H_ - -/*! - Goertzel filter descriptor. -*/ -struct goertzel_descriptor_s -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t fac; -#else - float fac; -#endif - int samples; -}; - -/*! - Goertzel filter state descriptor. -*/ -struct goertzel_state_s -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t v2; - int16_t v3; - int16_t fac; -#else - float v2; - float v3; - float fac; -#endif - int samples; - int current_sample; -}; - -/*! - Goertzel filter descriptor. -*/ -typedef struct goertzel_descriptor_s goertzel_descriptor_t; - -/*! - Goertzel filter state descriptor. -*/ -typedef struct goertzel_state_s goertzel_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! \brief Create a descriptor for use with either a Goertzel transform */ -SPAN_DECLARE(void) make_goertzel_descriptor(goertzel_descriptor_t *t, - float freq, - int samples); - -/*! \brief Initialise the state of a Goertzel transform. - \param s The Goertzel context. If NULL, a context is allocated. - \param t The Goertzel descriptor. - \return A pointer to the Goertzel state. */ -SPAN_DECLARE(goertzel_state_t *) goertzel_init(goertzel_state_t *s, - goertzel_descriptor_t *t); - -SPAN_DECLARE(int) goertzel_release(goertzel_state_t *s); - -SPAN_DECLARE(int) goertzel_free(goertzel_state_t *s); - -/*! \brief Reset the state of a Goertzel transform. - \param s The Goertzel context. */ -SPAN_DECLARE(void) goertzel_reset(goertzel_state_t *s); - -/*! \brief Update the state of a Goertzel transform. - \param s The Goertzel context. - \param amp The samples to be transformed. - \param samples The number of samples. - \return The number of samples unprocessed */ -SPAN_DECLARE(int) goertzel_update(goertzel_state_t *s, - const int16_t amp[], - int samples); - -/*! \brief Evaluate the final result of a Goertzel transform. - \param s The Goertzel context. - \return The result of the transform. The expected result for a pure sine wave - signal of level x dBm0, at the very centre of the bin is: - [Floating point] ((samples_per_goertzel_block*32768.0/1.4142)*10^((x - DBM0_MAX_SINE_POWER)/20.0))^2 - [Fixed point] ((samples_per_goertzel_block*256.0/1.4142)*10^((x - DBM0_MAX_SINE_POWER)/20.0))^2 */ -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int32_t) goertzel_result(goertzel_state_t *s); -#else -SPAN_DECLARE(float) goertzel_result(goertzel_state_t *s); -#endif - -/*! \brief Update the state of a Goertzel transform. - \param s The Goertzel context. - \param amp The sample to be transformed. */ -static __inline__ void goertzel_sample(goertzel_state_t *s, int16_t amp) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t x; - int16_t v1; -#else - float v1; -#endif - - v1 = s->v2; - s->v2 = s->v3; -#if defined(SPANDSP_USE_FIXED_POINT) - x = (((int32_t) s->fac*s->v2) >> 14); - /* Scale down the input signal to avoid overflows. 9 bits is enough to - monitor the signals of interest with adequate dynamic range and - resolution. In telephony we generally only start with 13 or 14 bits, - anyway. */ - s->v3 = x - v1 + (amp >> 7); -#else - s->v3 = s->fac*s->v2 - v1 + amp; -#endif - s->current_sample++; -} -/*- End of function --------------------------------------------------------*/ - -/* Scale down the input signal to avoid overflows. 9 bits is enough to - monitor the signals of interest with adequate dynamic range and - resolution. In telephony we generally only start with 13 or 14 bits, - anyway. This is sufficient for the longest Goertzel we currently use. */ -#if defined(SPANDSP_USE_FIXED_POINT) -#define goertzel_preadjust_amp(amp) (((int16_t) amp) >> 7) -#else -#define goertzel_preadjust_amp(amp) ((float) amp) -#endif - -/* Minimal update the state of a Goertzel transform. This is similar to - goertzel_sample, but more suited to blocks of Goertzels. It assumes - the amplitude is pre-shifted, and does not update the per-state sample - count. - \brief Update the state of a Goertzel transform. - \param s The Goertzel context. - \param amp The adjusted sample to be transformed. */ -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ void goertzel_samplex(goertzel_state_t *s, int16_t amp) -#else -static __inline__ void goertzel_samplex(goertzel_state_t *s, float amp) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t x; - int16_t v1; -#else - float v1; -#endif - - v1 = s->v2; - s->v2 = s->v3; -#if defined(SPANDSP_USE_FIXED_POINT) - x = (((int32_t) s->fac*s->v2) >> 14); - s->v3 = x - v1 + amp; -#else - s->v3 = s->fac*s->v2 - v1 + amp; -#endif -} -/*- End of function --------------------------------------------------------*/ - -/*! Generate a Hamming weighted coefficient set, to be used for a periodogram analysis. - \param coeffs The generated coefficients. - \param freq The frequency to be matched by the periodogram, in Hz. - \param sample_rate The sample rate of the signal, in samples per second. - \param window_len The length of the periodogram window. This must be an even number. - \return The number of generated coefficients. -*/ -SPAN_DECLARE(int) periodogram_generate_coeffs(complexf_t coeffs[], float freq, int sample_rate, int window_len); - -/*! Generate the phase offset to be expected between successive periodograms evaluated at the - specified interval. - \param offset A point to the generated phase offset. - \param freq The frequency being matched by the periodogram, in Hz. - \param sample_rate The sample rate of the signal, in samples per second. - \param interval The interval between periodograms, in samples. - \return The scaling factor. -*/ -SPAN_DECLARE(float) periodogram_generate_phase_offset(complexf_t *offset, float freq, int sample_rate, int interval); - -/*! Evaluate a periodogram. - \param coeffs A set of coefficients generated by periodogram_generate_coeffs(). - \param amp The complex amplitude of the signal. - \param len The length of the periodogram, in samples. This must be an even number. - \return The periodogram result. -*/ -SPAN_DECLARE(complexf_t) periodogram(const complexf_t coeffs[], const complexf_t amp[], int len); - -/*! Prepare data for evaluating a set of periodograms. - \param sum A vector of sums of pairs of signal samples. This will be half the length of len. - \param diff A vector of differences between pairs of signal samples. This will be half the length of len. - \param amp The complex amplitude of the signal. - \param len The length of the periodogram, in samples. This must be an even number. - \return The length of the vectors sum and diff. -*/ -SPAN_DECLARE(int) periodogram_prepare(complexf_t sum[], complexf_t diff[], const complexf_t amp[], int len); - -/*! Evaluate a periodogram, based on data prepared by periodogram_prepare(). This is more efficient - than using periodogram() when several periodograms are to be applied to the same signal. - \param coeffs A set of coefficients generated by periodogram_generate_coeffs(). - \param sum A vector of sums produced by periodogram_prepare(). - \param diff A vector of differences produced by periodogram_prepare(). - \param len The length of the periodogram, in samples. This must be an even number. - \return The periodogram result. -*/ -SPAN_DECLARE(complexf_t) periodogram_apply(const complexf_t coeffs[], const complexf_t sum[], const complexf_t diff[], int len); - -/*! Apply a phase offset, to find the frequency error between periodogram evaluations. - specified interval. - \param phase_offset A point to the expected phase offset. - \param scale The scaling factor to be used. - \param last_result A pointer to the previous periodogram result. - \param result A pointer to the current periodogram result. - \return The frequency error, in Hz. -*/ -SPAN_DECLARE(float) periodogram_freq_error(const complexf_t *phase_offset, float scale, const complexf_t *last_result, const complexf_t *result); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/tone_generate.h b/libs/spandsp/src/spandsp/tone_generate.h deleted file mode 100644 index a3d1b5a893..0000000000 --- a/libs/spandsp/src/spandsp/tone_generate.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tone_generate.h - General telephony tone generation. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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_TONE_GENERATE_H_) -#define _SPANDSP_TONE_GENERATE_H_ - -/*! \page tone_generation_page Tone generation -\section tone_generation_page_sec_1 What does it do? -The tone generation module provides for the generation of cadenced tones, -suitable for a wide range of telephony applications. - -\section tone_generation_page_sec_2 How does it work? -Oscillators are a problem. They oscillate due to instability, and yet we need -them to behave in a stable manner. A look around the web will reveal many papers -on this subject. Many describe rather complex solutions to the problem. However, -we are only concerned with telephony applications. It is possible to generate -the tones we need with a very simple efficient scheme. It is also practical to -use an exhaustive test to prove the oscillator is stable under all the -conditions in which we will use it. -*/ - -typedef struct tone_gen_tone_descriptor_s tone_gen_tone_descriptor_t; - -/*! - Cadenced multi-tone generator descriptor. -*/ -typedef struct tone_gen_descriptor_s tone_gen_descriptor_t; - -/*! - Cadenced multi-tone generator state descriptor. This defines the state of - a single working instance of a generator. -*/ -typedef struct tone_gen_state_s tone_gen_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Create a tone generator descriptor - \brief Create a tone generator descriptor - \param s The descriptor - \param f1 The first frequency, in Hz - \param l1 The level of the first frequency, in dBm0 - \param f2 0 for no second frequency, a positive number for the second frequency, - in Hz, or a negative number for an AM modulation frequency, in Hz - \param l2 The level of the second frequency, in dBm0, or the percentage modulation depth - for an AM modulated tone. - \param d1 x - \param d2 x - \param d3 x - \param d4 x - \param repeat x */ -SPAN_DECLARE(tone_gen_descriptor_t *) tone_gen_descriptor_init(tone_gen_descriptor_t *s, - int f1, - int l1, - int f2, - int l2, - int d1, - int d2, - int d3, - int d4, - int repeat); - -SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s); - -SPAN_DECLARE(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples); - -SPAN_DECLARE(tone_gen_state_t *) tone_gen_init(tone_gen_state_t *s, tone_gen_descriptor_t *t); - -SPAN_DECLARE(int) tone_gen_release(tone_gen_state_t *s); - -SPAN_DECLARE(int) tone_gen_free(tone_gen_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v17rx.h b/libs/spandsp/src/spandsp/v17rx.h deleted file mode 100644 index 8f6c34993d..0000000000 --- a/libs/spandsp/src/spandsp/v17rx.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v17rx.h - ITU V.17 modem receive part - * - * 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 */ - -#if !defined(_SPANDSP_V17RX_H_) -#define _SPANDSP_V17RX_H_ - -/*! \page v17rx_page The V.17 receiver -\section v17rx_page_sec_1 What does it do? -The V.17 receiver implements the receive side of a V.17 modem. This can operate -at data rates of 14400, 12000, 9600 and 7200 bits/second. The audio input is a stream -of 16 bit samples, at 8000 samples/second. The transmit and receive side of V.17 -modems operate independantly. V.17 is mostly used for FAX transmission over PSTN -lines, where it provides the standard 14400 bits/second rate. - -\section v17rx_page_sec_2 How does it work? -V.17 uses QAM modulation, at 2400 baud, and trellis coding. Constellations with -16, 32, 64, and 128 points are defined. After one bit per baud is absorbed by the -trellis coding, this gives usable bit rates of 7200, 9600, 12000, and 14400 per -second. - -V.17 specifies a training sequence at the start of transmission, which makes the -design of a V.17 receiver relatively straightforward. The first stage of the -training sequence consists of 256 -symbols, alternating between two constellation positions. The receiver monitors -the signal power, to sense the possible presence of a valid carrier. When the -alternating signal begins, the power rising above a minimum threshold (-43dBm0) -causes the main receiver computation to begin. The initial measured power is -used to quickly set the gain of the receiver. After this initial settling, the -front end gain is locked, and the adaptive equalizer tracks any subsequent -signal level variation. The signal is oversampled to 24000 samples/second (i.e. -signal, zero, zero, signal, zero, zero, ...) and fed to a complex root raised -cosine pulse shaping filter. This filter has been modified from the conventional -root raised cosine filter, by shifting it up the band, to be centred at the nominal -carrier frequency. This filter interpolates the samples, pulse shapes, and performs -a fractional sample delay at the same time. 192 sets of filter coefficients are used -to achieve a set of finely spaces fractional sample delays, between zero and -one sample. By choosing every fifth sample, and the appropriate set of filter -coefficients, the properly tuned symbol tracker can select data samples at 4800 -samples/second from points within 0.28 degrees of the centre and mid-points of -each symbol. The output of the filter is multiplied by a complex carrier, generated -by a DDS. The result is a baseband signal, requiring no further filtering, apart from -an adaptive equalizer. The baseband signal is fed to a T/2 adaptive equalizer. -A band edge component maximisation algorithm is used to tune the sampling, so the samples -fed to the equalizer are close to the mid point and edges of each symbol. Initially -the algorithm is very lightly damped, to ensure the symbol alignment pulls in -quickly. Because the sampling rate will not be precisely the same as the -transmitter's (the spec. says the symbol timing should be within 0.01%), the -receiver constantly evaluates and corrects this sampling throughout its -operation. During the symbol timing maintainence phase, the algorithm uses -a heavier damping. - -The carrier is specified as 1800Hz +- 1Hz at the transmitter, and 1800 +-7Hz at -the receiver. The receive carrier would only be this inaccurate if the link -includes FDM sections. These are being phased out, but the design must still -allow for the worst case. Using an initial 1800Hz signal for demodulation gives -a worst case rotation rate for the constellation of about one degree per symbol. -Once the symbol timing synchronisation algorithm has been given time to lock to the -symbol timing of the initial alternating pattern, the phase of the demodulated signal -is recorded on two successive symbols - once for each of the constellation positions. -The receiver then tracks the symbol alternations, until a large phase jump occurs. -This signifies the start of the next phase of the training sequence. At this -point the total phase shift between the original recorded symbol phase, and the -symbol phase just before the phase jump occurred is used to provide a coarse -estimation of the rotation rate of the constellation, and it current absolute -angle of rotation. These are used to update the current carrier phase and phase -update rate in the carrier DDS. The working data already in the pulse shaping -filter and equalizer buffers is given a similar step rotation to pull it all -into line. From this point on, a heavily damped integrate and dump approach, -based on the angular difference between each received constellation position and -its expected position, is sufficient to track the carrier, and maintain phase -alignment. A fast rough approximator for the arc-tangent function is adequate -for the estimation of the angular error. - -The next phase of the training sequence is a scrambled sequence of two -particular symbols. We train the T/2 adaptive equalizer using this sequence. The -scrambling makes the signal sufficiently diverse to ensure the equalizer -converges to the proper generalised solution. At the end of this sequence, the -equalizer should be sufficiently well adapted that is can correctly resolve the -full QAM constellation. However, the equalizer continues to adapt throughout -operation of the modem, fine tuning on the more complex data patterns of the -full QAM constellation. - -In the last phase of the training sequence, the modem enters normal data -operation, with a short defined period of all ones as data. As in most high -speed modems, data in a V.17 modem passes through a scrambler, to whiten the -spectrum of the signal. The transmitter should initialise its data scrambler, -and pass the ones through it. At the end of the ones, real data begins to pass -through the scrambler, and the transmit modem is in normal operation. The -receiver tests that ones are really received, in order to verify the modem -trained correctly. If all is well, the data following the ones is fed to the -application, and the receive modem is up and running. Unfortunately, some -transmit side of some real V.17 modems fail to initialise their scrambler before -sending the ones. This means the first 23 received bits (the length of the -scrambler register) cannot be trusted for the test. The receive modem, -therefore, only tests that bits starting at bit 24 are really ones. - -The V.17 signal is trellis coded. Two bits of each symbol are convolutionally coded -to form a 3 bit trellis code - the two original bits, plus an extra redundant bit. It -is possible to ignore the trellis coding, and just decode the non-redundant bits. -However, the noise performance of the receiver would suffer. Using a proper -trellis decoder adds several dB to the noise tolerance to the receiving modem. Trellis -coding seems quite complex at first sight, but is fairly straightforward once you -get to grips with it. - -Trellis decoding tracks the data in terms of the possible states of the convolutional -coder at the transmitter. There are 8 possible states of the V.17 coder. The first -step in trellis decoding is to find the best candidate constellation point -for each of these 8 states. One of thse will be our final answer. The constellation -has been designed so groups of 8 are spread fairly evenly across it. Locating them -is achieved is a reasonably fast manner, by looking up the answers in a set of space -map tables. The disadvantage is the tables are potentially large enough to affect -cache performance. The trellis decoder works over 16 successive symbols. The result -of decoding is not known until 16 symbols after the data enters the decoder. The -minimum total accumulated mismatch between each received point and the actual -constellation (termed the distance) is assessed for each of the 8 states. A little -analysis of the coder shows that each of the 8 current states could be arrived at -from 4 different previous states, through 4 different constellation bit patterns. -For each new state, the running total distance is arrived at by inspecting a previous -total plus a new distance for the appropriate 4 previous states. The minimum of the 4 -values becomes the new distance for the state. Clearly, a mechanism is needed to stop -this distance from growing indefinitely. A sliding window, and several other schemes -are possible. However, a simple single pole IIR is very simple, and provides adequate -results. - -For each new state we store the constellation bit pattern, or path, to that state, and -the number of the previous state. We find the minimum distance amongst the 8 new -states for each new symbol. We then trace back through the states, until we reach the -one 16 states ago which leads to the current minimum distance. The bit pattern stored -there is the error corrected bit pattern for that symbol. - -So, what does Trellis coding actually achieve? TCM is easier to understand by looking -at the V.23bis modem spec. The V.32bis spec. is very similar to V.17, except that it -is a full duplex modem and has non-TCM options, as well as the TCM ones in V.17. - -V32bis defines two options for pumping 9600 bits per second down a phone line - one -with and one without TCM. Both run at 2400 baud. The non-TCM one uses simple 16 point -QAM on the raw data. The other takes two out of every four raw bits, and convolutionally -encodes them to 3. Now we have 5 bits per symbol, and we need 32 point QAM to send the -data. - -The raw error rate from simple decoding of the 32 point QAM is horrible compared to -decoding the 16 point QAM. If a point decoded from the 32 point QAM is wrong, the likely -correct choice should be one of the adjacent ones. It is unlikely to have been one that -is far away across the constellation, unless there was a huge noise spike, interference, -or something equally nasty. Now, the 32 point symbols do not exist in isolation. There -was a kind of temporal smearing in the convolutional coding. It created a well defined -dependency between successive symbols. If we knew for sure what the last few symbols -were, they would lead us to a limited group of possible values for the current symbol, -constrained by the behaviour of the convolutional coder. If you look at how the symbols -were mapped to constellation points, you will see the mapping tries to spread those -possible symbols as far apart as possible. This will leave only one that is pretty -close to the received point, which must be the correct choice. However, this assumes -we know the last few symbols for sure. Since we don't, we have a bit more work to do -to achieve reliable decoding. - -Instead of decoding to the nearest point on the constellation, we decode to a group of -likely constellation points in the neighbourhood of the received point. We record the -mismatch for each - that is the distance across the constellation between the received -point and the group of nearby points. To avoid square roots, recording x2 + y2 can be -good enough. Symbol by symbol, we record this information. After a few symbols we can -stand back and look at the recorded information. - -For each symbol we have a set of possible symbol values and error metric pairs. The -dependency between symbols, created by the convolutional coder, means some paths from -symbol to symbol are possible and some are not. It we trace back through the possible -symbol to symbol paths, and total up the error metric through those paths, we end up -with a set of figures of merit (or more accurately figures of demerit, since -larger == worse) for the likelihood of each path being the correct one. The path with -the lowest total metric is the most likely, and gives us our final choice for what we -think the current symbol really is. - -That was hard work. It takes considerable computation to do this selection and traceback, -symbol by symbol. We need to get quite a lot from this. It needs to drive the error rate -down so far that is compensates for the much higher error rate due to the larger -constellation, and then buys us some actual benefit. Well in the example we are looking -at - V.32bis at 9600bps - it works out the error rate from the TCM option is like using -the non-TCM option with several dB more signal to noise ratio. That's nice. The non-TCM -option is pretty reasonable on most phone lines, but a better error rate is always a -good thing. However, V32bis includes a 14,400bps option. That uses 2400 baud, and 6 bit -symbols. Convolutional encoding increases that to 7 bits per symbol, by taking 2 bits and -encoding them to 3. This give a 128 point QAM constellation. Again, the difference between -using this, and using just an uncoded 64 point constellation is equivalent to maybe 5dB of -extra signal to noise ratio. However, in this case it is the difference between the modem -working only on the most optimal lines, and being widely usable across most phone lines. -TCM absolutely transformed the phone line modem business. -*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -#define V17_CONSTELLATION_SCALING_FACTOR 1024.0 -#else -#define V17_CONSTELLATION_SCALING_FACTOR 1.0 -#endif - -/*! - V.17 modem receive side descriptor. This defines the working state for a - single instance of a V.17 modem receiver. -*/ -typedef struct v17_rx_state_s v17_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise a V.17 modem receive context. - \brief Initialise a 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 put_bit The callback routine used to put the received data. - \param user_data An opaque pointer passed to the put_bit routine. - \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data); - -/*! Reinitialise an existing V.17 modem receive context. - \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 0 if a long training sequence is expected. - 1 if a short training sequence is expected. - 2 if the expected training sequence is automatically selected. - \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); - -/*! Release a V.17 modem receive context. - \brief Release a V.17 modem receive context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v17_rx_release(v17_rx_state_t *s); - -/*! Free a V.17 modem receive context. - \brief Free a V.17 modem receive context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v17_rx_free(v17_rx_state_t *s); - -/*! Get the logging context associated with a V.17 modem receive context. - \brief Get the logging context associated with a V.17 modem receive context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v17_rx_get_logging_state(v17_rx_state_t *s); - -/*! Change the put_bit function associated with a V.17 modem receive context. - \brief Change the put_bit function associated with a V.17 modem receive context. - \param s The modem context. - \param put_bit The callback routine used to handle received bits. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit, void *user_data); - -/*! Change the modem status report function associated with a V.17 modem receive context. - \brief Change the modem status report function associated with a V.17 modem receive context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Process a block of received V.17 modem audio samples. - \brief Process a block of received V.17 modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len); - -/*! Fake processing of a missing block of received V.17 modem audio samples. - (e.g due to packet loss). - \brief Fake processing of a missing block of received V.17 modem audio samples. - \param s The modem context. - \param len The number of samples to fake. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len); - -/*! Get a snapshot of the current equalizer coefficients. - \brief Get a snapshot of the current equalizer coefficients. - \param s The modem context. - \param coeffs The vector of complex coefficients. - \return The number of coefficients in the vector. */ -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v17_rx_equalizer_state(v17_rx_state_t *s, complexi16_t **coeffs); -#else -SPAN_DECLARE(int) v17_rx_equalizer_state(v17_rx_state_t *s, complexf_t **coeffs); -#endif - -/*! Get the current received carrier frequency. - \param s The modem context. - \return The frequency, in Hertz. */ -SPAN_DECLARE(float) v17_rx_carrier_frequency(v17_rx_state_t *s); - -/*! Get the current symbol timing correction since startup. - \param s The modem context. - \return The correction. */ -SPAN_DECLARE(float) v17_rx_symbol_timing_correction(v17_rx_state_t *s); - -/*! Get a current received signal power. - \param s The modem context. - \return The signal power, in dBm0. */ -SPAN_DECLARE(float) v17_rx_signal_power(v17_rx_state_t *s); - -/*! Set the power level at which the carrier detection will cut in - \param s The modem context. - \param cutoff The signal cutoff power, in dBm0. */ -SPAN_DECLARE(void) v17_rx_signal_cutoff(v17_rx_state_t *s, float cutoff); - -/*! Set a handler routine to process QAM status reports - \param s The modem context. - \param handler The handler routine. - \param user_data An opaque pointer passed to the handler routine. */ -SPAN_DECLARE(void) v17_rx_set_qam_report_handler(v17_rx_state_t *s, qam_report_handler_t handler, void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v17tx.h b/libs/spandsp/src/spandsp/v17tx.h deleted file mode 100644 index 79d65629fc..0000000000 --- a/libs/spandsp/src/spandsp/v17tx.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v17tx.h - ITU V.17 modem transmit part - * - * 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_V17TX_H_) -#define _SPANDSP_V17TX_H_ - -/*! \page v17tx_page The V.17 transmitter -\section v17tx_page_sec_1 What does it do? -The V.17 transmitter implements the transmit side of a V.17 modem. This can -operate at data rates of 14400, 12000, 9600 and 7200 bits/second. The audio -output is a stream of 16 bit samples, at 8000 samples/second. The transmit and -receive side of V.17 modems operate independantly. V.17 is mostly used for FAX -transmission, where it provides the standard 14400 bits/second rate. - -\section v17tx_page_sec_2 How does it work? -V.17 uses QAM modulation and trellis coding. The data to be transmitted is -scrambled, to whiten it. The least significant 2 bits of each symbol are then -differentially encoded, using a simple lookup approach. The resulting 2 bits are -convolutionally encoded, producing 3 bits. The extra bit is the redundant bit -of the trellis code. The other bits of the symbol pass by the differential -and convolutional coding unchanged. The resulting bits define the constellation -point to be transmitted for the symbol. The redundant bit doubles the size of the -constellation, and so increases the error rate for detecting individual symbols -at the receiver. However, when a number of successive symbols are processed at -the receiver, the redundancy actually provides several dB of improved error -performance. - -The standard method of producing a QAM modulated signal is to use a sampling -rate which is a multiple of the baud rate. The raw signal is then a series of -complex pulses, each an integer number of samples long. These can be shaped, -using a suitable complex filter, and multiplied by a complex carrier signal -to produce the final QAM signal for transmission. - -The pulse shaping filter is only vaguely defined by the V.17 spec. Some of the -other ITU modem specs. fully define the filter, typically specifying a root -raised cosine filter, with 50% excess bandwidth. This is a pity, since it -increases the variability of the received signal. However, the receiver's -adaptive equalizer will compensate for these differences. The current -design uses a root raised cosine filter with 25% excess bandwidth. Greater -excess bandwidth will not allow the tranmitted signal to meet the spectral -requirements. - -The sampling rate for our transmitter is defined by the channel - 8000 per -second. This is not a multiple of the baud rate (i.e. 2400 baud). The baud -interval is actually 10/3 sample periods. Instead of using a symmetric -FIR to pulse shape the signal, a polyphase filter is used. This consists of -10 sets of coefficients, offering zero to 9/10ths of a baud phase shift as well -as root raised cosine filtering. The appropriate coefficient set is chosen for -each signal sample generated. - -The carrier is generated using the DDS method. Using two second order resonators, -started in quadrature, might be more efficient, as it would have less impact on -the processor cache than a table lookup approach. However, the DDS approach -suits the receiver better, so the same signal generator is also used for the -transmitter. -*/ - -/*! - V.17 modem transmit side descriptor. This defines the working state for a - single instance of a V.17 modem transmitter. -*/ -typedef struct v17_tx_state_s v17_tx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Adjust a V.17 modem transmit context's power output. - \brief Adjust a V.17 modem transmit context's output power. - \param s The modem context. - \param power The power level, in dBm0 */ -SPAN_DECLARE(void) v17_tx_power(v17_tx_state_t *s, float power); - -/*! Initialise a V.17 modem transmit context. This must be called before the first - use of the context, to initialise its contents. - \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 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, 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. - \return 0 for OK, -1 for parameter error. */ -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. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v17_tx_release(v17_tx_state_t *s); - -/*! Free a V.17 modem transmit context. - \brief Free a V.17 modem transmit context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v17_tx_free(v17_tx_state_t *s); - -/*! Get the logging context associated with a V.17 modem transmit context. - \brief Get the logging context associated with a V.17 modem transmit context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v17_tx_get_logging_state(v17_tx_state_t *s); - -/*! Change the get_bit function associated with a V.17 modem transmit context. - \brief Change the get_bit function associated with a V.17 modem transmit context. - \param s The modem context. - \param get_bit The callback routine used to get the data to be transmitted. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit, void *user_data); - -/*! Change the modem status report function associated with a V.17 modem transmit context. - \brief Change the modem status report function associated with a V.17 modem transmit context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Generate a block of V.17 modem audio samples. - \brief Generate a block of V.17 modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v18.h b/libs/spandsp/src/spandsp/v18.h deleted file mode 100644 index f0bd66d48a..0000000000 --- a/libs/spandsp/src/spandsp/v18.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v18.h - V.18 text telephony for the deaf. - * - * Written by Steve Underwood - * - * Copyright (C) 2004-2009 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 */ - -/*! \page v18_page The V.18 text telephony protocols -\section v18_page_sec_1 What does it do? - -\section v18_page_sec_2 How does it work? -*/ - -#if !defined(_SPANDSP_V18_H_) -#define _SPANDSP_V18_H_ - -typedef struct v18_state_s v18_state_t; - -enum -{ - V18_MODE_NONE = 0x0001, - /* V.18 Annex A - Weitbrecht TDD at 45.45bps (US TTY), half-duplex, 5 bit baudot (USA). */ - 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 = 0x0004, - /* V.18 Annex B - DTMF encoding of ASCII (Denmark, Holland and others). */ - 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 = 0x0010, - /* V.18 Annex D - 300bps, Bell 103, duplex, ASCII (USA). */ - V18_MODE_BELL103 = 0x0020, - /* V.18 Annex E - 1200bps Videotex terminals, ASCII (France). */ - V18_MODE_V23VIDEOTEX = 0x0040, - /* V.18 Annex F - V.21 text telephone, V.21, duplex, ASCII (Sweden, Norway and Finland). */ - V18_MODE_V21TEXTPHONE = 0x0080, - /* V.18 Annex G - V.18 text telephone mode. */ - 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, - - V18_AUTOMODING_NONE, - - /* 5-bit, V.21, V.23, EDT, DTMF, Bell 103 */ - V18_AUTOMODING_AUSTRALIA, - V18_AUTOMODING_IRELAND, - - /* EDT, V.21, V.23, 5-bit, DTMF, Bell 103 */ - V18_AUTOMODING_GERMANY, - V18_AUTOMODING_SWITZERLAND, - V18_AUTOMODING_ITALY, - V18_AUTOMODING_SPAIN, - V18_AUTOMODING_AUSTRIA, - - /* DTMF, V.21, V.23, 5-bit, EDT, Bell 103 */ - V18_AUTOMODING_NETHERLANDS, - - /* V.21, DTMF, 5-bit, EDT, V.23, Bell 103 */ - V18_AUTOMODING_ICELAND, - V18_AUTOMODING_NORWAY, - V18_AUTOMODING_SWEDEN, - V18_AUTOMODING_FINALND, - V18_AUTOMODING_DENMARK, - - /* V.21, 5-bit, V.23, EDT, DTMF, Bell 103 */ - V18_AUTOMODING_UK, - - /* 5-bit, Bell 103, V.21, V.23, EDT, DTMF */ - V18_AUTOMODING_USA, - - /* V.23, EDT, DTMF, 5-bit, V.21, Bell 103 */ - V18_AUTOMODING_FRANCE, - V18_AUTOMODING_BELGIUM, - - V18_AUTOMODING_END -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -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 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, - bool calling_party, - int mode, - int nation, - put_msg_func_t put_msg, - void *user_data); - -/*! Release a V.18 context. - \brief Release a V.18 context. - \param s The V.18 context. - \return 0 for OK. */ -SPAN_DECLARE(int) v18_release(v18_state_t *s); - -/*! Free a V.18 context. - \brief Release a V.18 context. - \param s The V.18 context. - \return 0 for OK. */ -SPAN_DECLARE(int) v18_free(v18_state_t *s); - -/*! Generate a block of V.18 audio samples. - \brief Generate a block of V.18 audio samples. - \param s The V.18 context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len); - -/*! Process a block of received V.18 audio samples. - \brief Process a block of received V.18 audio samples. - \param s The V.18 context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of unprocessed samples. -*/ -SPAN_DECLARE(int) v18_rx(v18_state_t *s, const int16_t amp[], int len); - -/*! Fake processing of a missing block of received V.18 audio samples. - (e.g due to packet loss). - \brief Fake processing of a missing block of received V.18 audio samples. - \param s The V.18 context. - \param len The number of samples to fake. - \return The number of unprocessed samples. -*/ -SPAN_DECLARE(int) v18_rx_fillin(v18_state_t *s, int len); - -/*! \brief Put a string to a V.18 context's input buffer. - \param s The V.18 context. - \param msg The string to be added. - \param len The length of the string. If negative, the string is - assumed to be a NULL terminated string. - \return The number of characters actually added. This may be less than the - length of the digit string, if the buffer fills up. If the string is - invalid, this function will return -1. */ -SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len); - -/*! \brief Get the current mode of a V.18 connection. - \param s The V.18 context. - \return The mode. */ -SPAN_DECLARE(int) v18_get_current_mode(v18_state_t *s); - -/*! \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. -*/ -SPAN_DECLARE(const char *) v18_mode_to_str(int mode); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v22bis.h b/libs/spandsp/src/spandsp/v22bis.h deleted file mode 100644 index fd93373cec..0000000000 --- a/libs/spandsp/src/spandsp/v22bis.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v22bis.h - ITU V.22bis modem - * - * 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 */ - -/*! \page v22bis_page The V.22bis modem -\section v22bis_page_sec_1 What does it do? -The V.22bis modem is a duplex modem for general data use on the PSTN, at rates -of 1200 and 2400 bits/second. It is a compatible extension of the V.22 modem, -which is a 1200 bits/second only design. It is a band-split design, using carriers -of 1200Hz and 2400Hz. It is the fastest PSTN modem in general use which does not -use echo-cancellation. - -\section v22bis__page_sec_2 How does it work? -V.22bis uses 4PSK modulation at 1200 bits/second or 16QAM modulation at 2400 -bits/second. At 1200bps the symbols are so long that a fixed compromise equaliser -is sufficient to recover the 4PSK signal reliably. At 2400bps an adaptive -equaliser is necessary. - -The V.22bis training sequence includes sections which allow the modems to determine -if the far modem can support (or is willing to support) 2400bps operation. The -modems will automatically use 2400bps if both ends are willing to use that speed, -or 1200bps if one or both ends to not acknowledge that 2400bps is OK. -*/ - -#if !defined(_SPANDSP_V22BIS_H_) -#define _SPANDSP_V22BIS_H_ - -#if defined(SPANDSP_USE_FIXED_POINT) -#define V22BIS_CONSTELLATION_SCALING_FACTOR 1024.0 -#else -#define V22BIS_CONSTELLATION_SCALING_FACTOR 1.0 -#endif - -enum -{ - V22BIS_GUARD_TONE_NONE, - V22BIS_GUARD_TONE_550HZ, - V22BIS_GUARD_TONE_1800HZ -}; - -/*! - V.22bis modem descriptor. This defines the working state for a single instance - of a V.22bis modem. -*/ -typedef struct v22bis_state_s v22bis_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Process a block of received V.22bis modem audio samples. - \brief Process a block of received V.22bis modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len); - -/*! Fake processing of a missing block of received V.22bis modem audio samples. - (e.g due to packet loss). - \brief Fake processing of a missing block of received V.22bis modem audio samples. - \param s The modem context. - \param len The number of samples to fake. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len); - -/*! Get a snapshot of the current equalizer coefficients. - \brief Get a snapshot of the current equalizer coefficients. - \param coeffs The vector of complex coefficients. - \return The number of coefficients in the vector. */ -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexi16_t **coeffs); -#else -SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexf_t **coeffs); -#endif - -/*! Get the current received carrier frequency. - \param s The modem context. - \return The frequency, in Hertz. */ -SPAN_DECLARE(float) v22bis_rx_carrier_frequency(v22bis_state_t *s); - -/*! Get the current symbol timing correction since startup. - \param s The modem context. - \return The correction. */ -SPAN_DECLARE(float) v22bis_rx_symbol_timing_correction(v22bis_state_t *s); - -/*! Get a current received signal power. - \param s The modem context. - \return The signal power, in dBm0. */ -SPAN_DECLARE(float) v22bis_rx_signal_power(v22bis_state_t *s); - -/*! Set the power level at which the carrier detection will cut in - \param s The modem context. - \param cutoff The signal cutoff power, in dBm0. */ -SPAN_DECLARE(void) v22bis_rx_signal_cutoff(v22bis_state_t *s, float cutoff); - -/*! Set a handler routine to process QAM status reports - \param s The modem context. - \param handler The handler routine. - \param user_data An opaque pointer passed to the handler routine. */ -SPAN_DECLARE(void) v22bis_rx_set_qam_report_handler(v22bis_state_t *s, qam_report_handler_t handler, void *user_data); - -/*! Generate a block of V.22bis modem audio samples. - \brief Generate a block of V.22bis modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples to be generated. - \return The number of samples actually generated. */ -SPAN_DECLARE(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len); - -/*! Adjust a V.22bis modem transmit context's power output. - \brief Adjust a V.22bis modem transmit context's output power. - \param s The modem context. - \param power The power level, in dBm0 */ -SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power); - -/*! Reinitialise an existing V.22bis modem context, so it may be reused. - \brief Reinitialise an existing V.22bis modem context. - \param s The modem context. - \param bit_rate The bit rate of the modem. Valid values are 1200 and 2400. - \return 0 for OK, -1 for bad parameter. */ -SPAN_DECLARE(int) v22bis_restart(v22bis_state_t *s, int bit_rate); - -/*! Request a retrain for a V.22bis modem context. A rate change may also be requested. - \brief Request a retrain for a V.22bis modem context. - \param s The modem context. - \param bit_rate The bit rate of the modem. Valid values are 1200 and 2400. - \return 0 for OK, -1 for request rejected. */ -SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate); - -/*! Request a loopback 2 for a V.22bis modem context. - \brief Request a loopback 2 for a V.22bis modem context. - \param s The modem context. - \param enable True to enable loopback, or false to disable it. - \return 0 for OK, -1 for request reject. */ -SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, 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 - \param s The modem context. */ -SPAN_DECLARE(int) v22bis_get_current_bit_rate(v22bis_state_t *s); - -/*! Initialise a V.22bis modem context. This must be called before the first - use of the context, to initialise its contents. - \brief Initialise a V.22bis modem context. - \param s The modem context. - \param bit_rate The bit rate of the modem. Valid values are 1200 and 2400. - \param guard The guard tone option. 0 = none, 1 = 550Hz, 2 = 1800Hz. - \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 get_bit_user_data An opaque pointer, passed in calls to the get_bit routine. - \param put_bit The callback routine used to put the data received. - \param put_bit_user_data An opaque pointer, passed in calls to the put_bit routine. - \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, - int bit_rate, - int guard, - bool calling_party, - get_bit_func_t get_bit, - void *get_bit_user_data, - put_bit_func_t put_bit, - void *put_bit_user_data); - -/*! Release a V.22bis modem receive context. - \brief Release a V.22bis modem receive context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v22bis_release(v22bis_state_t *s); - -/*! Free a V.22bis modem receive context. - \brief Free a V.22bis modem receive context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v22bis_free(v22bis_state_t *s); - -/*! Get the logging context associated with a V.22bis modem context. - \brief Get the logging context associated with a V.22bis modem context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v22bis_get_logging_state(v22bis_state_t *s); - -/*! Change the get_bit function associated with a V.22bis modem context. - \brief Change the get_bit function associated with a V.22bis modem context. - \param s The modem context. - \param get_bit The callback routine used to get the data to be transmitted. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v22bis_set_get_bit(v22bis_state_t *s, get_bit_func_t get_bit, void *user_data); - -/*! Change the get_bit function associated with a V.22bis modem context. - \brief Change the put_bit function associated with a V.22bis modem context. - \param s The modem context. - \param put_bit The callback routine used to process the data received. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit, void *user_data); - -/*! Change the modem status report function associated with a V.22bis modem receive context. - \brief Change the modem status report function associated with a V.22bis modem receive context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_status_func_t handler, void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v27ter_rx.h b/libs/spandsp/src/spandsp/v27ter_rx.h deleted file mode 100644 index cf8eaa99f7..0000000000 --- a/libs/spandsp/src/spandsp/v27ter_rx.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v27ter_rx.h - ITU V.27ter modem receive part - * - * 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 */ - -#if !defined(_SPANDSP_V27TER_RX_H_) -#define _SPANDSP_V27TER_RX_H_ - -/*! \page v27ter_rx_page The V.27ter receiver - -\section v27ter_rx_page_sec_1 What does it do? -The V.27ter receiver implements the receive side of a V.27ter modem. This can operate -at data rates of 4800 and 2400 bits/s. The audio input is a stream of 16 bit samples, -at 8000 samples/second. The transmit and receive side of V.27ter modems operate -independantly. V.27ter is mostly used for FAX transmission, where it provides the -standard 4800 bits/s rate (the 2400 bits/s mode is not used for FAX). - -\section v27ter_rx_page_sec_2 How does it work? -V.27ter defines two modes of operation. One uses 8-PSK at 1600 baud, giving 4800bps. -The other uses 4-PSK at 1200 baud, giving 2400bps. A training sequence is specified -at the start of transmission, which makes the design of a V.27ter receiver relatively -straightforward. -*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -#define V27TER_CONSTELLATION_SCALING_FACTOR 1024.0 -#else -#define V27TER_CONSTELLATION_SCALING_FACTOR 1.0 -#endif - -/*! - V.27ter modem receive side descriptor. This defines the working state for a - single instance of a V.27ter modem receiver. -*/ -typedef struct v27ter_rx_state_s v27ter_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise a V.27ter modem receive context. - \brief Initialise a 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 put_bit The callback routine used to put the received data. - \param user_data An opaque pointer passed to the put_bit routine. - \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v27ter_rx_state_t *) v27ter_rx_init(v27ter_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data); - -/*! Reinitialise an existing V.27ter modem receive context. - \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. - \return 0 for OK, -1 for bad parameter */ -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. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v27ter_rx_release(v27ter_rx_state_t *s); - -/*! Free a V.27ter modem receive context. - \brief Free a V.27ter modem receive context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v27ter_rx_free(v27ter_rx_state_t *s); - -/*! Get the logging context associated with a V.27ter modem receive context. - \brief Get the logging context associated with a V.27ter modem receive context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v27ter_rx_get_logging_state(v27ter_rx_state_t *s); - -/*! Change the put_bit function associated with a V.27ter modem receive context. - \brief Change the put_bit function associated with a V.27ter modem receive context. - \param s The modem context. - \param put_bit The callback routine used to handle received bits. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t put_bit, void *user_data); - -/*! Change the modem status report function associated with a V.27ter modem receive context. - \brief Change the modem status report function associated with a V.27ter modem receive context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Process a block of received V.27ter modem audio samples. - \brief Process a block of received V.27ter modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len); - -/*! Fake processing of a missing block of received V.27ter modem audio samples. - (e.g due to packet loss). - \brief Fake processing of a missing block of received V.27ter modem audio samples. - \param s The modem context. - \param len The number of samples to fake. - \return The number of samples unprocessed. -*/ -SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len); - -/*! Get a snapshot of the current equalizer coefficients. - \brief Get a snapshot of the current equalizer coefficients. - \param coeffs The vector of complex coefficients. - \return The number of coefficients in the vector. */ -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexi16_t **coeffs); -#else -SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexf_t **coeffs); -#endif - -/*! Get the current received carrier frequency. - \param s The modem context. - \return The frequency, in Hertz. */ -SPAN_DECLARE(float) v27ter_rx_carrier_frequency(v27ter_rx_state_t *s); - -/*! Get the current symbol timing correction since startup. - \param s The modem context. - \return The correction. */ -SPAN_DECLARE(float) v27ter_rx_symbol_timing_correction(v27ter_rx_state_t *s); - -/*! Get a current received signal power. - \param s The modem context. - \return The signal power, in dBm0. */ -SPAN_DECLARE(float) v27ter_rx_signal_power(v27ter_rx_state_t *s); - -/*! Set the power level at which the carrier detection will cut in - \param s The modem context. - \param cutoff The signal cutoff power, in dBm0. */ -SPAN_DECLARE(void) v27ter_rx_signal_cutoff(v27ter_rx_state_t *s, float cutoff); - -/*! Set a handler routine to process QAM status reports - \param s The modem context. - \param handler The handler routine. - \param user_data An opaque pointer passed to the handler routine. */ -SPAN_DECLARE(void) v27ter_rx_set_qam_report_handler(v27ter_rx_state_t *s, qam_report_handler_t handler, void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v27ter_tx.h b/libs/spandsp/src/spandsp/v27ter_tx.h deleted file mode 100644 index 96a0df5f54..0000000000 --- a/libs/spandsp/src/spandsp/v27ter_tx.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v27ter_tx.h - ITU V.27ter modem transmit part - * - * 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 */ - -#if !defined(_SPANDSP_V27TER_TX_H_) -#define _SPANDSP_V27TER_TX_H_ - -/*! \page v27ter_tx_page The V.27ter transmitter -\section v27ter_tx_page_sec_1 What does it do? -The V.27ter transmitter implements the transmit side of a V.27ter modem. This -can operate at data rates of 4800 and 2400 bits/s. The audio output is a stream -of 16 bit samples, at 8000 samples/second. The transmit and receive side of -V.27ter modems operate independantly. V.27ter is used for FAX transmission, -where it provides the standard 4800 and 2400 bits/s rates. - -\section v27ter_tx_page_sec_2 How does it work? -V.27ter uses DPSK modulation. A common method of producing a DPSK modulated -signal is to use a sampling rate which is a multiple of the baud rate. The raw -signal is then a series of complex pulses, each an integer number of samples -long. These can be shaped, using a suitable complex filter, and multiplied by a -complex carrier signal to produce the final DPSK signal for transmission. - -The pulse shaping filter for V.27ter is defined in the spec. It is a root raised -cosine filter with 50% excess bandwidth. - -The sampling rate for our transmitter is defined by the channel - 8000 samples/s. -This is a multiple of the baud rate at 4800 bits/s (8-PSK at 1600 baud, 5 samples per -symbol), but not at 2400 bits/s (4-PSK at 1200 baud, 20/3 samples per symbol). The baud -interval is actually 20/3 sample periods at 2400bis/s. A symmetric FIR is used to -apply root raised cosine filtering in the 4800bits/s mode. In the 2400bits/s mode -a polyphase FIR filter is used. This consists of 20 sets of coefficients, offering -zero to 19/20ths of a baud phase shift as well as root raised cosine filtering. -The appropriate coefficient set is chosen for each signal sample generated. - -The carrier is generated using the DDS method. Using 2 second order resonators, -started in quadrature, might be more efficient, as it would have less impact on -the processor cache than a table lookup approach. However, the DDS approach -suits the receiver better, so then same signal generator is also used for the -transmitter. -*/ - -/*! - V.27ter modem transmit side descriptor. This defines the working state for a - single instance of a V.27ter modem transmitter. -*/ -typedef struct v27ter_tx_state_s v27ter_tx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Adjust a V.27ter modem transmit context's power output. - \brief Adjust a V.27ter modem transmit context's output power. - \param s The modem context. - \param power The power level, in dBm0 */ -SPAN_DECLARE(void) v27ter_tx_power(v27ter_tx_state_t *s, float power); - -/*! Initialise a V.27ter modem transmit context. - \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 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, 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. - \return 0 for OK, -1 for bad parameter */ -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. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v27ter_tx_release(v27ter_tx_state_t *s); - -/*! Free a V.27ter modem transmit context. - \brief Free a V.27ter modem transmit context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v27ter_tx_free(v27ter_tx_state_t *s); - -/*! Get the logging context associated with a V.27ter modem transmit context. - \brief Get the logging context associated with a V.27ter modem transmit context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v27ter_tx_get_logging_state(v27ter_tx_state_t *s); - -/*! Change the get_bit function associated with a V.27ter modem transmit context. - \brief Change the get_bit function associated with a V.27ter modem transmit context. - \param s The modem context. - \param get_bit The callback routine used to get the data to be transmitted. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t get_bit, void *user_data); - -/*! Change the modem status report function associated with a V.27ter modem transmit context. - \brief Change the modem status report function associated with a V.27ter modem transmit context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Generate a block of V.27ter modem audio samples. - \brief Generate a block of V.27ter modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v29rx.h b/libs/spandsp/src/spandsp/v29rx.h deleted file mode 100644 index 9ef548e4c7..0000000000 --- a/libs/spandsp/src/spandsp/v29rx.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v29rx.h - ITU V.29 modem receive part - * - * 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 */ - -#if !defined(_SPANDSP_V29RX_H_) -#define _SPANDSP_V29RX_H_ - -/*! \page v29rx_page The V.29 receiver -\section v29rx_page_sec_1 What does it do? -The V.29 receiver implements the receive side of a V.29 modem. This can operate -at data rates of 9600, 7200 and 4800 bits/s. The audio input is a stream of 16 -bit samples, at 8000 samples/second. The transmit and receive side of V.29 -modems operate independantly. V.29 is mostly used for FAX transmission, where it -provides the standard 9600 and 7200 bits/s rates (the 4800 bits/s mode is not -used for FAX). - -\section v29rx_page_sec_2 How does it work? -V.29 operates at 2400 baud for all three bit rates. It uses 16-QAM modulation for -9600bps, 8-QAM for 7200bps, and 4-PSK for 4800bps. A training sequence is specified -at the start of transmission, which makes the design of a V.29 receiver relatively -straightforward. - -The first stage of the training sequence consists of 128 -symbols, alternating between two constellation positions. The receiver monitors -the signal power, to sense the possible presence of a valid carrier. When the -alternating signal begins, the power rising above a minimum threshold (-26dBm0) -causes the main receiver computation to begin. The initial measured power is -used to quickly set the gain of the receiver. After this initial settling, the -front end gain is locked, and the adaptive equalizer tracks any subsequent -signal level variation. The signal is oversampled to 24000 samples/second (i.e. -signal, zero, zero, signal, zero, zero, ...) and fed to a complex root raised -cosine pulse shaping filter. This filter has been modified from the conventional -root raised cosine filter, by shifting it up the band, to be centred at the nominal -carrier frequency. This filter interpolates the samples, pulse shapes, and performs -a fractional sample delay at the same time. 48 sets of filter coefficients are used to -achieve a set of finely spaces fractional sample delays, between zero and -one sample. By choosing every fifth sample, and the appropriate set of filter -coefficients, the properly tuned symbol tracker can select data samples at 4800 -samples/second from points within 1.125 degrees of the centre and mid-points of -each symbol. The output of the filter is multiplied by a complex carrier, generated -by a DDS. The result is a baseband signal, requiring no further filtering, apart from -an adaptive equalizer. The baseband signal is fed to a T/2 adaptive equalizer. -A band edge component maximisation algorithm is used to tune the sampling, so the samples -fed to the equalizer are close to the mid point and edges of each symbol. Initially -the algorithm is very lightly damped, to ensure the symbol alignment pulls in -quickly. Because the sampling rate will not be precisely the same as the -transmitter's (the spec. says the symbol timing should be within 0.01%), the -receiver constantly evaluates and corrects this sampling throughout its -operation. During the symbol timing maintainence phase, the algorithm uses -a heavier damping. - -The carrier is specified as 1700Hz +-1Hz at the transmitter, and 1700 +-7Hz at -the receiver. The receive carrier would only be this inaccurate if the link -includes FDM sections. These are being phased out, but the design must still -allow for the worst case. Using an initial 1700Hz signal for demodulation gives -a worst case rotation rate for the constellation of about one degree per symbol. -Once the symbol timing synchronisation algorithm has been given time to lock to -the symbol timing of the initial alternating pattern, the phase of the demodulated -signal is recorded on two successive symbols - once for each of the constellation -positions. The receiver then tracks the symbol alternations, until a large phase jump -occurs. This signifies the start of the next phase of the training sequence. At this -point the total phase shift between the original recorded symbol phase, and the -symbol phase just before the phase jump occurred is used to provide a coarse -estimation of the rotation rate of the constellation, and it current absolute -angle of rotation. These are used to update the current carrier phase and phase -update rate in the carrier DDS. The working data already in the pulse shaping -filter and equalizer buffers is given a similar step rotation to pull it all -into line. From this point on, a heavily damped integrate and dump approach, -based on the angular difference between each received constellation position and -its expected position, is sufficient to track the carrier, and maintain phase -alignment. A fast rough approximator for the arc-tangent function is adequate -for the estimation of the angular error. - -The next phase of the training sequence is a scrambled sequence of two -particular symbols. We train the T/2 adaptive equalizer using this sequence. The -scrambling makes the signal sufficiently diverse to ensure the equalizer -converges to the proper generalised solution. At the end of this sequence, the -equalizer should be sufficiently well adapted that is can correctly resolve the -full QAM constellation. However, the equalizer continues to adapt throughout -operation of the modem, fine tuning on the more complex data patterns of the -full QAM constellation. - -In the last phase of the training sequence, the modem enters normal data -operation, with a short defined period of all ones as data. As in most high -speed modems, data in a V.29 modem passes through a scrambler, to whiten the -spectrum of the signal. The transmitter should initialise its data scrambler, -and pass the ones through it. At the end of the ones, real data begins to pass -through the scrambler, and the transmit modem is in normal operation. The -receiver tests that ones are really received, in order to verify the modem -trained correctly. If all is well, the data following the ones is fed to the -application, and the receive modem is up and running. Unfortunately, some -transmit side of some real V.29 modems fail to initialise their scrambler before -sending the ones. This means the first 23 received bits (the length of the -scrambler register) cannot be trusted for the test. The receive modem, -therefore, only tests that bits starting at bit 24 are really ones. -*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -#define V29_CONSTELLATION_SCALING_FACTOR 4096.0 -#else -#define V29_CONSTELLATION_SCALING_FACTOR 1.0 -#endif - -#if defined(SPANDSP_USE_FIXED_POINT) -typedef void (*qam_report_handler_t)(void *user_data, const complexi16_t *constel, const complexi16_t *target, int symbol); -#else -typedef void (*qam_report_handler_t)(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol); -#endif - -/*! - V.29 modem receive side descriptor. This defines the working state for a - single instance of a V.29 modem receiver. -*/ -typedef struct v29_rx_state_s v29_rx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Initialise a V.29 modem receive context. - \brief Initialise a 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 put_bit The callback routine used to put the received data. - \param user_data An opaque pointer passed to the put_bit routine. - \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v29_rx_state_t *) v29_rx_init(v29_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data); - -/*! Reinitialise an existing V.29 modem receive context. - \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. - \return 0 for OK, -1 for bad parameter */ -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. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v29_rx_release(v29_rx_state_t *s); - -/*! Free a V.29 modem receive context. - \brief Free a V.29 modem receive context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v29_rx_free(v29_rx_state_t *s); - -/*! Get the logging context associated with a V.29 modem receive context. - \brief Get the logging context associated with a V.29 modem receive context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v29_rx_get_logging_state(v29_rx_state_t *s); - -/*! Change the put_bit function associated with a V.29 modem receive context. - \brief Change the put_bit function associated with a V.29 modem receive context. - \param s The modem context. - \param put_bit The callback routine used to handle received bits. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit, void *user_data); - -/*! Change the modem status report function associated with a V.29 modem receive context. - \brief Change the modem status report function associated with a V.29 modem receive context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Process a block of received V.29 modem audio samples. - \brief Process a block of received V.29 modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len); - -/*! Fake processing of a missing block of received V.29 modem audio samples. - (e.g due to packet loss). - \brief Fake processing of a missing block of received V.29 modem audio samples. - \param s The modem context. - \param len The number of samples to fake. - \return The number of samples unprocessed. */ -SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len); - -/*! Get a snapshot of the current equalizer coefficients. - \brief Get a snapshot of the current equalizer coefficients. - \param s The modem context. - \param coeffs The vector of complex coefficients. - \return The number of coefficients in the vector. */ -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v29_rx_equalizer_state(v29_rx_state_t *s, complexi16_t **coeffs); -#else -SPAN_DECLARE(int) v29_rx_equalizer_state(v29_rx_state_t *s, complexf_t **coeffs); -#endif - -/*! Get the current received carrier frequency. - \param s The modem context. - \return The frequency, in Hertz. */ -SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s); - -/*! Get the current symbol timing correction since startup. - \param s The modem context. - \return The correction. */ -SPAN_DECLARE(float) v29_rx_symbol_timing_correction(v29_rx_state_t *s); - -/*! Get the current received signal power. - \param s The modem context. - \return The signal power, in dBm0. */ -SPAN_DECLARE(float) v29_rx_signal_power(v29_rx_state_t *s); - -/*! Set the power level at which the carrier detection will cut in - \param s The modem context. - \param cutoff The signal cutoff power, in dBm0. */ -SPAN_DECLARE(void) v29_rx_signal_cutoff(v29_rx_state_t *s, float cutoff); - -/*! Set a handler routine to process QAM status reports - \param s The modem context. - \param handler The handler routine. - \param user_data An opaque pointer passed to the handler routine. */ -SPAN_DECLARE(void) v29_rx_set_qam_report_handler(v29_rx_state_t *s, qam_report_handler_t handler, void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v29tx.h b/libs/spandsp/src/spandsp/v29tx.h deleted file mode 100644 index 6bdb5de9e7..0000000000 --- a/libs/spandsp/src/spandsp/v29tx.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v29tx.h - ITU V.29 modem transmit part - * - * 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 */ - -#if !defined(_SPANDSP_V29TX_H_) -#define _SPANDSP_V29TX_H_ - -/*! \page v29tx_page The V.29 transmitter -\section v29tx_page_sec_1 What does it do? -The V.29 transmitter implements the transmit side of a V.29 modem. This can -operate at data rates of 9600, 7200 and 4800 bits/s. The audio output is a -stream of 16 bit samples, at 8000 samples/second. The transmit and receive side -of V.29 modems operate independantly. V.29 is mostly used for FAX transmission, -where it provides the standard 9600 and 7200 bits/s rates (the 4800 bits/s mode -is not used for FAX). - -\section v29tx_page_sec_2 How does it work? -V.29 uses QAM modulation. The standard method of producing a QAM modulated -signal is to use a sampling rate which is a multiple of the baud rate. The raw -signal is then a series of complex pulses, each an integer number of samples -long. These can be shaped, using a suitable complex filter, and multiplied by a -complex carrier signal to produce the final QAM signal for transmission. - -The pulse shaping filter is only vaguely defined by the V.29 spec. Some of the -other ITU modem specs. fully define the filter, typically specifying a root -raised cosine filter, with 50% excess bandwidth. This is a pity, since it -increases the variability of the received signal. However, the receiver's -adaptive equalizer will compensate for these differences. The current -design uses a root raised cosine filter with 25% excess bandwidth. Greater -excess bandwidth will not allow the tranmitted signal to meet the spectral -requirements. - -The sampling rate for our transmitter is defined by the channel - 8000 per -second. This is not a multiple of the baud rate (i.e. 2400 baud). The baud -interval is actually 10/3 sample periods. Instead of using a symmetric -FIR to pulse shape the signal, a polyphase filter is used. This consists of -10 sets of coefficients, offering zero to 9/10ths of a baud phase shift as well -as root raised cosine filtering. The appropriate coefficient set is chosen for -each signal sample generated. - -The carrier is generated using the DDS method. Using two second order resonators, -started in quadrature, might be more efficient, as it would have less impact on -the processor cache than a table lookup approach. However, the DDS approach -suits the receiver better, so the same signal generator is also used for the -transmitter. - -The equation defining QAM modulation is: - - s(n) = A*cos(2*pi*f*n + phi(n)) - -where phi(n) is the phase of the information, and A is the amplitude of the information - -using the identity - - cos(x + y) = cos(x)*cos(y) - sin(x)*sin(y) - -we get - - s(n) = A {cos(2*pi*f*n)*cos(phi(n)) - sin(2*pi*f*n)*sin(phi(n))} - -substituting with the constellation positions - - I(n) = A*cos(phi(n)) - Q(n) = A*sin(phi(n)) - -gives - - s(n) = I(n)*cos(2*pi*f*n) - Q(n)*sin(2*pi*f*n) - -*/ - -/*! - V.29 modem transmit side descriptor. This defines the working state for a - single instance of a V.29 modem transmitter. -*/ -typedef struct v29_tx_state_s v29_tx_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Adjust a V.29 modem transmit context's power output. - \brief Adjust a V.29 modem transmit context's output power. - \param s The modem context. - \param power The power level, in dBm0 */ -SPAN_DECLARE(void) v29_tx_power(v29_tx_state_t *s, float power); - -/*! Initialise a V.29 modem transmit context. This must be called before the first - use of the context, to initialise its contents. - \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 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, 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. - \return 0 for OK, -1 for bad parameter */ -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. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v29_tx_release(v29_tx_state_t *s); - -/*! Free a V.29 modem transmit context. - \brief Free a V.29 modem transmit context. - \param s The modem context. - \return 0 for OK */ -SPAN_DECLARE(int) v29_tx_free(v29_tx_state_t *s); - -/*! Get the logging context associated with a V.29 modem transmit context. - \brief Get the logging context associated with a V.29 modem transmit context. - \param s The modem context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v29_tx_get_logging_state(v29_tx_state_t *s); - -/*! Change the get_bit function associated with a V.29 modem transmit context. - \brief Change the get_bit function associated with a V.29 modem transmit context. - \param s The modem context. - \param get_bit The callback routine used to get the data to be transmitted. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit, void *user_data); - -/*! Change the modem status report function associated with a V.29 modem transmit context. - \brief Change the modem status report function associated with a V.29 modem transmit context. - \param s The modem context. - \param handler The callback routine used to report modem status changes. - \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_status_func_t handler, void *user_data); - -/*! Generate a block of V.29 modem audio samples. - \brief Generate a block of V.29 modem audio samples. - \param s The modem context. - \param amp The audio sample buffer. - \param len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v42.h b/libs/spandsp/src/spandsp/v42.h deleted file mode 100644 index fa1d7c1b5f..0000000000 --- a/libs/spandsp/src/spandsp/v42.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42.h - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 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. - */ - -/*! \page v42_page V.42 modem error correction -\section v42_page_sec_1 What does it do? -The V.42 specification defines an error correcting protocol for PSTN modems, based on -HDLC and LAP. This makes it similar to an X.25 link. A special variant of LAP, known -as LAP-M, is defined in the V.42 specification. A means for modems to determine if the -far modem supports V.42 is also defined. - -\section v42_page_sec_2 How does it work? -*/ - -#if !defined(_SPANDSP_V42_H_) -#define _SPANDSP_V42_H_ - -typedef struct v42_state_s v42_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(const char *) lapm_status_to_str(int status); - -SPAN_DECLARE(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok); - -SPAN_DECLARE(void) v42_start(v42_state_t *s); - -SPAN_DECLARE(void) v42_stop(v42_state_t *s); - -/*! Set the busy status of the local end of a V.42 context. - \param s The V.42 context. - \param busy The new local end busy status. - \return The previous local end busy status. -*/ -SPAN_DECLARE(int) v42_set_local_busy_status(v42_state_t *s, int busy); - -/*! Get the busy status of the far end of a V.42 context. - \param s The V.42 context. - \return The far end busy status. -*/ -SPAN_DECLARE(int) v42_get_far_busy_status(v42_state_t *s); - -SPAN_DECLARE(void) v42_rx_bit(void *user_data, int bit); - -SPAN_DECLARE(int) v42_tx_bit(void *user_data); - -SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t callback, void *user_data); - -/*! Get the logging context associated with a V.42 context. - \brief Get the logging context associated with a V.42 context. - \param s The V.42 context. - \return A pointer to the logging context */ -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 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, - bool calling_party, - bool detect, - get_msg_func_t iframe_get, - put_msg_func_t iframe_put, - void *user_data); - -/*! Restart a V.42 context. - \param s The V.42 context. -*/ -SPAN_DECLARE(void) v42_restart(v42_state_t *s); - -/*! Release a V.42 context. - \param s The V.42 context. - \return 0 if OK */ -SPAN_DECLARE(int) v42_release(v42_state_t *s); - -/*! Free a V.42 context. - \param s The V.42 context. - \return 0 if OK */ -SPAN_DECLARE(int) v42_free(v42_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v42bis.h b/libs/spandsp/src/spandsp/v42bis.h deleted file mode 100644 index 1f9ae98fa1..0000000000 --- a/libs/spandsp/src/spandsp/v42bis.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42bis.h - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 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. - */ - -/*! \page v42bis_page V.42bis modem data compression -\section v42bis_page_sec_1 What does it do? -The v.42bis specification defines a data compression scheme, to work in -conjunction with the error correction scheme defined in V.42. - -\section v42bis_page_sec_2 How does it work? -*/ - -#if !defined(_SPANDSP_V42BIS_H_) -#define _SPANDSP_V42BIS_H_ - -#define V42BIS_MIN_STRING_SIZE 6 -#define V42BIS_MAX_STRING_SIZE 250 -#define V42BIS_MIN_DICTIONARY_SIZE 512 -#define V42BIS_MAX_BITS 12 -#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ -#define V42BIS_MAX_OUTPUT_LENGTH 1024 - -enum -{ - V42BIS_P0_NEITHER_DIRECTION = 0, - V42BIS_P0_INITIATOR_RESPONDER, - V42BIS_P0_RESPONDER_INITIATOR, - V42BIS_P0_BOTH_DIRECTIONS -}; - -enum -{ - V42BIS_COMPRESSION_MODE_DYNAMIC = 0, - V42BIS_COMPRESSION_MODE_ALWAYS, - V42BIS_COMPRESSION_MODE_NEVER -}; - -/*! - V.42bis compression/decompression descriptor. This defines the working state for a - single instance of V.42bis compress/decompression. -*/ -typedef struct v42bis_state_s v42bis_state_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Compress a block of octets. - \param s The V.42bis context. - \param buf The data to be compressed. - \param len The length of the data buffer. - \return 0 */ -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len); - -/*! Flush out any data remaining in a compression buffer. - \param s The V.42bis context. - \return 0 */ -SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); - -/*! Decompress a block of octets. - \param s The V.42bis context. - \param buf The data to be decompressed. - \param len The length of the data buffer. - \return 0 */ -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len); - -/*! Flush out any data remaining in the decompression buffer. - \param s The V.42bis context. - \return 0 */ -SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); - -/*! Set the compression mode. - \param s The V.42bis context. - \param mode One of the V.42bis compression modes - - V42BIS_COMPRESSION_MODE_DYNAMIC, - V42BIS_COMPRESSION_MODE_ALWAYS, - V42BIS_COMPRESSION_MODE_NEVER */ -SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); - -/*! Get the logging context associated with a V.42bis context. - \brief Get the logging context associated with a V.42bis context. - \param s The V.42bis context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) v42bis_get_logging_state(v42bis_state_t *s); - -/*! Initialise a V.42bis context. - \param s The V.42bis context. - \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. - \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. - \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. - \param encode_handler Encode callback handler. - \param encode_user_data An opaque pointer passed to the encode callback handler. - \param max_encode_len The maximum length that should be passed to the encode handler. - \param decode_handler Decode callback handler. - \param decode_user_data An opaque pointer passed to the decode callback handler. - \param max_decode_len The maximum length that should be passed to the decode handler. - \return The V.42bis context. */ -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, - int negotiated_p0, - int negotiated_p1, - int negotiated_p2, - put_msg_func_t encode_handler, - void *encode_user_data, - int max_encode_len, - put_msg_func_t decode_handler, - void *decode_user_data, - int max_decode_len); - -/*! Release a V.42bis context. - \param s The V.42bis context. - \return 0 if OK */ -SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); - -/*! Free a V.42bis context. - \param s The V.42bis context. - \return 0 if OK */ -SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/v8.h b/libs/spandsp/src/spandsp/v8.h deleted file mode 100644 index ab3d1466c5..0000000000 --- a/libs/spandsp/src/spandsp/v8.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v8.h - V.8 modem negotiation processing. - * - * 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 */ - -/*! \page v8_page The V.8 modem negotiation protocol -\section v8_page_sec_1 What does it do? -The V.8 specification defines a procedure to be used as PSTN modem answer phone calls, -which allows the modems to negotiate the optimum modem standard, which both ends can -support. - -\section v8_page_sec_2 How does it work? -At startup the modems communicate using the V.21 standard at 300 bits/second. They -exchange simple messages about their capabilities, and choose the modem standard they -will use for data communication. The V.8 protocol then terminates, and the modems -being negotiating and training with their chosen modem standard. -*/ - -#if !defined(_SPANDSP_V8_H_) -#define _SPANDSP_V8_H_ - -typedef struct v8_parms_s v8_parms_t; - -typedef void (*v8_result_handler_t)(void *user_data, v8_parms_t *result); - -enum v8_call_function_e -{ - V8_CALL_TBS = 0, - V8_CALL_H324 = 1, - V8_CALL_V18 = 2, - V8_CALL_T101 = 3, - V8_CALL_T30_TX = 4, - V8_CALL_T30_RX = 5, - V8_CALL_V_SERIES = 6, - V8_CALL_FUNCTION_EXTENSION = 7 -}; - -enum v8_modulation_e -{ - V8_MOD_V17 = (1 << 0), /* V.17 half-duplex */ - V8_MOD_V21 = (1 << 1), /* V.21 duplex */ - V8_MOD_V22 = (1 << 2), /* V.22/V22.bis duplex */ - V8_MOD_V23HDX = (1 << 3), /* V.23 half-duplex */ - V8_MOD_V23 = (1 << 4), /* V.23 duplex */ - V8_MOD_V26BIS = (1 << 5), /* V.23 duplex */ - V8_MOD_V26TER = (1 << 6), /* V.23 duplex */ - V8_MOD_V27TER = (1 << 7), /* V.23 duplex */ - V8_MOD_V29 = (1 << 8), /* V.29 half-duplex */ - V8_MOD_V32 = (1 << 9), /* V.32/V32.bis duplex */ - V8_MOD_V34HDX = (1 << 10), /* V.34 half-duplex */ - V8_MOD_V34 = (1 << 11), /* V.34 duplex */ - V8_MOD_V90 = (1 << 12), /* V.90 duplex */ - V8_MOD_V92 = (1 << 13) /* V.92 duplex */ -}; - -enum v8_protocol_e -{ - V8_PROTOCOL_NONE = 0, - V8_PROTOCOL_LAPM_V42 = 1, - V8_PROTOCOL_EXTENSION = 7 -}; - -enum v8_pstn_access_e -{ - V8_PSTN_ACCESS_CALL_DCE_CELLULAR = 0x01, - V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR = 0x02, - V8_PSTN_ACCESS_DCE_ON_DIGITAL = 0x04 -}; - -enum v8_pcm_modem_availability_e -{ - V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE = 0x01, - V8_PSTN_PCM_MODEM_V90_V92_DIGITAL = 0x02, - V8_PSTN_PCM_MODEM_V91 = 0x04 -}; - -enum v8_status_e -{ - /*! V.8 negotiation is in progress. */ - V8_STATUS_IN_PROGRESS = 0, - /*! V.8 has been offered by the other (calling) party. */ - V8_STATUS_V8_OFFERED = 1, - /*! V.8 has been successfully negotiated. Note that this only means the V.8 - message exchange has successfully completed. The actual exchanged parameters - must be checked, to see if the call can proceed properly. */ - V8_STATUS_V8_CALL = 2, - /*! A non-V.8 is being received. */ - V8_STATUS_NON_V8_CALL = 3, - /*! V.8 negotiation failed. */ - V8_STATUS_FAILED = 4 -}; - -typedef struct v8_state_s v8_state_t; - -struct v8_parms_s -{ - int status; - int modem_connect_tone; - int send_ci; - int v92; - int call_function; - unsigned int modulations; - int protocol; - int pstn_access; - int pcm_modem_availability; - int nsf; - int t66; -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(int) v8_restart(v8_state_t *s, - 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 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, - bool calling_party, - v8_parms_t *parms, - v8_result_handler_t result_handler, - void *user_data); - -/*! Release a V.8 context. - \brief Release a V.8 context. - \param s The V.8 context. - \return 0 for OK. */ -SPAN_DECLARE(int) v8_release(v8_state_t *s); - -/*! Free a V.8 context. - \brief Release a V.8 context. - \param s The V.8 context. - \return 0 for OK. */ -SPAN_DECLARE(int) v8_free(v8_state_t *s); - -SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s); - -/*! Generate a block of V.8 audio samples. - \brief Generate a block of V.8 audio samples. - \param s The V.8 context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. -*/ -SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len); - -/*! Process a block of received V.8 audio samples. - \brief Process a block of received V.8 audio samples. - \param s The V.8 context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. -*/ -SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len); - -/*! Log the list of supported modulations. - \brief Log the list of supported modulations. - \param s The V.8 context. - \param modulation_schemes The list of supported modulations. */ -SPAN_DECLARE(void) v8_log_supported_modulations(v8_state_t *s, int modulation_schemes); - -SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function); -SPAN_DECLARE(const char *) v8_modulation_to_str(int modulation_scheme); -SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol); -SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access); -SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf); -SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability); -SPAN_DECLARE(const char *) v8_t66_to_str(int t66); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/vector_float.h b/libs/spandsp/src/spandsp/vector_float.h deleted file mode 100644 index 97d95f3007..0000000000 --- a/libs/spandsp/src/spandsp/vector_float.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * vector_float.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_VECTOR_FLOAT_H_) -#define _SPANDSP_VECTOR_FLOAT_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -SPAN_DECLARE(void) vec_copyf(float z[], const float x[], int n); - -SPAN_DECLARE(void) vec_copy(double z[], const double x[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_copyl(long double z[], const long double x[], int n); -#endif - -SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n); - -SPAN_DECLARE(void) vec_negate(double z[], const double x[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_negatel(long double z[], const long double x[], int n); -#endif - -SPAN_DECLARE(void) vec_zerof(float z[], int n); - -SPAN_DECLARE(void) vec_zero(double z[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_zerol(long double z[], int n); -#endif - -SPAN_DECLARE(void) vec_setf(float z[], float x, int n); - -SPAN_DECLARE(void) vec_set(double z[], double x, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_setl(long double z[], long double x, int n); -#endif - -SPAN_DECLARE(void) vec_addf(float z[], const float x[], const float y[], int n); - -SPAN_DECLARE(void) vec_add(double z[], const double x[], const double y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_addl(long double z[], const long double x[], const long double y[], int n); -#endif - -SPAN_DECLARE(void) vec_scaledxy_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n); - -SPAN_DECLARE(void) vec_scaledxy_add(double z[], const double x[], double x_scale, const double y[], double y_scale, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledxy_addl(long double z[], const long double x[], long double x_scale, const long double y[], long double y_scale, int n); -#endif - -SPAN_DECLARE(void) vec_scaledy_addf(float z[], const float x[], const float y[], float y_scale, int n); - -SPAN_DECLARE(void) vec_scaledy_add(double z[], const double x[], const double y[], double y_scale, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledy_addl(long double z[], const long double x[], const long double y[], long double y_scale, int n); -#endif - -SPAN_DECLARE(void) vec_subf(float z[], const float x[], const float y[], int n); - -SPAN_DECLARE(void) vec_sub(double z[], const double x[], const double y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_subl(long double z[], const long double x[], const long double y[], int n); -#endif - -SPAN_DECLARE(void) vec_scaledxy_subf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n); - -SPAN_DECLARE(void) vec_scaledxy_sub(double z[], const double x[], double x_scale, const double y[], double y_scale, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledxy_subl(long double z[], const long double x[], long double x_scale, const long double y[], long double y_scale, int n); -#endif - -SPAN_DECLARE(void) vec_scaledx_subf(float z[], const float x[], float x_scale, const float y[], int n); - -SPAN_DECLARE(void) vec_scaledx_sub(double z[], const double x[], double x_scale, const double y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledx_subl(long double z[], const long double x[], long double x_scale, const long double y[], int n); -#endif - -SPAN_DECLARE(void) vec_scaledy_subf(float z[], const float x[], const float y[], float y_scale, int n); - -SPAN_DECLARE(void) vec_scaledy_sub(double z[], const double x[], const double y[], double y_scale, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledy_subl(long double z[], const long double x[], const long double y[], long double y_scale, int n); -#endif - -SPAN_DECLARE(void) vec_scalar_mulf(float z[], const float x[], float y, int n); - -SPAN_DECLARE(void) vec_scalar_mul(double z[], const double x[], double y, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scalar_mull(long double z[], const long double x[], long double y, int n); -#endif - -SPAN_DECLARE(void) vec_scalar_addf(float z[], const float x[], float y, int n); - -SPAN_DECLARE(void) vec_scalar_add(double z[], const double x[], double y, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scalar_addl(long double z[], const long double x[], long double y, int n); -#endif - -SPAN_DECLARE(void) vec_scalar_subf(float z[], const float x[], float y, int n); - -SPAN_DECLARE(void) vec_scalar_sub(double z[], const double x[], double y, int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scalar_subl(long double z[], const long double x[], long double y, int n); -#endif - -SPAN_DECLARE(void) vec_mulf(float z[], const float x[], const float y[], int n); - -SPAN_DECLARE(void) vec_mul(double z[], const double x[], const double y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_mull(long double z[], const long double x[], const long double y[], int n); -#endif - -/*! \brief Find the dot product of two float vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(float) vec_dot_prodf(const float x[], const float y[], int n); - -/*! \brief Find the dot product of two double vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(double) vec_dot_prod(const double x[], const double y[], int n); - -#if defined(HAVE_LONG_DOUBLE) -/*! \brief Find the dot product of two long double vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(long double) vec_dot_prodl(const long double x[], const long double y[], int n); -#endif - -/*! \brief Find the dot product of two float vectors, where the first is a circular buffer - with an offset for the starting position. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \param pos The starting position in the x vector. - \return The dot product of the two vectors. */ -SPAN_DECLARE(float) vec_circular_dot_prodf(const float x[], const float y[], int n, int pos); - -SPAN_DECLARE(void) vec_lmsf(const float x[], float y[], int n, float error); - -SPAN_DECLARE(void) vec_circular_lmsf(const float x[], float y[], int n, int pos, float error); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/vector_int.h b/libs/spandsp/src/spandsp/vector_int.h deleted file mode 100644 index 775d525c86..0000000000 --- a/libs/spandsp/src/spandsp/vector_int.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * vector_int.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_VECTOR_INT_H_) -#define _SPANDSP_VECTOR_INT_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -static __inline__ void vec_copyi(int z[], const int x[], int n) -{ - memcpy(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_copyi16(int16_t z[], const int16_t x[], int n) -{ - memcpy(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_copyi32(int32_t z[], const int32_t x[], int n) -{ - memcpy(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_movei(int z[], const int x[], int n) -{ - memmove(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_movei16(int16_t z[], const int16_t x[], int n) -{ - memmove(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_movei32(int32_t z[], const int32_t x[], int n) -{ - memmove(z, x, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_zeroi(int z[], int n) -{ - memset(z, 0, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_zeroi16(int16_t z[], int n) -{ - memset(z, 0, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_zeroi32(int32_t z[], int n) -{ - memset(z, 0, n*sizeof(z[0])); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_seti(int z[], int x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_seti16(int16_t z[], int16_t x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_seti32(int32_t z[], int32_t x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -/*- End of function --------------------------------------------------------*/ - -/*! \brief Find the dot product of two int16_t vectors. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \return The dot product of the two vectors. */ -SPAN_DECLARE(int32_t) vec_dot_prodi16(const int16_t x[], const int16_t y[], int n); - -/*! \brief Find the dot product of two int16_t vectors, where the first is a circular buffer - with an offset for the starting position. - \param x The first vector. - \param y The first vector. - \param n The number of elements in the vectors. - \param pos The starting position in the x vector. - \return The dot product of the two vectors. */ -SPAN_DECLARE(int32_t) vec_circular_dot_prodi16(const int16_t x[], const int16_t y[], int n, int pos); - -SPAN_DECLARE(void) vec_lmsi16(const int16_t x[], int16_t y[], int n, int16_t error); - -SPAN_DECLARE(void) vec_circular_lmsi16(const int16_t x[], int16_t y[], int n, int pos, int16_t error); - -/*! \brief Find the minimum and maximum values in an int16_t vector. - \param x The vector to be searched. - \param n The number of elements in the vector. - \param out A two element vector. The first will receive the - maximum. The second will receive the minimum. This parameter - may be set to NULL. - \return The absolute maximum value. Since the range of negative numbers - exceeds the range of positive one, the returned integer is longer - than the ones being searched. */ -SPAN_DECLARE(int32_t) vec_min_maxi16(const int16_t x[], int n, int16_t out[]); - -static __inline__ int vec_norm2i16(const int16_t *vec, int len) -{ - int i; - int sum; - - sum = 0; - for (i = 0; i < len; i++) - sum += vec[i]*vec[i]; - return sum; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void vec_sari16(int16_t *vec, int len, int shift) -{ - int i; - - for (i = 0; i < len; i++) - vec[i] >>= shift; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int vec_max_bitsi16(const int16_t *vec, int len) -{ - int i; - int max; - int v; - int b; - - max = 0; - for (i = 0; i < len; i++) - { - v = abs(vec[i]); - if (v > max) - max = v; - } - b = 0; - while (max != 0) - { - b++; - max >>= 1; - } - return b; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/version.h b/libs/spandsp/src/spandsp/version.h deleted file mode 100644 index 469cd37b08..0000000000 --- a/libs/spandsp/src/spandsp/version.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * version.h - A tag file, so the exact installed revision can be assertained. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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_VERSION_H_) -#define _SPANDSP_VERSION_H_ - -/* The date and time of the version are in UTC form. */ - -#define SPANDSP_RELEASE_DATE 20120902 -#define SPANDSP_RELEASE_TIME 163333 -#define SPANDSP_RELEASE_DATETIME_STRING "20120902 163333" - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/version.h.in b/libs/spandsp/src/spandsp/version.h.in deleted file mode 100644 index c5d137a01c..0000000000 --- a/libs/spandsp/src/spandsp/version.h.in +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * version.h - A tag file, so the exact installed revision can be assertained. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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_VERSION_H_) -#define _SPANDSP_VERSION_H_ - -/* The date and time of the version are in UTC form. */ - -#define SPANDSP_RELEASE_DATE $SPANDSP_RELEASE_DATE -#define SPANDSP_RELEASE_TIME $SPANDSP_RELEASE_TIME -#define SPANDSP_RELEASE_DATETIME_STRING "$SPANDSP_RELEASE_DATE $SPANDSP_RELEASE_TIME" - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/super_tone_rx.c b/libs/spandsp/src/super_tone_rx.c deleted file mode 100644 index 48dc02e693..0000000000 --- a/libs/spandsp/src/super_tone_rx.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * super_tone_rx.c - Flexible telephony supervisory tone detection. - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#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" -#include "spandsp/complex_vector_float.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" - -#include "spandsp/private/super_tone_rx.h" - -#if defined(SPANDSP_USE_FIXED_POINT) -#define DETECTION_THRESHOLD 16439 /* -42dBm0 [((SUPER_TONE_BINS*SUPER_TONE_BINS*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 */ -#else -#define DETECTION_THRESHOLD 2104205.6f /* -42dBm0 [((SUPER_TONE_BINS*SUPER_TONE_BINS*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 */ -#endif - -static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq) -{ - int i; - - if (freq == 0) - return -1; - /* Look for an existing frequency */ - for (i = 0; i < desc->used_frequencies; i++) - { - if (desc->pitches[i][0] == freq) - return desc->pitches[i][1]; - } - /* Look for an existing tone which is very close. We may need to merge - the detectors. */ - for (i = 0; i < desc->used_frequencies; i++) - { - if ((desc->pitches[i][0] - 10) <= freq && freq <= (desc->pitches[i][0] + 10)) - { - /* Merge these two */ - desc->pitches[desc->used_frequencies][0] = freq; - desc->pitches[desc->used_frequencies][1] = i; - make_goertzel_descriptor(&desc->desc[desc->pitches[i][1]], (float) (freq + desc->pitches[i][0])/2, SUPER_TONE_BINS); - desc->used_frequencies++; - return desc->pitches[i][1]; - } - } - desc->pitches[i][0] = freq; - desc->pitches[i][1] = desc->monitored_frequencies; - if (desc->monitored_frequencies%5 == 0) - { - 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++; - return desc->pitches[i][1]; -} -/*- End of function --------------------------------------------------------*/ - -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 **) 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; - desc->tones++; - return desc->tones - 1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_rx_add_element(super_tone_rx_descriptor_t *desc, - int tone, - int f1, - int f2, - int min, - int max) -{ - int step; - - step = desc->tone_segs[tone]; - if (step%5 == 0) - { - 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); - desc->tone_list[tone][step].min_duration = min*8; - desc->tone_list[tone][step].max_duration = (max == 0) ? 0x7FFFFFFF : max*8; - desc->tone_segs[tone]++; - return step; -} -/*- End of function --------------------------------------------------------*/ - -static int test_cadence(super_tone_rx_segment_t *pattern, - int steps, - super_tone_rx_segment_t *test, - int rotation) -{ - int i; - int j = 0; - - if (rotation >= 0) - { - /* Check only for the sustaining of a tone in progress. This means - we only need to check each block if the latest step is compatible - with the tone template. */ - if (steps < 0) - { - /* A -ve value for steps indicates we just changed step, and need to - check the last one ended within spec. If we don't do this - extra test a low duration segment might be accepted as OK. */ - steps = -steps; - j = (rotation + steps - 2)%steps; - if (pattern[j].f1 != test[8].f1 || pattern[j].f2 != test[8].f2) - return 0; - if (pattern[j].min_duration > test[8].min_duration*SUPER_TONE_BINS - || - pattern[j].max_duration < test[8].min_duration*SUPER_TONE_BINS) - { - return 0; - } - } - if (steps) - j = (rotation + steps - 1)%steps; - if (pattern[j].f1 != test[9].f1 || pattern[j].f2 != test[9].f2) - return 0; - if (pattern[j].max_duration < test[9].min_duration*SUPER_TONE_BINS) - return 0; - } - else - { - /* Look for a complete template match. */ - for (i = 0; i < steps; i++) - { - j = i + 10 - steps; - if (pattern[i].f1 != test[j].f1 || pattern[i].f2 != test[j].f2) - return 0; - if (pattern[i].min_duration > test[j].min_duration*SUPER_TONE_BINS - || - pattern[i].max_duration < test[j].min_duration*SUPER_TONE_BINS) - { - return 0; - } - } - } - return 1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(super_tone_rx_descriptor_t *) super_tone_rx_make_descriptor(super_tone_rx_descriptor_t *desc) -{ - if (desc == NULL) - { - if ((desc = (super_tone_rx_descriptor_t *) span_alloc(sizeof(*desc))) == NULL) - return NULL; - } - desc->tone_list = NULL; - desc->tone_segs = NULL; - - desc->used_frequencies = 0; - desc->monitored_frequencies = 0; - desc->desc = NULL; - desc->tones = 0; - return desc; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_rx_free_descriptor(super_tone_rx_descriptor_t *desc) -{ - int i; - - if (desc) - { - for (i = 0; i < desc->tones; i++) - { - if (desc->tone_list[i]) - span_free(desc->tone_list[i]); - } - if (desc->tone_list) - span_free(desc->tone_list); - if (desc->tone_segs) - span_free(desc->tone_segs); - if (desc->desc) - span_free(desc->desc); - span_free(desc); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) super_tone_rx_tone_callback(super_tone_rx_state_t *s, - tone_report_func_t callback, - void *user_data) -{ - s->tone_callback = callback; - s->callback_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) super_tone_rx_segment_callback(super_tone_rx_state_t *s, - tone_segment_func_t callback) -{ - s->segment_callback = callback; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(super_tone_rx_state_t *) super_tone_rx_init(super_tone_rx_state_t *s, - super_tone_rx_descriptor_t *desc, - tone_report_func_t callback, - void *user_data) -{ - int i; - - if (desc == NULL) - return NULL; - if (callback == NULL) - return NULL; - if (s == NULL) - { - if ((s = (super_tone_rx_state_t *) span_alloc(sizeof(*s) + desc->monitored_frequencies*sizeof(goertzel_state_t))) == NULL) - return NULL; - } - - for (i = 0; i < 11; i++) - { - s->segments[i].f1 = -1; - s->segments[i].f2 = -1; - s->segments[i].min_duration = 0; - } - s->segment_callback = NULL; - s->tone_callback = callback; - s->callback_data = user_data; - if (desc) - s->desc = desc; - s->detected_tone = -1; -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif - for (i = 0; i < desc->monitored_frequencies; i++) - goertzel_init(&s->state[i], &s->desc->desc[i]); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_rx_release(super_tone_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_rx_free(super_tone_rx_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void super_tone_chunk(super_tone_rx_state_t *s) -{ - int i; - int j; - int k1; - int k2; -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t res[SUPER_TONE_BINS/2] = {0}; -#else - float res[SUPER_TONE_BINS/2] = {0}; -#endif - - for (i = 0; i < s->desc->monitored_frequencies; i++) - res[i] = goertzel_result(&s->state[i]); - /* Find our two best monitored frequencies, which also have adequate energy. */ - if (s->energy < DETECTION_THRESHOLD) - { - k1 = -1; - k2 = -1; - } - else - { - if (res[0] > res[1]) - { - k1 = 0; - k2 = 1; - } - else - { - k1 = 1; - k2 = 0; - } - for (j = 2; j < s->desc->monitored_frequencies; j++) - { - if (res[j] >= res[k1]) - { - k2 = k1; - k1 = j; - } - else if (res[j] >= res[k2]) - { - k2 = j; - } - } - if ((res[k1] + res[k2]) < TONE_TO_TOTAL_ENERGY*s->energy) - { - k1 = -1; - k2 = -1; - } - else if (res[k1] > TONE_TWIST*res[k2]) - { - k2 = -1; - } - else if (k2 < k1) - { - j = k1; - k1 = k2; - k2 = j; - } - } - /* See if this differs from last time. */ - if (k1 != s->segments[10].f1 || k2 != s->segments[10].f2) - { - /* It is different, but this might just be a transitional quirk, or - a one shot hiccup (eg due to noise). Only if this same thing is - seen a second time should we change state. */ - s->segments[10].f1 = k1; - s->segments[10].f2 = k2; - /* While things are hopping around, consider this a continuance of the - previous state. */ - s->segments[9].min_duration++; - } - else - { - if (k1 != s->segments[9].f1 || k2 != s->segments[9].f2) - { - if (s->detected_tone >= 0) - { - /* Test for the continuance of the existing tone pattern, based on our new knowledge of an - entire segment length. */ - if (!test_cadence(s->desc->tone_list[s->detected_tone], -s->desc->tone_segs[s->detected_tone], s->segments, s->rotation++)) - { - s->detected_tone = -1; - s->tone_callback(s->callback_data, s->detected_tone, -10, 0); - } - } - if (s->segment_callback) - { - s->segment_callback(s->callback_data, - s->segments[9].f1, - s->segments[9].f2, - s->segments[9].min_duration*SUPER_TONE_BINS/8); - } - memmove(&s->segments[0], &s->segments[1], 9*sizeof(s->segments[0])); - s->segments[9].f1 = k1; - s->segments[9].f2 = k2; - s->segments[9].min_duration = 1; - } - else - { - /* This is a continuance of the previous state */ - if (s->detected_tone >= 0) - { - /* Test for the continuance of the existing tone pattern. We must do this here, so we can sense the - discontinuance of the tone on an excessively long segment. */ - if (!test_cadence(s->desc->tone_list[s->detected_tone], s->desc->tone_segs[s->detected_tone], s->segments, s->rotation)) - { - s->detected_tone = -1; - s->tone_callback(s->callback_data, s->detected_tone, -10, 0); - } - } - s->segments[9].min_duration++; - } - } - if (s->detected_tone < 0) - { - /* Test for the start of any of the monitored tone patterns */ - for (j = 0; j < s->desc->tones; j++) - { - if (test_cadence(s->desc->tone_list[j], s->desc->tone_segs[j], s->segments, -1)) - { - s->detected_tone = j; - s->rotation = 0; - s->tone_callback(s->callback_data, s->detected_tone, -10, 0); - break; - } - } - } -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_rx(super_tone_rx_state_t *s, const int16_t amp[], int samples) -{ - int i; - int x; - int sample; -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t xamp; -#else - float xamp; -#endif - - x = 0; - for (sample = 0; sample < samples; sample += x) - { - for (i = 0; i < s->desc->monitored_frequencies; i++) - x = goertzel_update(&s->state[i], amp + sample, samples - sample); - for (i = 0; i < x; i++) - { - xamp = goertzel_preadjust_amp(amp[sample + i]); -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy += ((int32_t) xamp*xamp); -#else - s->energy += xamp*xamp; -#endif - } - if (s->state[0].current_sample >= SUPER_TONE_BINS) - { - /* We have finished a Goertzel block. */ - super_tone_chunk(s); -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif - } - } - return samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_rx_fillin(super_tone_rx_state_t *s, int samples) -{ - /* TODO: Roll the detector forward without a state change */ - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/super_tone_tx.c b/libs/spandsp/src/super_tone_tx.c deleted file mode 100644 index cd6ac8290e..0000000000 --- a/libs/spandsp/src/super_tone_tx.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * super_tone_tx.c - Flexible telephony supervisory tone generation. - * - * 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#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" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_tx.h" - -#include "spandsp/private/tone_generate.h" -#include "spandsp/private/super_tone_tx.h" - -/* - The tone played to wake folk up when they have left the phone off hook is an - oddity amongst supervisory tones. It is designed to sound loud and nasty. Most - tones are one or two pure sine pitches, or one AM moduluated pitch. This alert - tone varies between countries, but AT&T are a typical example. - - AT&T Receiver Off-Hook Tone is 1400 Hz, 2060 Hz, 2450 Hz and 2600 Hz at 0dBm0/frequency - on and off every .1 second. On some older space division switching systems - Receiver Off-Hook was 1400 Hz, 2060 Hz, 2450 Hz and 2600 Hz at +5 VU on and - off every .1 second. On a No. 5 ESS this continues for 30 seconds. On a No. - 2/2B ESS this continues for 40 seconds. On some other AT&T switches there are - two iterations of 50 seconds each. -*/ - -SPAN_DECLARE(super_tone_tx_step_t *) super_tone_tx_make_step(super_tone_tx_step_t *s, - float f1, - float l1, - float f2, - float l2, - int length, - int cycles) -{ - if (s == NULL) - { - if ((s = (super_tone_tx_step_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - if (f1 >= 1.0f) - { - s->tone[0].phase_rate = dds_phase_ratef(f1); - s->tone[0].gain = dds_scaling_dbm0f(l1); - } - else - { - s->tone[0].phase_rate = 0; - s->tone[0].gain = 0.0f; - } - if (f2 >= 1.0f) - { - s->tone[1].phase_rate = dds_phase_ratef(f2); - s->tone[1].gain = dds_scaling_dbm0f(l2); - } - else - { - s->tone[1].phase_rate = 0; - s->tone[1].gain = 0.0f; - } - s->tone_on = (f1 > 0.0f); - s->length = length*SAMPLE_RATE/1000; - s->cycles = cycles; - s->next = NULL; - s->nest = NULL; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_tx_free_tone(super_tone_tx_step_t *s) -{ - super_tone_tx_step_t *t; - - while (s) - { - /* Follow nesting... */ - if (s->nest) - super_tone_tx_free_tone(s->nest); - t = s; - s = s->next; - span_free(t); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(super_tone_tx_state_t *) super_tone_tx_init(super_tone_tx_state_t *s, super_tone_tx_step_t *tree) -{ - if (tree == NULL) - return NULL; - if (s == NULL) - { - if ((s = (super_tone_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->level = 0; - s->levels[0] = tree; - s->cycles[0] = tree->cycles; - - s->current_position = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_tx_release(super_tone_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_tx_free(super_tone_tx_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) super_tone_tx(super_tone_tx_state_t *s, int16_t amp[], int max_samples) -{ - int samples; - int limit; - int len; - int i; - float xamp; - super_tone_tx_step_t *tree; - - if (s->level < 0 || s->level >= SUPER_TONE_TX_MAX_LEVELS) - return 0; - samples = 0; - tree = s->levels[s->level]; - while (tree && samples < max_samples) - { - if (tree->tone_on) - { - /* A period of tone. A length of zero means infinite length. */ - if (s->current_position == 0) - { - /* New step - prepare the tone generator */ - for (i = 0; i < SUPER_TONE_TX_MAX_TONES; i++) - s->tone[i] = tree->tone[i]; - } - len = tree->length - s->current_position; - if (tree->length == 0) - { - len = max_samples - samples; - /* We just need to make current position non-zero */ - s->current_position = 1; - } - else if (len > max_samples - samples) - { - len = max_samples - samples; - s->current_position += len; - } - else - { - s->current_position = 0; - } - if (s->tone[0].phase_rate < 0) - { - for (limit = len + samples; samples < limit; samples++) - { - /* There must be two, and only two tones */ - xamp = dds_modf(&s->phase[0], -s->tone[0].phase_rate, s->tone[0].gain, 0) - *(1.0f + dds_modf(&s->phase[1], s->tone[1].phase_rate, s->tone[1].gain, 0)); - amp[samples] = (int16_t) lfastrintf(xamp); - } - } - else - { - for (limit = len + samples; samples < limit; samples++) - { - xamp = 0.0f; - for (i = 0; i < SUPER_TONE_TX_MAX_TONES; i++) - { - if (s->tone[i].phase_rate == 0) - break; - xamp += dds_modf(&s->phase[i], s->tone[i].phase_rate, s->tone[i].gain, 0); - } - amp[samples] = (int16_t) lfastrintf(xamp); - } - } - if (s->current_position) - return samples; - } - else if (tree->length) - { - /* A period of silence. The length must always - be explicitly stated. A length of zero does - not give infinite silence. */ - len = tree->length - s->current_position; - if (len > max_samples - samples) - { - len = max_samples - samples; - s->current_position += len; - } - else - { - s->current_position = 0; - } - memset(amp + samples, 0, sizeof(uint16_t)*len); - samples += len; - if (s->current_position) - return samples; - } - /* Nesting has priority... */ - if (tree->nest) - { - if (s->level < SUPER_TONE_TX_MAX_LEVELS - 1) - { - /* TODO: We have stopped an over-range value being used, but we really - ought to deal with the condition properly. */ - tree = tree->nest; - s->levels[++s->level] = tree; - s->cycles[s->level] = tree->cycles; - } - } - else - { - /* ...Next comes repeating, and finally moving forward a step. */ - /* When repeating, note that zero cycles really means endless cycles. */ - while (tree->cycles && --s->cycles[s->level] <= 0) - { - tree = tree->next; - if (tree) - { - /* A fresh new step. */ - s->levels[s->level] = tree; - s->cycles[s->level] = tree->cycles; - break; - } - /* If we are nested we need to pop, otherwise this is the end. */ - if (s->level <= 0) - { - /* Mark the tone as completed */ - s->levels[0] = NULL; - break; - } - tree = s->levels[--s->level]; - } - } - } - return samples; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/swept_tone.c b/libs/spandsp/src/swept_tone.c deleted file mode 100644 index d371bb2828..0000000000 --- a/libs/spandsp/src/swept_tone.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * swept_tone.c - Swept tone generation - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/dds.h" - -#include "spandsp/swept_tone.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/swept_tone.h" - -SPAN_DECLARE(swept_tone_state_t *) swept_tone_init(swept_tone_state_t *s, float start, float end, float level, int duration, int repeating) -{ - if (s == NULL) - { - if ((s = (swept_tone_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->current_phase_inc = - s->starting_phase_inc = dds_phase_rate(start); - s->phase_inc_step = dds_phase_rate((end - start)/(float) duration); - s->scale = dds_scaling_dbm0(level); - s->duration = duration; - s->repeating = repeating; - s->pos = 0; - s->phase = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) swept_tone(swept_tone_state_t *s, int16_t amp[], int max_len) -{ - int i; - int len; - int chunk_len; - - for (len = 0; len < max_len; ) - { - chunk_len = max_len - len; - if (chunk_len > s->duration - s->pos) - chunk_len = s->duration - s->pos; - for (i = len; i < len + chunk_len; i++) - { - amp[i] = (dds(&s->phase, s->current_phase_inc)*s->scale) >> 15; - s->current_phase_inc += s->phase_inc_step; - } - len += chunk_len; - s->pos += chunk_len; - if (s->pos >= s->duration) - { - if (!s->repeating) - break; - s->pos = 0; - s->current_phase_inc = s->starting_phase_inc; - } - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) swept_tone_current_frequency(swept_tone_state_t *s) -{ - return dds_frequency(s->current_phase_inc); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) swept_tone_release(swept_tone_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) swept_tone_free(swept_tone_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c deleted file mode 100644 index cb1f7a5c50..0000000000 --- a/libs/spandsp/src/t30.c +++ /dev/null @@ -1,7410 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30.c - ITU T.30 FAX transfer processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 -#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/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/queue.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/hdlc.h" -#include "spandsp/fsk.h" -#include "spandsp/v29rx.h" -#include "spandsp/v29tx.h" -#include "spandsp/v27ter_rx.h" -#include "spandsp/v27ter_tx.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/t30_fcf.h" -#include "spandsp/t35.h" -#include "spandsp/t30.h" -#include "spandsp/t30_api.h" -#include "spandsp/t30_logging.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/timezone.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" -#include "spandsp/private/t30.h" -#include "spandsp/private/t30_dis_dtc_dcs_bits.h" - -#include "t30_local.h" - -/*! The maximum permitted number of retries of a single command allowed. */ -#define MAX_COMMAND_TRIES 6 - -/*! The maximum permitted number of retries of a single response request allowed. This - is not specified in T.30. However, if you don't apply some limit a messed up FAX - terminal could keep you retrying all day. Its a backstop protection. */ -#define MAX_RESPONSE_TRIES 6 - -/* T.30 defines the following call phases: - Phase A: Call set-up. - Exchange of CNG, CED and the called terminal identification. - Phase B: Pre-message procedure for identifying and selecting the required facilities. - Capabilities negotiation, and training, up the the confirmation to receive. - Phase C: Message transmission (includes phasing and synchronization where appropriate). - Transfer of the message at high speed. - Phase D: Post-message procedure, including end-of-message and confirmation and multi-document procedures. - End of message and acknowledgement. - Phase E: Call release - Final call disconnect. */ -enum -{ - T30_PHASE_IDLE = 0, /* Freshly initialised */ - T30_PHASE_A_CED, /* Doing the CED (answer) sequence */ - T30_PHASE_A_CNG, /* Doing the CNG (caller) sequence */ - T30_PHASE_B_RX, /* Receiving pre-message control messages */ - T30_PHASE_B_TX, /* Transmitting pre-message control messages */ - T30_PHASE_C_NON_ECM_RX, /* Receiving a document message in non-ECM mode */ - T30_PHASE_C_NON_ECM_TX, /* Transmitting a document message in non-ECM mode */ - T30_PHASE_C_ECM_RX, /* Receiving a document message in ECM (HDLC) mode */ - T30_PHASE_C_ECM_TX, /* Transmitting a document message in ECM (HDLC) mode */ - T30_PHASE_D_RX, /* Receiving post-message control messages */ - T30_PHASE_D_TX, /* Transmitting post-message control messages */ - T30_PHASE_E, /* In phase E */ - T30_PHASE_CALL_FINISHED /* Call completely finished */ -}; - -static const char *phase_names[] = -{ - "IDLE", - "A_CED", - "A_CNG", - "B_RX", - "B_TX", - "C_NON_ECM_RX", - "C_NON_ECM_TX", - "C_ECM_RX", - "C_ECM_TX", - "D_RX", - "D_TX", - "E", - "CALL_FINISHED" -}; - -/* These state names are modelled after places in the T.30 flow charts. */ -enum -{ - T30_STATE_IDLE = 0, - T30_STATE_ANSWERING, - T30_STATE_B, - T30_STATE_C, - T30_STATE_D, - T30_STATE_D_TCF, - T30_STATE_D_POST_TCF, - T30_STATE_F_TCF, - T30_STATE_F_CFR, - T30_STATE_F_FTT, - T30_STATE_F_DOC_NON_ECM, - T30_STATE_F_POST_DOC_NON_ECM, - T30_STATE_F_DOC_ECM, - T30_STATE_F_POST_DOC_ECM, - T30_STATE_F_POST_RCP_MCF, - T30_STATE_F_POST_RCP_PPR, - T30_STATE_F_POST_RCP_RNR, - T30_STATE_R, - T30_STATE_T, - T30_STATE_I, - T30_STATE_II, - T30_STATE_II_Q, - T30_STATE_III_Q, - T30_STATE_IV, - T30_STATE_IV_PPS_NULL, - T30_STATE_IV_PPS_Q, - T30_STATE_IV_PPS_RNR, - T30_STATE_IV_CTC, - T30_STATE_IV_EOR, - T30_STATE_IV_EOR_RNR, - T30_STATE_CALL_FINISHED -}; - -static const char *state_names[] = -{ - "IDLE", - "ANSWERING", - "B", - "C", - "D", - "D_TCF", - "D_POST_TCF", - "F_TCF", - "F_CFR", - "F_FTT", - "F_DOC_NON_ECM", - "F_POST_DOC_NON_ECM", - "F_DOC_ECM", - "F_POST_DOC_ECM", - "F_POST_RCP_MCF", - "F_POST_RCP_PPR", - "F_POST_RCP_RNR", - "R", - "T", - "I", - "II", - "II_Q", - "III_Q", - "IV", - "IV_PPS_NULL", - "IV_PPS_Q", - "IV_PPS_RNR", - "IV_CTC", - "IV_EOR", - "IV_EOR_RNR", - "CALL_FINISHED" -}; - -enum -{ - T30_MIN_SCAN_20MS = 0, - T30_MIN_SCAN_5MS = 1, - T30_MIN_SCAN_10MS = 2, - T30_MIN_SCAN_40MS = 4, - T30_MIN_SCAN_0MS = 7, -}; - -enum -{ - T30_MODE_SEND_DOC = 1, - T30_MODE_RECEIVE_DOC -}; - -/*! These are internal assessments of received image quality, used to determine whether we - continue, retrain, or abandon the call. This is only relevant to non-ECM operation. */ -enum -{ - T30_COPY_QUALITY_PERFECT = 0, - T30_COPY_QUALITY_GOOD, - T30_COPY_QUALITY_POOR, - T30_COPY_QUALITY_BAD -}; - -enum -{ - DISBIT1 = 0x01, - DISBIT2 = 0x02, - DISBIT3 = 0x04, - DISBIT4 = 0x08, - DISBIT5 = 0x10, - DISBIT6 = 0x20, - DISBIT7 = 0x40, - DISBIT8 = 0x80 -}; - -/*! There are high level indications of what is happening at any instant, to guide the cleanup - continue, retrain, or abandoning of the call. */ -enum -{ - OPERATION_IN_PROGRESS_NONE = 0, - OPERATION_IN_PROGRESS_T4_RX, - OPERATION_IN_PROGRESS_T4_TX, - OPERATION_IN_PROGRESS_POST_T4_RX, - OPERATION_IN_PROGRESS_POST_T4_TX -}; - -/* All timers specified in milliseconds */ - -/*! Time-out T0 defines the amount of time an automatic calling terminal waits for the called terminal - to answer the call. - T0 begins after the dialling of the number is completed and is reset: - a) when T0 times out; or - b) when timer T1 is started; or - c) if the terminal is capable of detecting any condition which indicates that the call will not be - successful, when such a condition is detected. - The recommended value of T0 is 60+-5s. However, when it is anticipated that a long call set-up - time may be encountered, an alternative value of up to 120s may be used. - NOTE - National regulations may require the use of other values for T0. */ -#define DEFAULT_TIMER_T0 60000 - -/*! Time-out T1 defines the amount of time two terminals will continue to attempt to identify each - other. T1 is 35+-5s, begins upon entering phase B, and is reset upon detecting a valid signal or - when T1 times out. - For operating methods 3 and 4 (see 3.1), the calling terminal starts time-out T1 upon reception of - the V.21 modulation scheme. - For operating method 4 bis a (see 3.1), the calling terminal starts time-out T1 upon starting - transmission using the V.21 modulation scheme. - Annex A says T1 is also the timeout to be used for the receipt of the first HDLC frame after the - start of high speed flags in ECM mode. This seems a strange reuse of the T1 name, so we distinguish - it here by calling it T1A. */ -#define DEFAULT_TIMER_T1 35000 -#define DEFAULT_TIMER_T1A 35000 - -/*! Time-out T2 makes use of the tight control between commands and responses to detect the loss of - command/response synchronization. T2 is 6+-1s, and begins when initiating a command search - (e.g., the first entrance into the "command received" subroutine, reference flow diagram in section 5.2). - T2 is reset when an HDLC flag is received or when T2 times out. */ -#define DEFAULT_TIMER_T2 7000 - -/*! Once HDLC flags begin, T2 is reset, and a 3s timer begins. This timer is unnamed in T.30. Here we - term it T2_FLAGGED. No tolerance is specified for this timer. T2_FLAGGED specifies the maximum - time to wait for the end of a frame, after the initial flag has been seen. */ -#define DEFAULT_TIMER_T2_FLAGGED 3000 - -/*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. If we - don't, there are circumstances where we could continue and reply before the incoming signals have - really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF - carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified. - It is unnamed in T.30. Here we term it T2_DROPPED */ -#define DEFAULT_TIMER_T2_DROPPED 200 - -/*! Timer T2C is a fake timer state for internal use */ - -/*! Time-out T3 defines the amount of time a terminal will attempt to alert the local operator in - response to a procedural interrupt. Failing to achieve operator intervention, the terminal will - discontinue this attempt and shall issue other commands or responses. T3 is 10+-5s, begins on the - first detection of a procedural interrupt command/response signal (i.e., PIN/PIP or PRI-Q) and is - reset when T3 times out or when the operator initiates a line request. */ -#define DEFAULT_TIMER_T3 15000 - -/*! Time-out T4 defines the amount of time a terminal will wait for flags to begin, when waiting for a - response from a remote terminal. T2 is 3s +-15%, and begins when initiating a response search - (e.g., the first entrance into the "response received" subroutine, reference flow diagram in section 5.2). - T4 is reset when an HDLC flag is received or when T4 times out. - NOTE - For manual FAX units, the value of timer T4 may be either 3.0s +-15% or 4.5s +-15%. - If the value of 4.5s is used, then after detection of a valid response to the first DIS, it may - be reduced to 3.0s +-15%. T4 = 3.0s +-15% for automatic units. */ -#define DEFAULT_TIMER_T4 3450 - -/*! Once HDLC flags begin, T4 is reset, and a 3s timer begins. This timer is unnamed in T.30. Here we - term it T4_FLAGGED. No tolerance is specified for this timer. T4_FLAGGED specifies the maximum time - to wait for the end of a frame, after the initial flag has been seen. Note that a different timer - is used for the fast HDLC in ECM mode, to provide time for physical paper handling. */ -#define DEFAULT_TIMER_T4_FLAGGED 3000 - -/*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. if we - don't, there are circumstances where we could continue and reply before the incoming signals have - really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need to wait for the TCF - carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified. - It is unnamed in T.30. Here we term it T4_DROPPED */ -#define DEFAULT_TIMER_T4_DROPPED 200 - -/*! Timer T4C is a fake timer state for internal use */ - -/*! Time-out T5 is defined for the optional T.4 error correction mode. Time-out T5 defines the amount - of time waiting for clearance of the busy condition of the receiving terminal. T5 is 60+-5s and - begins on the first detection of the RNR response. T5 is reset when T5 times out or the MCF or PIP - response is received or when the ERR or PIN response is received in the flow control process after - transmitting the EOR command. If the timer T5 has expired, the DCN command is transmitted for - call release. */ -#define DEFAULT_TIMER_T5 65000 - -/*! (Annex C - ISDN) Time-out T6 defines the amount of time two terminals will continue to attempt to - identify each other. T6 is 5+-0.5s. The timeout begins upon entering Phase B, and is reset upon - detecting a valid signal, or when T6 times out. */ -#define DEFAULT_TIMER_T6 5000 - -/*! (Annex C - ISDN) Time-out T7 is used to detect loss of command/response synchronization. T7 is 6+-1s. - The timeout begins when initiating a command search (e.g., the first entrance into the "command received" - subroutine - see flow diagram in C.5) and is reset upon detecting a valid signal or when T7 times out. */ -#define DEFAULT_TIMER_T7 7000 - -/*! (Annex C - ISDN) Time-out T8 defines the amount of time waiting for clearance of the busy condition - of the receiving terminal. T8 is 10+-1s. The timeout begins on the first detection of the combination - of no outstanding corrections and the RNR response. T8 is reset when T8 times out or MCF response is - received. If the timer T8 expires, a DCN command is transmitted for call release. */ -#define DEFAULT_TIMER_T8 10000 - -/*! Final time we allow for things to flush through the system, before we disconnect, in milliseconds. - 200ms should be fine for a PSTN call. For a T.38 call something longer is desirable. This delay is - to allow sufficient time for the last message to be flushed all the way through to the far end. */ -#define FINAL_FLUSH_TIME 1000 - -/*! The number of PPRs received before CTC or EOR is sent in ECM mode. T.30 defines this as 4, - but it could be varied, and the Japanese spec, for example, does make this value a - variable. */ -#define PPR_LIMIT_BEFORE_CTC_OR_EOR 4 - -/* HDLC message header byte values */ -#define ADDRESS_FIELD 0xFF -#define CONTROL_FIELD_NON_FINAL_FRAME 0x03 -#define CONTROL_FIELD_FINAL_FRAME 0x13 - -enum -{ - TIMER_IS_IDLE = 0, - TIMER_IS_T2, - TIMER_IS_T1A, - TIMER_IS_T2_FLAGGED, - TIMER_IS_T2_DROPPED, - TIMER_IS_T2C, - TIMER_IS_T4, - TIMER_IS_T4_FLAGGED, - TIMER_IS_T4_DROPPED, - TIMER_IS_T4C -}; - -/* Start points in the fallback table for different capabilities */ -/*! The starting point in the modem fallback sequence if V.17 is allowed */ -#define T30_V17_FALLBACK_START 0 -/*! The starting point in the modem fallback sequence if V.17 is not allowed */ -#define T30_V29_FALLBACK_START 3 -/*! The starting point in the modem fallback sequence if V.29 is not allowed */ -#define T30_V27TER_FALLBACK_START 6 - -static const struct -{ - int bit_rate; - int modem_type; - int which; - uint8_t dcs_code; -} fallback_sequence[] = -{ - {14400, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 )}, - {12000, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT4 )}, - { 9600, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT3)}, - { 9600, T30_MODEM_V29, T30_SUPPORT_V29, ( DISBIT3)}, - { 7200, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT4 | DISBIT3)}, - { 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 )} -}; - -static void queue_phase(t30_state_t *s, int phase); -static void set_phase(t30_state_t *s, int phase); -static void set_state(t30_state_t *s, int state); -static void shut_down_hdlc_tx(t30_state_t *s); -static void send_frame(t30_state_t *s, const uint8_t *fr, int frlen); -static void send_simple_frame(t30_state_t *s, int type); -static void send_dcn(t30_state_t *s); -static void repeat_last_command(t30_state_t *s); -static void terminate_call(t30_state_t *s); -static void start_final_pause(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 send_cfr_sequence(t30_state_t *s, int start); -static int build_dcs(t30_state_t *s); -static void set_min_scan_time(t30_state_t *s); -static void timer_t2_start(t30_state_t *s); -static void timer_t2_flagged_start(t30_state_t *s); -static void timer_t2_dropped_start(t30_state_t *s); -static void timer_t4_start(t30_state_t *s); -static void timer_t4_flagged_start(t30_state_t *s); -static void timer_t4_dropped_start(t30_state_t *s); -static void timer_t2_t4_stop(t30_state_t *s); - -/*! Test a specified bit within a DIS, DTC or DCS frame */ -#define test_ctrl_bit(s,bit) ((s)[3 + ((bit - 1)/8)] & (1 << ((bit - 1)%8))) -/*! Set a specified bit within a DIS, DTC or DCS frame */ -#define set_ctrl_bit(s,bit) (s)[3 + ((bit - 1)/8)] |= (1 << ((bit - 1)%8)) -/*! Set a specified block of bits within a DIS, DTC or DCS frame */ -#define set_ctrl_bits(s,val,bit) (s)[3 + ((bit - 1)/8)] |= ((val) << ((bit - 1)%8)) -/*! 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; - /*endif*/ - } - /*endfor*/ - if (fallback_sequence[i].bit_rate == 0) - return -1; - /*endif*/ - 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; - /*endif*/ - } - /*endwhile*/ - if (fallback_sequence[s->current_fallback].bit_rate == 0) - { - /* Reset the fallback sequence */ - s->current_fallback = 0; - return -1; - } - /*endif*/ - /* 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 - already happened, repeating it here is harmless. */ - switch (s->operation_in_progress) - { - case OPERATION_IN_PROGRESS_T4_TX: - t4_tx_release(&s->t4.tx); - s->operation_in_progress = OPERATION_IN_PROGRESS_POST_T4_TX; - break; - case OPERATION_IN_PROGRESS_T4_RX: - t4_rx_release(&s->t4.rx); - s->operation_in_progress = OPERATION_IN_PROGRESS_POST_T4_RX; - break; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int tx_start_page(t30_state_t *s) -{ - if (t4_tx_start_page(&s->t4.tx)) - { - terminate_operation_in_progress(s); - return -1; - } - /*endif*/ - s->ecm_block = 0; - s->error_correcting_mode_retries = 0; - span_log(&s->logging, SPAN_LOG_FLOW, "Starting page %d of transfer\n", s->tx_page_number + 1); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int tx_end_page(t30_state_t *s) -{ - s->retries = 0; - if (t4_tx_end_page(&s->t4.tx) == 0) - { - s->tx_page_number++; - s->ecm_block = 0; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_start_page(t30_state_t *s) -{ - int i; - - t4_rx_set_image_width(&s->t4.rx, s->image_width); - t4_rx_set_sub_address(&s->t4.rx, s->rx_info.sub_address); - t4_rx_set_dcs(&s->t4.rx, s->rx_dcs_string); - t4_rx_set_far_ident(&s->t4.rx, s->rx_info.ident); - 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_compression); - t4_rx_set_x_resolution(&s->t4.rx, s->x_resolution); - t4_rx_set_y_resolution(&s->t4.rx, s->y_resolution); - - if (t4_rx_start_page(&s->t4.rx)) - return -1; - /*endif*/ - /* Clear the ECM buffer */ - for (i = 0; i < 256; i++) - s->ecm_len[i] = -1; - /*endfor*/ - s->ecm_block = 0; - s->ecm_frames = -1; - s->ecm_frames_this_tx_burst = 0; - s->error_correcting_mode_retries = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_end_page(t30_state_t *s) -{ - if (t4_rx_end_page(&s->t4.rx) == 0) - { - s->rx_page_number++; - s->ecm_block = 0; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void report_rx_ecm_page_result(t30_state_t *s) -{ - t4_stats_t stats; - - /* This is only used for ECM pages, as copy_quality() does a similar job for non-ECM - pages as a byproduct of assessing copy quality. */ - t4_rx_get_transfer_statistics(&s->t4.rx, &stats); - 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_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 --------------------------------------------------------*/ - -static int copy_quality(t30_state_t *s) -{ - t4_stats_t stats; - int quality; - - t4_rx_get_transfer_statistics(&s->t4.rx, &stats); - /* There is no specification for judging copy quality. However, we need to classify - it at three levels, to control what we do next: OK; tolerable, but retrain; - intolerable. */ - /* Based on the thresholds used in the TSB85 tests, we consider: - <5% bad rows is OK - <15% bad rows to be tolerable, but retrain - >15% bad rows to be intolerable - */ - /* This is called before the page is confirmed, so we need to add one to get the page - number right */ - 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_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); - /* Don't treat a page as perfect because it has zero bad rows out of zero total rows. A zero row - page has got to be some kind of total page failure. */ - if (stats.bad_rows == 0 && stats.length != 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Page quality is perfect\n"); - quality = T30_COPY_QUALITY_PERFECT; - } - else if (stats.bad_rows*20 < stats.length) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Page quality is good\n"); - quality = T30_COPY_QUALITY_GOOD; - } - else if (stats.bad_rows*20 < stats.length*3) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Page quality is poor\n"); - quality = T30_COPY_QUALITY_POOR; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Page quality is bad\n"); - quality = T30_COPY_QUALITY_BAD; - } - /*endif*/ - return quality; -} -/*- End of function --------------------------------------------------------*/ - -static void report_tx_result(t30_state_t *s, int result) -{ - t4_stats_t stats; - - if (span_log_test(&s->logging, SPAN_LOG_FLOW)) - { - t4_tx_get_transfer_statistics(&s->t4.tx, &stats); - span_log(&s->logging, - SPAN_LOG_FLOW, - "%s - delivered %d pages\n", - (result) ? "Success" : "Failure", - stats.pages_transferred); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void release_resources(t30_state_t *s) -{ - if (s->tx_info.nsf) - { - span_free(s->tx_info.nsf); - s->tx_info.nsf = NULL; - } - /*endif*/ - s->tx_info.nsf_len = 0; - if (s->tx_info.nsc) - { - span_free(s->tx_info.nsc); - s->tx_info.nsc = NULL; - } - /*endif*/ - s->tx_info.nsc_len = 0; - if (s->tx_info.nss) - { - span_free(s->tx_info.nss); - s->tx_info.nss = NULL; - } - /*endif*/ - s->tx_info.nss_len = 0; - if (s->tx_info.tsa) - { - span_free(s->tx_info.tsa); - s->tx_info.tsa = NULL; - } - /*endif*/ - if (s->tx_info.ira) - { - span_free(s->tx_info.ira); - s->tx_info.ira = NULL; - } - /*endif*/ - if (s->tx_info.cia) - { - span_free(s->tx_info.cia); - s->tx_info.cia = NULL; - } - /*endif*/ - if (s->tx_info.isp) - { - span_free(s->tx_info.isp); - s->tx_info.isp = NULL; - } - /*endif*/ - if (s->tx_info.csa) - { - span_free(s->tx_info.csa); - s->tx_info.csa = NULL; - } - /*endif*/ - - if (s->rx_info.nsf) - { - span_free(s->rx_info.nsf); - s->rx_info.nsf = NULL; - } - /*endif*/ - s->rx_info.nsf_len = 0; - if (s->rx_info.nsc) - { - span_free(s->rx_info.nsc); - s->rx_info.nsc = NULL; - } - /*endif*/ - s->rx_info.nsc_len = 0; - if (s->rx_info.nss) - { - span_free(s->rx_info.nss); - s->rx_info.nss = NULL; - } - /*endif*/ - s->rx_info.nss_len = 0; - if (s->rx_info.tsa) - { - span_free(s->rx_info.tsa); - s->rx_info.tsa = NULL; - } - /*endif*/ - if (s->rx_info.ira) - { - span_free(s->rx_info.ira); - s->rx_info.ira = NULL; - } - /*endif*/ - if (s->rx_info.cia) - { - span_free(s->rx_info.cia); - s->rx_info.cia = NULL; - } - /*endif*/ - if (s->rx_info.isp) - { - span_free(s->rx_info.isp); - s->rx_info.isp = NULL; - } - /*endif*/ - if (s->rx_info.csa) - { - span_free(s->rx_info.csa); - s->rx_info.csa = NULL; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static uint8_t check_next_tx_step(t30_state_t *s) -{ - int res; - int more; - - res = t4_tx_next_page_has_different_format(&s->t4.tx); - if (res == 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "More pages to come with the same format\n"); - return (s->local_interrupt_pending) ? T30_PRI_MPS : T30_MPS; - } - /*endif*/ - if (res > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "More pages to come with a different format\n"); - s->tx_start_page = t4_tx_get_current_page_in_file(&s->t4.tx) + 1; - return (s->local_interrupt_pending) ? T30_PRI_EOM : T30_EOM; - } - /*endif*/ - /* Call a user handler, if one is set, to check if another document is to be sent. - If so, we send an EOM, rather than an EOP. Then we will renegotiate, and the new - document will begin. */ - if (s->document_handler) - more = s->document_handler(s->document_user_data, 0); - else - more = false; - /*endif*/ - 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; - ///*endif*/ - return (s->local_interrupt_pending) ? T30_PRI_EOM : T30_EOM; - } - /*endif*/ - 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 --------------------------------------------------------*/ - -static int get_partial_ecm_page(t30_state_t *s) -{ - int i; - int len; - - s->ppr_count = 0; - s->ecm_progress = 0; - /* Fill our partial page buffer with a partial page. Use the negotiated preferred frame size - as the basis for the size of the frames produced. */ - /* We fill the buffer with complete HDLC frames, ready to send out. */ - /* The frames are all marked as not being final frames. When sent, the are followed by a partial - page signal, which is marked as the final frame. */ - for (i = 3; i < 32 + 3; i++) - s->ecm_frame_map[i] = 0xFF; - /*endfor*/ - for (i = 0; i < 256; i++) - { - s->ecm_len[i] = -1; - s->ecm_data[i][0] = ADDRESS_FIELD; - s->ecm_data[i][1] = CONTROL_FIELD_NON_FINAL_FRAME; - s->ecm_data[i][2] = T4_FCD; - /* 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 (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); - /*endif*/ - if (len < s->octets_per_ecm_frame) - { - /* 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) - { - memset(&s->ecm_data[i][4 + len], 0, s->octets_per_ecm_frame - len); - s->ecm_len[i++] = (int16_t) (s->octets_per_ecm_frame + 4); - } - /*endif*/ - s->ecm_frames = i; - 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; - } - /*endif*/ - s->ecm_len[i] = (int16_t) (4 + len); - } - /*endfor*/ - /* We filled the entire buffer */ - s->ecm_frames = 256; - span_log(&s->logging, SPAN_LOG_FLOW, "Partial page buffer full (%d per frame)\n", s->octets_per_ecm_frame); - s->ecm_at_page_end = (t4_tx_image_complete(&s->t4.tx) == SIG_STATUS_END_OF_DATA); - return 256; -} -/*- End of function --------------------------------------------------------*/ - -static int send_next_ecm_frame(t30_state_t *s) -{ - int i; - uint8_t frame[3]; - - if (s->ecm_current_tx_frame < s->ecm_frames) - { - /* Search for the next frame, within the current partial page, which has - not been tagged as transferred OK. */ - for (i = s->ecm_current_tx_frame; i < s->ecm_frames; i++) - { - if (s->ecm_len[i] >= 0) - { - send_frame(s, s->ecm_data[i], s->ecm_len[i]); - s->ecm_current_tx_frame = i + 1; - s->ecm_frames_this_tx_burst++; - return 0; - } - /*endif*/ - } - /*endfor*/ - s->ecm_current_tx_frame = s->ecm_frames; - } - /*endif*/ - if (s->ecm_current_tx_frame < s->ecm_frames + 3) - { - /* We have sent all the FCD frames. Send three RCP frames, as per - T.4/A.1 and T.4/A.2. The repeats are to minimise the risk of a bit - error stopping the receiving end from recognising the RCP. */ - s->ecm_current_tx_frame++; - /* The RCP frame is an odd man out, as its a simple 1 byte control - frame, but is specified to not have the final bit set. It doesn't - seem to have the DIS received bit set, either. */ - frame[0] = ADDRESS_FIELD; - frame[1] = CONTROL_FIELD_NON_FINAL_FRAME; - frame[2] = T4_RCP; - 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; - return 0; - } - /*endif*/ - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static void send_rr(t30_state_t *s) -{ - if (s->current_status != T30_ERR_TX_T5EXP) - send_simple_frame(s, T30_RR); - else - send_dcn(s); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int send_first_ecm_frame(t30_state_t *s) -{ - s->ecm_current_tx_frame = 0; - s->ecm_frames_this_tx_burst = 0; - return send_next_ecm_frame(s); -} -/*- End of function --------------------------------------------------------*/ - -static void print_frame(t30_state_t *s, const char *io, const uint8_t *msg, int len) -{ - span_log(&s->logging, - SPAN_LOG_FLOW, - "%s %s with%s final frame tag\n", - io, - t30_frametype(msg[2]), - (msg[1] & 0x10) ? "" : "out"); - span_log_buf(&s->logging, SPAN_LOG_FLOW, io, msg, len); -} -/*- End of function --------------------------------------------------------*/ - -static void shut_down_hdlc_tx(t30_state_t *s) -{ - if (s->send_hdlc_handler) - s->send_hdlc_handler(s->send_hdlc_user_data, NULL, 0); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -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->real_time_frame_user_data, false, msg, len); - /*endif*/ - if (s->send_hdlc_handler) - s->send_hdlc_handler(s->send_hdlc_user_data, msg, len); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void send_simple_frame(t30_state_t *s, int type) -{ - uint8_t frame[3]; - - /* The simple command/response frames are always final frames */ - frame[0] = ADDRESS_FIELD; - frame[1] = CONTROL_FIELD_FINAL_FRAME; - frame[2] = (uint8_t) (type | s->dis_received); - send_frame(s, frame, 3); -} -/*- End of function --------------------------------------------------------*/ - -static void send_20digit_msg_frame(t30_state_t *s, int cmd, char *msg) -{ - size_t len; - int p; - uint8_t frame[23]; - - len = strlen(msg); - p = 0; - frame[p++] = ADDRESS_FIELD; - frame[p++] = CONTROL_FIELD_NON_FINAL_FRAME; - frame[p++] = (uint8_t) (cmd | s->dis_received); - while (len > 0) - frame[p++] = msg[--len]; - /*endwhile*/ - while (p < 23) - frame[p++] = ' '; - /*endwhile*/ - send_frame(s, frame, 23); -} -/*- End of function --------------------------------------------------------*/ - -static int send_nsf_frame(t30_state_t *s) -{ - /* Only send if there is an NSF message to send. */ - if (s->tx_info.nsf && s->tx_info.nsf_len) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Sending user supplied NSF - %d octets\n", s->tx_info.nsf_len); - s->tx_info.nsf[0] = ADDRESS_FIELD; - s->tx_info.nsf[1] = CONTROL_FIELD_NON_FINAL_FRAME; - s->tx_info.nsf[2] = T30_NSF; - send_frame(s, s->tx_info.nsf, s->tx_info.nsf_len + 3); - return true; - } - /*endif*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_nss_frame(t30_state_t *s) -{ - /* Only send if there is an NSF message to send. */ - if (s->tx_info.nss && s->tx_info.nss_len) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Sending user supplied NSS - %d octets\n", s->tx_info.nss_len); - s->tx_info.nss[0] = ADDRESS_FIELD; - 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; - } - /*endif*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_nsc_frame(t30_state_t *s) -{ - /* Only send if there is an NSF message to send. */ - if (s->tx_info.nsc && s->tx_info.nsc_len) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Sending user supplied NSC - %d octets\n", s->tx_info.nsc_len); - s->tx_info.nsc[0] = ADDRESS_FIELD; - s->tx_info.nsc[1] = CONTROL_FIELD_NON_FINAL_FRAME; - s->tx_info.nsc[2] = T30_NSC; - send_frame(s, s->tx_info.nsc, s->tx_info.nsc_len + 3); - return true; - } - /*endif*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_ident_frame(t30_state_t *s, uint8_t cmd) -{ - if (s->tx_info.ident[0]) - { - 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; - } - /*endif*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_psa_frame(t30_state_t *s) -{ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE) && s->tx_info.polled_sub_address[0]) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_sep_frame(t30_state_t *s) -{ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE) && s->tx_info.selective_polling_address[0]) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_sid_frame(t30_state_t *s) -{ - /* Only send if there is an ID to send. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_PASSWORD) && s->tx_info.sender_ident[0]) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SENDER_ID_TRANSMISSION); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_pwd_frame(t30_state_t *s) -{ - /* Only send if there is a password to send. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_PASSWORD) && s->tx_info.password[0]) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_sub_frame(t30_state_t *s) -{ - /* Only send if there is a sub-address to send. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SUBADDRESSING_CAPABLE) && s->tx_info.sub_address[0]) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SUBADDRESS_TRANSMISSION); - return false; -} -/*- End of function --------------------------------------------------------*/ - -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; - } - /*endif*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_ira_frame(t30_state_t *s) -{ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INTERNET_ROUTING_ADDRESS) && 0) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION); - return false; -} -/*- End of function --------------------------------------------------------*/ - -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; - } - /*endif*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_isp_frame(t30_state_t *s) -{ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS) && 0) - { - 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; - } - /*endif*/ - clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); - return false; -} -/*- End of function --------------------------------------------------------*/ - -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; - } - /*endif*/ -#endif - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int send_pps_frame(t30_state_t *s) -{ - uint8_t frame[7]; - - frame[0] = ADDRESS_FIELD; - frame[1] = CONTROL_FIELD_FINAL_FRAME; - frame[2] = (uint8_t) (T30_PPS | s->dis_received); - frame[3] = (s->ecm_at_page_end) ? ((uint8_t) (s->next_tx_step | s->dis_received)) : T30_NULL; - frame[4] = (uint8_t) (s->tx_page_number & 0xFF); - frame[5] = (uint8_t) (s->ecm_block & 0xFF); - frame[6] = (uint8_t) ((s->ecm_frames_this_tx_burst == 0) ? 0 : (s->ecm_frames_this_tx_burst - 1)); - span_log(&s->logging, SPAN_LOG_FLOW, "Sending PPS-%s\n", t30_frametype(frame[3])); - send_frame(s, frame, 7); - return frame[3] & 0xFE; -} -/*- 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; - /*endfor*/ - - /* 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); - /*endif*/ - if ((s->iaf & T30_IAF_MODE_T38)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38); - /*endif*/ - /* 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); - /*endif*/ - if ((s->supported_modems & T30_SUPPORT_V29)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_MODEM_TYPE_1); - /*endif*/ - /* 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); - /*endif*/ - - /* 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); - /*endif*/ - - /* 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); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - - /* 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); - /*endif*/ - if ((s->supported_compressions & T4_COMPRESSION_NONE)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNCOMPRESSED_CAPABLE); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - } - /*endif*/ - - //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); - //} - ///*endif*/ - - 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); - /*endif*/ - - if ((s->supported_compressions & T4_COMPRESSION_T42_T81)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); - /*endif*/ - 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 */ - } - /*endif*/ - if ((s->supported_compressions & T4_COMPRESSION_T45)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE); - /*endif*/ - 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); - } - /*endif*/ - - if ((s->supported_compressions & T4_COMPRESSION_12BIT)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE); - /*endif*/ - - if ((s->supported_compressions & T4_COMPRESSION_NO_SUBSAMPLING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING); - /*endif*/ - - /* No custom illuminant */ - /* No custom gamut range */ - } - /*endif*/ - } - /*endif*/ - if ((s->supported_t30_features & T30_SUPPORT_FIELD_NOT_VALID)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FNV_CAPABLE); - /*endif*/ - 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); - /*endif*/ - if ((s->supported_t30_features & T30_SUPPORT_POLLED_SUB_ADDRESSING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); - /*endif*/ - if ((s->supported_t30_features & T30_SUPPORT_SELECTIVE_POLLING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); - /*endif*/ - if ((s->supported_t30_features & T30_SUPPORT_SUB_ADDRESSING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SUBADDRESSING_CAPABLE); - /*endif*/ - if ((s->supported_t30_features & T30_SUPPORT_IDENTIFICATION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); - /*endif*/ - - /* 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); - /*endif*/ - - /* 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); - /*endif*/ - if ((s->supported_t30_features & T30_SUPPORT_INTERNET_ROUTING_ADDRESS)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_ROUTING_ADDRESS); - /*endif*/ - - 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); - /*endif*/ - } - /*endif*/ - if ((s->supported_bilevel_resolutions & T4_RESOLUTION_600_1200)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE); - /*endif*/ - 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); - /*endif*/ - } - /*endif*/ - if ((s->supported_bilevel_resolutions & T4_RESOLUTION_400_800)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE); - /*endif*/ - if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R16_SUPERFINE)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE); - /*endif*/ - 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); - /*endif*/ - } - /*endif*/ - if ((s->supported_bilevel_resolutions & T4_RESOLUTION_300_600)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE); - /*endif*/ - 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); - /*endif*/ - } - /*endif*/ - 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); - /*endif*/ - if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R8_FINE)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE); - /*endif*/ - 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); - /*endif*/ - } - /*endif*/ - /* 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); - /*endif*/ - - 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); - /*endif*/ - 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); - /*endif*/ - - /* 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); - /*endif*/ - /* 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); - /*endif*/ - /* 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. - We just need to edit the prebuilt message. */ - s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received); - /* If we have a file name to receive into, then we are receive capable */ - if (s->rx_file[0]) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT); - else - clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT); - /*endif*/ - /* If we have a file name to transmit, then we are ready to transmit (polling) */ - if (s->tx_file[0]) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT); - else - clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT); - /*endif*/ - 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 = 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); - /* Check if there is some real message content here */ - if (s->local_dis_dtc_frame[i]) - break; - /*endif*/ - } - /*endfor*/ - s->local_dis_dtc_len = i + 1; - /* Fill in any required extension bits */ - s->local_dis_dtc_frame[i] &= ~DISBIT8; - for (i--; i > 4; i--) - s->local_dis_dtc_frame[i] |= DISBIT8; - /*endfor*/ - t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); - return s->local_dis_dtc_len; -} -/*- End of function --------------------------------------------------------*/ - -static int build_dcs(t30_state_t *s) -{ - int i; - int use_bilevel; - int image_type; - - /* 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 < T30_MAX_DIS_DTC_DCS_LEN; i++) - s->dcs_frame[i] = 0x00; - /*endfor*/ - - /* 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 ((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); - /*endif*/ - /* Check for T.38 mode. */ - 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*/ -#endif - - /* Set to required modem rate */ - s->dcs_frame[4] |= fallback_sequence[s->current_fallback].dcs_code; - - /* Select the compression to use. */ - 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_T4_1D: - /* There is nothing to set to select this encoding. */ - break; - 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_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); - /*endif*/ - 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); - /*endif*/ - //if (???????? & T4_COMPRESSION_NO_SUBSAMPLING)) - // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING); - ///*endif*/ - //if (???????? & T4_COMPRESSION_?????)) - // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_PREFERRED_HUFFMAN_TABLES); - ///*endif*/ - 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_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); - /*endif*/ - 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); - /*endif*/ - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); - use_bilevel = false; - break; -#if defined(SPANDSP_SUPPORT_T45) - case T4_COMPRESSION_T45: - use_bilevel = false; - break; -#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, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); - break; - } - /*endswitch*/ - - /* Set the image width */ - switch (s->line_width_code) - { - 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. */ - 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; - } - /*endswitch*/ - - /* 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 ((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); - /*endif*/ - - /* 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); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - 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; - } - /*endswitch*/ - - if (s->error_correcting_mode) - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM_MODE); - /*endif*/ - - 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); - /*endif*/ - - 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, 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); - } - /*endif*/ - s->dcs_len = 19; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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 = 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); - /* Check if there is some real message content here */ - if (s->dcs_frame[i]) - break; - /*endif*/ - } - /*endfor*/ - s->dcs_len = i + 1; - /* Fill in any required extension bits */ - s->local_dis_dtc_frame[i] &= ~DISBIT8; - for (i-- ; i > 4; i--) - s->dcs_frame[i] |= DISBIT8; - /*endfor*/ - t30_decode_dis_dtc_dcs(s, s->dcs_frame, s->dcs_len); - return s->dcs_len; -} -/*- End of function --------------------------------------------------------*/ - -static int analyze_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) -{ - t30_decode_dis_dtc_dcs(s, msg, len); - if (len < 6) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Short DIS/DTC frame\n"); - return -1; - } - /*endif*/ - - if (msg[2] == T30_DIS) - s->dis_received = true; - /*endif*/ - - /* 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; - /*endif*/ - 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); - /*endif*/ - - 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; - /*endif*/ - } - 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; - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) - s->mutual_compressions &= ~T4_COMPRESSION_T6; - /*endif*/ - /* 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); - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE)) - s->mutual_compressions &= ~T4_COMPRESSION_T85_L0; - /*endif*/ - - /* 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; - /*endif*/ - - /* 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; - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE)) - s->mutual_compressions &= ~T4_COMPRESSION_SYCC_T81; - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE)) - s->mutual_compressions &= ~T4_COMPRESSION_T43; - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE)) - s->mutual_compressions &= ~T4_COMPRESSION_T45; - /*endif*/ - - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) - s->mutual_compressions &= ~T4_COMPRESSION_12BIT; - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING)) - s->mutual_compressions &= ~T4_COMPRESSION_NO_SUBSAMPLING; - /*endif*/ - - /* bit74 custom illuminant */ - /* bit75 custom gamut range */ - } - /*endif*/ - - 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; - /*endif*/ - } - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE)) - s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_600_1200; - /*endif*/ - 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; - /*endif*/ - } - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE)) - s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_400_800; - /*endif*/ - 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; - /*endif*/ - } - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE)) - s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_300_600; - /*endif*/ - 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; - /*endif*/ - } - /*endif*/ - 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); - /*endif*/ - 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; - } - /*endif*/ - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED)) - s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_200_100; - /*endif*/ - /* 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; - /*endif*/ - - 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; - /*endif*/ - } - /*endif*/ - /* 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; - /*endif*/ - } - /*endif*/ - 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; - /*endif*/ - 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; - /*endif*/ - - 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; - } - /*endif*/ - /* 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; - } - /*endif*/ - /* 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; - } - /*endif*/ - /* 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; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) -{ - /* 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] = - { - { 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; - } - /*endif*/ - - /* 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])); - /*endfor*/ - - /* 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; - /*endif*/ - 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); - /*endif*/ - - 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 */ - } - /*endif*/ - } - /*endif*/ - - 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 */ - } - /*endif*/ - } - /*endif*/ - - if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING)) - { - //???? = T4_COMPRESSION_NO_SUBSAMPLING; - } - /*endif*/ - - if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_PREFERRED_HUFFMAN_TABLES)) - { - //???? = T4_COMPRESSION_T42_T81_HUFFMAN; - } - /*endif*/ - - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - /*endif*/ - - /* 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; - /*endif*/ - } - 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; - /*endif*/ - } - 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; - /*endif*/ - } - 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; - /*endif*/ - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - /*endif*/ - } - 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; - } - /*endif*/ - } - 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; - } - /*endif*/ - } - /*endif*/ - } - 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; - } - /*endif*/ - } - /*endif*/ - - /* 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; - /*endif*/ - } - /*endif*/ - 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; - /*endif*/ - } - 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; - /*endif*/ - } - 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; - /*endif*/ - } - 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; - /*endif*/ - } - else - { - if ((s->supported_compressions & T4_COMPRESSION_T4_1D)) - s->line_compression = T4_COMPRESSION_T4_1D; - /*endif*/ - } - /*endif*/ - } - /*endif*/ - - if (s->line_compression == -1) - { - t30_set_status(s, T30_ERR_INCOMPATIBLE); - return -1; - } - /*endif*/ - 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; - } - /*endif*/ - - 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"); - /*endif*/ - - 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; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void send_dcn(t30_state_t *s) -{ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_C); - send_simple_frame(s, T30_DCN); -} -/*- End of function --------------------------------------------------------*/ - -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. */ - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Returning to phase B\n"); - /* Run the T1 timer, like we do on first detecting the far end. */ - s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T1); - set_state(s, (s->calling_party) ? T30_STATE_T : T30_STATE_R); -} -/*- End of function --------------------------------------------------------*/ - -static int send_dis_or_dtc_sequence(t30_state_t *s, int start) -{ - /* (NSF) (CSI) DIS */ - /* (NSC) (CIG) (PWD) (SEP) (PSA) (CIA) (ISP) DTC */ - if (start) - { - set_dis_or_dtc(s); - set_state(s, T30_STATE_R); - s->step = 0; - } - /*endif*/ - if (!s->dis_received) - { - /* DIS sequence */ - switch (s->step) - { - case 0: - s->step++; - if (send_nsf_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 1: - s->step++; - if (send_ident_frame(s, T30_CSI)) - break; - /*endif*/ - /* Fall through */ - case 2: - s->step++; - prune_dis_dtc(s); - send_frame(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); - break; - case 3: - s->step++; - shut_down_hdlc_tx(s); - break; - default: - return -1; - } - /*endswitch*/ - } - else - { - /* DTC sequence */ - switch (s->step) - { - case 0: - s->step++; - if (send_nsc_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 1: - s->step++; - if (send_ident_frame(s, T30_CIG)) - break; - /*endif*/ - /* Fall through */ - case 2: - s->step++; - if (send_pwd_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 3: - s->step++; - if (send_sep_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 4: - s->step++; - if (send_psa_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 5: - s->step++; - if (send_cia_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 6: - s->step++; - if (send_isp_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 7: - s->step++; - prune_dis_dtc(s); - send_frame(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); - break; - case 8: - s->step++; - shut_down_hdlc_tx(s); - break; - default: - return -1; - } - /*endswitch*/ - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int send_dcs_sequence(t30_state_t *s, int start) -{ - /* (NSS) (TSI) (SUB) (SID) (TSA) (IRA) DCS */ - /* Schedule training after the messages */ - if (start) - { - set_state(s, T30_STATE_D); - s->step = 0; - } - /*endif*/ - switch (s->step) - { - case 0: - s->step++; - if (send_nss_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 1: - s->step++; - if (send_ident_frame(s, T30_TSI)) - break; - /*endif*/ - /* Fall through */ - case 2: - s->step++; - if (send_sub_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 3: - s->step++; - if (send_sid_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 4: - s->step++; - if (send_tsa_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 5: - s->step++; - if (send_ira_frame(s)) - break; - /*endif*/ - /* Fall through */ - case 6: - s->step++; - prune_dcs(s); - send_frame(s, s->dcs_frame, s->dcs_len); - break; - case 7: - s->step++; - shut_down_hdlc_tx(s); - break; - default: - return -1; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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. */ - if (start) - s->step = 0; - /*endif*/ - switch (s->step) - { - case 0: - s->step++; - if (send_csa_frame(s)) - break; - /*endif*/ - /* 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; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void terminate_call(t30_state_t *s) -{ - /* Make sure any FAX in progress is tidied up. If the tidying up has - already happened, repeating it here is harmless. */ - terminate_operation_in_progress(s); - s->timer_t0_t1 = 0; - s->timer_t2_t4 = 0; - s->timer_t3 = 0; - s->timer_t5 = 0; - if (s->phase_e_handler) - s->phase_e_handler(s->phase_e_user_data, s->current_status); - /*endif*/ - set_state(s, T30_STATE_CALL_FINISHED); - set_phase(s, T30_PHASE_CALL_FINISHED); - release_resources(s); - span_log(&s->logging, SPAN_LOG_FLOW, "Call completed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void start_final_pause(t30_state_t *s) -{ - /* We need to allow some time for the last part of our FAX signalling to flush through - to the far end before we declare the call finished. If we say it is finished too soon, - the call disconnect message could cause buffers downstream to be flushed, rather than - played out to completion. If that clips the final message, the far end might declare - that the call prematrurely terminated. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Starting final pause before disconnecting\n"); - /* Make sure any FAX in progress is tidied up. If the tidying up has - already happened, repeating it here is harmless. */ - terminate_operation_in_progress(s); - s->timer_t0_t1 = 0; - s->timer_t2_t4 = 0; - s->timer_t3 = 0; - s->timer_t5 = 0; - set_phase(s, T30_PHASE_E); - set_state(s, T30_STATE_B); -} -/*- End of function --------------------------------------------------------*/ - -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. */ - static const uint8_t translate_min_scan_time[3][8] = - { - /* Normal */ - {T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_0MS}, - /* Fine */ - {T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_40MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_0MS}, - /* Superfine, when half fine time is selected */ - {T30_MIN_SCAN_10MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_20MS, T30_MIN_SCAN_10MS, T30_MIN_SCAN_5MS, T30_MIN_SCAN_0MS} - }; - /* Translation between the codes for the minimum scan time we will use, and milliseconds. */ - static const int min_scan_times[8] = - { - 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) - min_bits_field = T30_MIN_SCAN_0MS; - else - min_bits_field = (s->far_dis_dtc_frame[5] >> 4) & 7; - /*endif*/ - switch (s->y_resolution) - { - case T4_Y_RESOLUTION_SUPERFINE: - 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: - 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; - } - /*endswitch*/ - 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; - /*endif*/ - 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 res; - - if (s->tx_file[0] == '\0') - { - /* There is nothing to send */ - span_log(&s->logging, SPAN_LOG_FLOW, "No document to send\n"); - return -1; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Start sending document\n"); - if (t4_tx_init(&s->t4.tx, s->tx_file, s->tx_start_page, s->tx_stop_page) == NULL) - { - span_log(&s->logging, SPAN_LOG_WARNING, "Cannot open source TIFF file '%s'\n", s->tx_file); - t30_set_status(s, T30_ERR_FILEERROR); - return -1; - } - /*endif*/ - s->operation_in_progress = OPERATION_IN_PROGRESS_T4_TX; - - 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); - /*endif*/ - - t4_tx_get_pages_in_file(&s->t4.tx); - - 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) - { - 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; - } - /*endswitch*/ - return -1; - } - /*endif*/ - 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; - } - /*endif*/ - - if (s->error_correcting_mode) - { - if (get_partial_ecm_page(s) == 0) - span_log(&s->logging, SPAN_LOG_WARNING, "No image data to send\n"); - /*endif*/ - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int start_receiving_document(t30_state_t *s) -{ - if (s->rx_file[0] == '\0') - { - /* There is nothing to receive to */ - span_log(&s->logging, SPAN_LOG_FLOW, "No document to receive\n"); - return -1; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Start receiving document\n"); - s->ecm_block = 0; - send_dis_or_dtc_sequence(s, true); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void unexpected_non_final_frame(t30_state_t *s, const uint8_t *msg, int len) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame in state %s\n", t30_frametype(msg[2]), state_names[s->state]); - if (s->current_status == T30_ERR_OK) - t30_set_status(s, T30_ERR_UNEXPECTED); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void unexpected_final_frame(t30_state_t *s, const uint8_t *msg, int len) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame in state %s\n", t30_frametype(msg[2]), state_names[s->state]); - if (s->current_status == T30_ERR_OK) - t30_set_status(s, T30_ERR_UNEXPECTED); - /*endif*/ - send_dcn(s); -} -/*- End of function --------------------------------------------------------*/ - -static void unexpected_frame_length(t30_state_t *s, const uint8_t *msg, int len) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len); - if (s->current_status == T30_ERR_OK) - t30_set_status(s, T30_ERR_UNEXPECTED); - /*endif*/ - send_dcn(s); -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) -{ - int new_status; - - queue_phase(s, T30_PHASE_B_TX); - if (analyze_rx_dis_dtc(s, msg, len) < 0) - { - send_dcn(s); - return -1; - } - /*endif*/ - if (s->phase_b_handler) - { - new_status = s->phase_b_handler(s->phase_b_user_data, msg[2]); - if (new_status != T30_ERR_OK) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Application rejected DIS/DTC - '%s'\n", t30_completion_code_to_str(new_status)); - t30_set_status(s, new_status); - /* TODO: If FNV is allowed, process it here */ - send_dcn(s); - return -1; - } - /*endif*/ - } - /*endif*/ - /* Try to send something */ - if (s->tx_file[0]) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Trying to send file '%s'\n", s->tx_file); - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT)) - { - 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; - } - /*endif*/ - if (start_sending_document(s)) - { - send_dcn(s); - return -1; - } - /*endif*/ - if (build_dcs(s)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "The far end is incompatible\n", s->tx_file); - send_dcn(s); - return -1; - } - /*endif*/ - /* 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); - return 0; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "%s - nothing to send\n", t30_frametype(msg[2])); - /* ... then try to receive something */ - if (s->rx_file[0]) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Trying to receive file '%s'\n", s->rx_file); - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot transmit\n", t30_frametype(msg[2])); - t30_set_status(s, T30_ERR_TX_INCAPABLE); - send_dcn(s); - return -1; - } - /*endif*/ - if (start_receiving_document(s)) - { - send_dcn(s); - return -1; - } - /*endif*/ - if (set_dis_or_dtc(s)) - { - t30_set_status(s, T30_ERR_INCOMPATIBLE); - send_dcn(s); - return -1; - } - /*endif*/ - s->retries = 0; - send_dis_or_dtc_sequence(s, true); - return 0; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "%s - nothing to receive\n", t30_frametype(msg[2])); - /* There is nothing to do, or nothing we are able to do. */ - send_dcn(s); - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) -{ - int new_status; - - if (analyze_rx_dcs(s, msg, len) < 0) - { - send_dcn(s); - return -1; - } - /*endif*/ - - if (s->phase_b_handler) - { - new_status = s->phase_b_handler(s->phase_b_user_data, msg[2]); - if (new_status != T30_ERR_OK) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Application rejected DCS - '%s'\n", t30_completion_code_to_str(new_status)); - t30_set_status(s, new_status); - /* TODO: If FNV is allowed, process it here */ - send_dcn(s); - return -1; - } - /*endif*/ - } - /*endif*/ - /* Start document reception */ - span_log(&s->logging, - SPAN_LOG_FLOW, - "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"); - t30_set_status(s, T30_ERR_FILEERROR); - send_dcn(s); - return -1; - } - /*endif*/ - if (s->operation_in_progress != OPERATION_IN_PROGRESS_T4_RX) - { - 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); - send_dcn(s); - return -1; - } - /*endif*/ - s->operation_in_progress = OPERATION_IN_PROGRESS_T4_RX; - } - /*endif*/ - if (!(s->iaf & T30_IAF_MODE_NO_TCF)) - { - /* TCF is always sent with long training */ - s->short_train = false; - set_state(s, T30_STATE_F_TCF); - queue_phase(s, T30_PHASE_C_NON_ECM_RX); - timer_t2_start(s); - } - /*endif*/ - return 0; -} -/*- 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); - /*endif*/ - break; - } - /*endswitch*/ - - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (fcf == T30_EOP) - terminate_operation_in_progress(s); - else - rx_start_page(s); - /*endif*/ - - switch (quality) - { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - s->last_rx_page_result = T30_MCF; - break; - case T30_COPY_QUALITY_POOR: - s->last_rx_page_result = T30_RTP; - break; - case T30_COPY_QUALITY_BAD: - default: - s->last_rx_page_result = T30_RTN; - break; - } - /*endswitch*/ - set_state(s, T30_STATE_III_Q); - send_simple_frame(s, s->last_rx_page_result); -} -/*- End of function --------------------------------------------------------*/ - -static int send_response_to_pps(t30_state_t *s) -{ - queue_phase(s, T30_PHASE_D_TX); - if (s->rx_ecm_block_ok) - { - set_state(s, T30_STATE_F_POST_RCP_MCF); - send_simple_frame(s, T30_MCF); - return true; - } - /*endif*/ - /* 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); - s->ecm_frame_map[0] = ADDRESS_FIELD; - 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; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) -{ - int page; - int block; - int frames; - int i; - int j; - int frame_no; - int first_bad_frame; - int first; - int expected_len; - int res; - - if (len < 7) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad PPS message length %d.\n", len); - return -1; - } - /*endif*/ - s->last_pps_fcf2 = msg[3] & 0xFE; - - /* The frames count is not well specified in T.30. In practice it seems it might be the - number of frames in the current block, or it might be the number of frames in the - current burst of transmission. For a burst of resent frames this would make it smaller - than the actual size of the block. If we only accept the number when it exceeds - previous values, we should get the real number of frames in the block. */ - frames = msg[6] + 1; - block = msg[5]; - page = msg[4]; - - if (s->ecm_frames < 0) - { - /* First time. Take the number and believe in it. */ - s->ecm_frames = frames; - } - else - { - /* If things have gone wrong, the far end might try to send us zero FCD - frames. It can't represent zero in the block count field, so it might - put zero there, or it might simplistically insert (blocks - 1), and put - 0xFF there. Beware of this. */ - if (frames == 0xFF) - { - /* This is probably zero, erroneously rolled over to the maximum count */ - frames = 0; - } - /*endif*/ - } - /*endif*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "Received PPS-%s - page %d, block %d, %d frames\n", - t30_frametype(msg[3]), - page, - block, - frames); - /* Check that we have received the page and block we expected. If the far end missed - our last response, it might have repeated the previous chunk. */ - if ((s->rx_page_number & 0xFF) != page || (s->ecm_block & 0xFF) != block) - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "ECM rx page/block mismatch - expected %d/%d, but received %d/%d.\n", - (s->rx_page_number & 0xFF), - (s->ecm_block & 0xFF), - page, - block); - /* Look for this being a repeat, because the other end missed the last response - we sent - which would have been a T30_MCF - If the block is for the previous - page, or the previous block of the current page, we can assume we have hit this - condition. */ - if (((s->rx_page_number & 0xFF) == page && ((s->ecm_block - 1) & 0xFF) == block) - || - (((s->rx_page_number - 1) & 0xFF) == page && s->ecm_block == 0)) - { - /* This must be a repeat of the last thing the far end sent, while we are expecting - the first transfer of a new block. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Looks like a repeat from the previous page/block - send MCF again.\n"); - /* Clear the ECM buffer */ - for (i = 0; i < 256; i++) - s->ecm_len[i] = -1; - /*endfor*/ - s->ecm_frames = -1; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_F_POST_RCP_MCF); - send_simple_frame(s, T30_MCF); - } - else - { - /* Give up */ - t30_set_status(s, T30_ERR_RX_ECMPHD); - send_dcn(s); - } - /*endif*/ - return 0; - } - /*endif*/ - - /* Build a bit map of which frames we now have stored OK */ - first_bad_frame = 256; - first = true; - expected_len = 256; - for (i = 0; i < 32; i++) - { - s->ecm_frame_map[i + 3] = 0; - for (j = 0; j < 8; j++) - { - frame_no = (i << 3) + j; - if (s->ecm_len[frame_no] >= 0) - { - /* The correct pattern of frame lengths is they will all be 64 or 256 octets long, except the - last one. The last one might the same length as all the others, or it might be exactly the - right length to contain the last chunk of the data. That is, some people pad at the end, - and some do not. */ - /* Vet the frames which are present, to detect any with inappropriate lengths. This might seem - like overkill, as the frames must have had good CRCs to get this far. However, in the real - world there are systems, especially T.38 ones, which give bad frame lengths, and which screw - up communication unless you apply these checks. From experience, if you find a frame has a - suspect length, and demand retransmission, there is a good chance the new copy will be alright. */ - if (frame_no < s->ecm_frames - 1) - { - /* Expect all frames, except the last one, to follow the length of the first one */ - if (first) - { - /* 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; - /*endif*/ - first = false; - } - /*endif*/ - /* Check the length is consistent with the first frame */ - if (s->ecm_len[frame_no] != expected_len) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length ECM frame - %d\n", s->ecm_len[frame_no]); - s->ecm_len[frame_no] = -1; - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ - if (s->ecm_len[frame_no] < 0) - { - s->ecm_frame_map[i + 3] |= (1 << j); - if (frame_no < first_bad_frame) - first_bad_frame = frame_no; - /*endif*/ - if (frame_no < s->ecm_frames) - s->error_correcting_mode_retries++; - /*endif*/ - } - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - s->rx_ecm_block_ok = (first_bad_frame >= s->ecm_frames); - 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 (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]); - /*endif*/ - 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; - } - /*endif*/ - } - /*endfor*/ - /* Clear the ECM buffer */ - for (i = 0; i < 256; i++) - s->ecm_len[i] = -1; - /*endfor*/ - s->ecm_block++; - s->ecm_frames = -1; - - switch (s->last_pps_fcf2) - { - case T30_NULL: - /* We can accept only this partial page. */ - break; - default: - /* We can accept and confirm the whole page. */ - s->next_rx_step = s->last_pps_fcf2; - rx_end_page(s); - report_rx_ecm_page_result(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, s->last_pps_fcf2); - /*endif*/ - rx_start_page(s); - break; - } - /*endswitch*/ - } - /*endif*/ - - switch (s->last_pps_fcf2) - { - case T30_PRI_MPS: - case T30_PRI_EOM: - case T30_PRI_EOP: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_NULL: - case T30_MPS: - case T30_EOM: - case T30_EOS: - case T30_EOP: - if (s->receiver_not_ready_count > 0) - { - s->receiver_not_ready_count--; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_F_POST_RCP_RNR); - send_simple_frame(s, T30_RNR); - } - else - { - if (send_response_to_pps(s)) - { - switch (s->last_pps_fcf2) - { - 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; - break; - } - /*endswitch*/ - } - /*endif*/ - } - /*endif*/ - break; - default: - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void process_rx_ppr(t30_state_t *s, const uint8_t *msg, int len) -{ - int i; - int j; - int frame_no; - uint8_t frame[5]; - - if (len != 3 + 256/8) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for PPR bits - %d\n", (len - 3)*8); - /* This frame didn't get corrupted in transit, because its CRC is OK. It was sent bad - and there is little possibility that causing a retransmission will help. It is best - to just give up. */ - t30_set_status(s, T30_ERR_TX_ECMPHD); - terminate_call(s); - return; - } - /*endif*/ - s->retries = 0; - /* Check which frames are OK, and mark them as OK. */ - for (i = 0; i < 32; i++) - { - for (j = 0; j < 8; j++) - { - frame_no = (i << 3) + j; - /* Tick off the frames they are not complaining about as OK */ - if ((msg[i + 3] & (1 << j)) == 0) - { - if (s->ecm_len[frame_no] >= 0) - s->ecm_progress++; - /*endif*/ - s->ecm_len[frame_no] = -1; - } - else - { - if (frame_no < s->ecm_frames) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Frame %d to be resent\n", frame_no); - s->error_correcting_mode_retries++; - } - /*endif*/ -#if 0 - /* Diagnostic: See if the other end is complaining about something we didn't even send this time. */ - if (s->ecm_len[frame_no] < 0) - span_log(&s->logging, SPAN_LOG_FLOW, "PPR contains complaint about frame %d, which was not sent\n", frame_no); - /*endif*/ -#endif - } - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (++s->ppr_count >= PPR_LIMIT_BEFORE_CTC_OR_EOR) - { - /* Continue to correct? */ - /* Continue only if we have been making progress */ - s->ppr_count = 0; - if (s->ecm_progress && fallback_sequence[s->current_fallback + 1].bit_rate) - { - s->current_fallback++; - s->ecm_progress = 0; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_IV_CTC); - frame[0] = ADDRESS_FIELD; - frame[1] = CONTROL_FIELD_FINAL_FRAME; - frame[2] = (uint8_t) (T30_CTC | s->dis_received); - frame[3] = 0; - frame[4] = fallback_sequence[s->current_fallback].dcs_code; - send_frame(s, frame, 5); - } - else - { - set_state(s, T30_STATE_IV_EOR); - queue_phase(s, T30_PHASE_D_TX); - frame[0] = ADDRESS_FIELD; - frame[1] = CONTROL_FIELD_FINAL_FRAME; - frame[2] = (uint8_t) (T30_EOR | s->dis_received); - frame[3] = (s->ecm_at_page_end) ? ((uint8_t) (s->next_tx_step | s->dis_received)) : T30_NULL; - span_log(&s->logging, SPAN_LOG_FLOW, "Sending EOR + %s\n", t30_frametype(frame[3])); - send_frame(s, frame, 4); - } - /*endif*/ - } - else - { - /* Initiate resending of the remainder of the frames. */ - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len) -{ - int frame_no; - - /* Facsimile coded data */ - switch (s->state) - { - case T30_STATE_F_DOC_ECM: - if (len > 4 + 256) - { - /* For other frame types we kill the call on an unexpected frame length. For FCD frames it is better to just ignore - the frame, and let retries sort things out. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len); - } - else - { - frame_no = msg[3]; - /* Just store the actual image data, and record its length */ - span_log(&s->logging, SPAN_LOG_FLOW, "Storing ECM frame %d, length %d\n", frame_no, len - 4); - 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; - } - /*endif*/ - /* We have received something, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - t30_set_status(s, T30_ERR_OK); - /*endif*/ - break; - default: - unexpected_non_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_rx_rcp(t30_state_t *s, const uint8_t *msg, int len) -{ - /* Return to control for partial page. These might come through with or without the final frame tag. - Here we deal with the "no final frame tag" case. */ - switch (s->state) - { - case T30_STATE_F_DOC_ECM: - set_state(s, T30_STATE_F_POST_DOC_ECM); - queue_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - /* We have received something, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - t30_set_status(s, T30_ERR_OK); - /*endif*/ - break; - case T30_STATE_F_POST_DOC_ECM: - /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance - of receiving a correct one. */ - timer_t2_start(s); - break; - default: - unexpected_non_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_rx_fnv(t30_state_t *s, const uint8_t *msg, int len) -{ - logging_state_t *log; - const char *x; - - /* Field not valid */ - /* TODO: analyse the message, as per 5.3.6.2.13 */ - if (!span_log_test(&s->logging, SPAN_LOG_FLOW)) - return; - /*endif*/ - log = &s->logging; - - if ((msg[3] & 0x01)) - span_log(log, SPAN_LOG_FLOW, " Incorrect password (PWD).\n"); - /*endif*/ - if ((msg[3] & 0x02)) - span_log(log, SPAN_LOG_FLOW, " Selective polling reference (SEP) not known.\n"); - /*endif*/ - if ((msg[3] & 0x04)) - span_log(log, SPAN_LOG_FLOW, " Sub-address (SUB) not known.\n"); - /*endif*/ - if ((msg[3] & 0x08)) - span_log(log, SPAN_LOG_FLOW, " Sender identity (SID) not known.\n"); - /*endif*/ - if ((msg[3] & 0x10)) - span_log(log, SPAN_LOG_FLOW, " Secure fax error.\n"); - /*endif*/ - if ((msg[3] & 0x20)) - span_log(log, SPAN_LOG_FLOW, " Transmitting subscriber identity (TSI) not accepted.\n"); - /*endif*/ - if ((msg[3] & 0x40)) - span_log(log, SPAN_LOG_FLOW, " Polled sub-address (PSA) not known.\n"); - /*endif*/ - if (len > 4 && (msg[3] & DISBIT8)) - { - if ((msg[4] & 0x01)) - span_log(log, SPAN_LOG_FLOW, " BFT negotiations request not accepted.\n"); - /*endif*/ - if ((msg[4] & 0x02)) - span_log(log, SPAN_LOG_FLOW, " Internet routing address (IRA) not known.\n"); - /*endif*/ - if ((msg[4] & 0x04)) - span_log(log, SPAN_LOG_FLOW, " Internet selective polling address (ISP) not known.\n"); - /*endif*/ - } - /*endif*/ - if (len > 5) - { - span_log(log, SPAN_LOG_FLOW, " FNV sequence number %d.\n", msg[5]); - } - /*endif*/ - if (len > 6) - { - switch (msg[6]) - { - case T30_PWD: - x = "Incorrect password (PWD)"; - break; - case T30_SEP: - x = "Selective polling reference (SEP) not known"; - break; - case T30_SUB: - case T30_SUB | 0x01: - x = "Sub-address (SUB) not known"; - break; - case T30_SID: - case T30_SID | 0x01: - x = "Sender identity (SID) not known"; - break; - case T30_SPI: - x = "Secure fax error"; - break; - case T30_TSI: - case T30_TSI | 0x01: - x = "Transmitting subscriber identity (TSI) not accepted"; - break; - case T30_PSA: - x = "Polled sub-address (PSA) not known"; - break; - default: - x = "???"; - break; - } - /*endswitch*/ - span_log(log, SPAN_LOG_FLOW, " FNV diagnostic info type %s.\n", x); - } - /*endif*/ - if (len > 7) - { - span_log(log, SPAN_LOG_FLOW, " FNV length %d.\n", msg[7]); - } - /*endif*/ - /* We've decoded it, but we don't yet know how to deal with it, so treat it as unexpected */ - unexpected_final_frame(s, msg, len); -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_answering(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* We should be sending the TCF data right now */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DIS: - /* TODO: This is a fudge to allow for starting up in T.38, where the other end has - seen DIS by analogue modem means, and has immediately sent DIS/DTC. We might have - missed useful info, like TSI, but just accept things and carry on form now. */ - span_log(&s->logging, SPAN_LOG_FLOW, "DIS/DTC before DIS\n"); - process_rx_dis_dtc(s, msg, len); - break; - case T30_DCS: - /* TODO: This is a fudge to allow for starting up in T.38, where the other end has - seen DIS by analogue modem means, and has immediately sent DCS. We might have - missed useful info, like TSI, but just accept things and carry on form now. */ - span_log(&s->logging, SPAN_LOG_FLOW, "DCS before DIS\n"); - process_rx_dcs(s, msg, len); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_TX_GOTDCN); - terminate_call(s); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_b(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DCN: - /* Just ignore any DCN's which appear at this stage. */ - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_c(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DCN: - /* Just ignore any DCN's which appear at this stage. */ - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_d(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* We should be sending the DCS sequence right now */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DCN: - t30_set_status(s, T30_ERR_TX_BADDCS); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_d_tcf(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* We should be sending the TCF data right now */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DCN: - t30_set_status(s, T30_ERR_TX_BADDCS); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CFR: - /* Trainability test succeeded. Send the document. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Trainability test succeeded\n"); - s->retries = 0; - s->short_train = true; - if (s->error_correcting_mode) - { - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - else - { - set_state(s, T30_STATE_I); - queue_phase(s, T30_PHASE_C_NON_ECM_TX); - } - /*endif*/ - break; - case T30_FTT: - /* Trainability test failed. Try again. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Trainability test failed\n"); - s->retries = 0; - s->short_train = false; - if (step_fallback_entry(s) < 0) - { - /* We have fallen back as far as we can go. Give up. */ - t30_set_status(s, T30_ERR_CANNOT_TRAIN); - send_dcn(s); - break; - } - /*endif*/ - queue_phase(s, T30_PHASE_B_TX); - send_dcs_sequence(s, true); - break; - case T30_DIS: - /* It appears they didn't see what we sent - retry the TCF */ - if (++s->retries >= MAX_COMMAND_TRIES) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Too many retries. Giving up.\n"); - t30_set_status(s, T30_ERR_RETRYDCN); - send_dcn(s); - break; - } - /*endif*/ - 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); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_TX_BADDCS); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_tcf(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* We should be receiving TCF right now, not HDLC messages */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_cfr(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* We're waiting for a response to the CFR we sent */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DCS: - /* If we received another DCS, they must have missed our CFR */ - process_rx_dcs(s, msg, len); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_ftt(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* We're waiting for a response to the FTT we sent */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DCS: - process_rx_dcs(s, msg, len); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - /* If we are getting HDLC messages, and we have not moved to the _POST_DOC_NON_ECM - state, it looks like either: - - we didn't see the image data carrier properly, or - - they didn't see our T30_CFR, and are repeating the DCS/TCF sequence. - - they didn't see our T30_MCF, T30_RTP or T30_RTN and are repeating the end of page message. */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DIS: - process_rx_dis_dtc(s, msg, len); - break; - case T30_DCS: - process_rx_dcs(s, msg, len); - break; - case T30_PRI_MPS: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_MPS: - if (s->image_carrier_attempted) - { - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - s->next_rx_step = fcf; - s->last_rx_page_result = T30_RTN; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_III_Q); - send_simple_frame(s, s->last_rx_page_result); - } - else - { - /* This appears to be a retry, because the far end didn't see our last response */ - repeat_last_command(s); - } - /*endif*/ - break; - case T30_PRI_EOM: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_EOM: - case T30_EOS: - if (s->image_carrier_attempted) - { - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - s->next_rx_step = fcf; - s->last_rx_page_result = T30_RTN; - /* Return to phase B */ - queue_phase(s, T30_PHASE_B_TX); - set_state(s, T30_STATE_III_Q); - send_simple_frame(s, s->last_rx_page_result); - } - else - { - /* This appears to be a retry, because the far end didn't see our last response */ - repeat_last_command(s); - } - /*endif*/ - break; - case T30_PRI_EOP: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_EOP: - if (s->image_carrier_attempted) - { - /* Treat this as a bad quality page. */ - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - s->next_rx_step = fcf; - s->last_rx_page_result = T30_RTN; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_III_Q); - send_simple_frame(s, s->last_rx_page_result); - } - else - { - /* This appears to be a retry, because the far end didn't see our last response */ - repeat_last_command(s); - } - /*endif*/ - break; - case T30_DCN: - t30_set_status(s, T30_ERR_RX_DCNDATA); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - t30_set_status(s, T30_ERR_RX_INVALCMD); - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- 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; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_PRI_MPS: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_MPS: - s->next_rx_step = fcf; - queue_phase(s, T30_PHASE_D_TX); - assess_copy_quality(s, fcf); - break; - case T30_PRI_EOM: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_EOM: - case T30_EOS: - s->next_rx_step = fcf; - /* Return to phase B */ - queue_phase(s, T30_PHASE_B_TX); - assess_copy_quality(s, fcf); - break; - case T30_PRI_EOP: - if (s->remote_interrupts_allowed) - { - } - /*endif*/ - /* Fall through */ - case T30_EOP: - span_log(&s->logging, SPAN_LOG_FLOW, "End of procedure detected\n"); - s->end_of_procedure_detected = true; - s->next_rx_step = fcf; - queue_phase(s, T30_PHASE_D_TX); - assess_copy_quality(s, fcf); - break; - case T30_DCS: - span_log(&s->logging, SPAN_LOG_FLOW, "DCS received after CFR\n"); - process_rx_dcs(s, msg, len); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_RX_DCNFAX); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - t30_set_status(s, T30_ERR_RX_INVALCMD); - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - uint8_t fcf2; - - /* This actually handles 2 states - _DOC_ECM and _POST_DOC_ECM - as they are very similar */ - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DIS: - process_rx_dis_dtc(s, msg, len); - break; - case T30_DCS: - process_rx_dcs(s, msg, len); - break; - case T4_RCP: - /* Return to control for partial page. These might come through with or without the final frame tag. - Here we deal with the "final frame tag" case. */ - process_rx_rcp(s, msg, len); - break; - case T30_EOR: - if (len != 4) - { - unexpected_frame_length(s, msg, len); - break; - } - /*endif*/ - fcf2 = msg[3] & 0xFE; - span_log(&s->logging, SPAN_LOG_FLOW, "Received EOR + %s\n", t30_frametype(msg[3])); - switch (fcf2) - { - case T30_PRI_EOP: - case T30_PRI_EOM: - case T30_PRI_MPS: - if (s->remote_interrupts_allowed) - { - /* TODO: Alert operator */ - } - /*endif*/ - /* Fall through */ - case T30_NULL: - case T30_EOP: - case T30_EOM: - case T30_EOS: - case T30_MPS: - s->image_carrier_attempted = false; - s->next_rx_step = fcf2; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_F_DOC_ECM); - send_simple_frame(s, T30_ERR); - break; - default: - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ - break; - case T30_PPS: - process_rx_pps(s, msg, len); - break; - case T30_CTC: - if ((msg[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) != fallback_sequence[s->current_fallback].dcs_code) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Modem changed in CTC.\n"); - if ((s->current_fallback = find_fallback_entry(msg[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0) - span_log(&s->logging, SPAN_LOG_FLOW, "Remote asked for a modem standard we do not support\n"); - /*endif*/ - } - /*endif*/ - s->image_carrier_attempted = false; - /* T.30 says we change back to long training here, whether or not the far end changed the modem type. */ - 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); - break; - case T30_RR: - break; - case T30_DCN: - t30_set_status(s, T30_ERR_RX_DCNDATA); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - t30_set_status(s, T30_ERR_RX_INVALCMD); - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_post_rcp_mcf(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_DCN: - terminate_call(s); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_post_rcp_ppr(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_f_post_rcp_rnr(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_RR: - if (s->receiver_not_ready_count > 0) - { - s->receiver_not_ready_count--; - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_F_POST_RCP_RNR); - send_simple_frame(s, T30_RNR); - } - else - { - /* Now we send the deferred response */ - if (send_response_to_pps(s)) - { - switch (s->last_pps_fcf2) - { - 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; - break; - } - /*endswitch*/ - } - /*endif*/ - } - /*endif*/ - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_r(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DIS: - process_rx_dis_dtc(s, msg, len); - break; - case T30_DCS: - process_rx_dcs(s, msg, len); - break; - case T30_DCN: - /* Received a DCN while waiting for a DIS or DCN */ - t30_set_status(s, T30_ERR_RX_DCNWHY); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_t(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_DIS: - process_rx_dis_dtc(s, msg, len); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_TX_GOTDCN); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - t30_set_status(s, T30_ERR_TX_NODIS); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_i(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_ii(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_PIP: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - case T30_MCF: - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_MPS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - /* Transmit the next page */ - if (tx_start_page(s)) - { - /* TODO: recover */ - break; - } - /*endif*/ - set_state(s, T30_STATE_I); - queue_phase(s, T30_PHASE_C_NON_ECM_TX); - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - report_tx_result(s, true); - return_to_phase_b(s, false); - break; - case T30_PRI_EOP: - case T30_EOP: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - send_dcn(s); - report_tx_result(s, true); - break; - } - /*endswitch*/ - break; - case T30_RTP: - s->rtp_events++; - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_MPS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (tx_start_page(s)) - { - /* TODO: recover */ - break; - } - /*endif*/ - /* Send fresh training, and then the next page */ - if (step_fallback_entry(s) < 0) - { - /* We have fallen back as far as we can go. Give up. */ - t30_set_status(s, T30_ERR_CANNOT_TRAIN); - send_dcn(s); - break; - } - /*endif*/ - queue_phase(s, T30_PHASE_B_TX); - restart_sending_document(s); - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - t4_tx_release(&s->t4.tx); - /* TODO: should go back to T, and resend */ - return_to_phase_b(s, true); - break; - case T30_PRI_EOP: - case T30_EOP: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - t4_tx_release(&s->t4.tx); - send_dcn(s); - break; - } - /*endswitch*/ - break; - case T30_PIN: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - case T30_RTN: - s->rtn_events++; - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_MPS: - s->retries = 0; - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (!s->retransmit_capable) - { - /* Send the next page, regardless of the problem with the current one. */ - if (tx_start_page(s)) - { - /* TODO: recover */ - break; - } - /*endif*/ - } - /*endif*/ - /* Send fresh training */ - if (step_fallback_entry(s) < 0) - { - /* We have fallen back as far as we can go. Give up. */ - t30_set_status(s, T30_ERR_CANNOT_TRAIN); - send_dcn(s); - break; - } - /*endif*/ - queue_phase(s, T30_PHASE_B_TX); - restart_sending_document(s); - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - s->retries = 0; - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (s->retransmit_capable) - { - /* Wait for DIS */ - } - else - { - return_to_phase_b(s, true); - } - /*endif*/ - break; - case T30_PRI_EOP: - case T30_EOP: - s->retries = 0; - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (s->retransmit_capable) - { - /* Send fresh training, and then repeat the last page */ - if (step_fallback_entry(s) < 0) - { - /* We have fallen back as far as we can go. Give up. */ - t30_set_status(s, T30_ERR_CANNOT_TRAIN); - send_dcn(s); - break; - } - /*endif*/ - queue_phase(s, T30_PHASE_B_TX); - restart_sending_document(s); - } - else - { - send_dcn(s); - } - /*endif*/ - break; - } - /*endswitch*/ - break; - case T30_DCN: - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_PRI_EOM: - case T30_MPS: - case T30_EOM: - case T30_EOS: - /* Unexpected DCN after EOM, EOS or MPS sequence */ - t30_set_status(s, T30_ERR_RX_DCNPHD); - break; - default: - t30_set_status(s, T30_ERR_TX_BADPG); - break; - } - /*endswitch*/ - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_MPS: - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - case T30_PRI_EOP: - case T30_EOP: - if (fcf == s->next_tx_step) - { - /* It looks like we have received an echo of what we just sent */ - span_log(&s->logging, SPAN_LOG_FLOW, "Received an echo of our own %s\n", t30_frametype(fcf)); - timer_t4_start(s); - break; - } - /*endif*/ - /* Fall through */ - default: - /* We don't know what to do with this. */ - t30_set_status(s, T30_ERR_TX_INVALRSP); - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iii_q(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_EOP: - case T30_EOM: - case T30_EOS: - case T30_MPS: - /* Looks like they didn't see our signal. Repeat it */ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_III_Q); - send_simple_frame(s, s->last_rx_page_result); - break; - case T30_DIS: - if (msg[2] == T30_DTC) - process_rx_dis_dtc(s, msg, len); - /*endif*/ - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_DCN: - if (s->last_rx_page_result == T30_RTN) - t30_set_status(s, T30_ERR_RX_DCNNORTN); - /*endif*/ - terminate_call(s); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_MCF: - s->retries = 0; - s->timer_t5 = 0; - /* Is there more of the current page to get, or do we move on? */ - span_log(&s->logging, SPAN_LOG_FLOW, "Is there more to send? - %d %d\n", s->ecm_frames, s->ecm_len[255]); - if (!s->ecm_at_page_end && get_partial_ecm_page(s) > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Additional image data to send\n"); - s->ecm_block++; - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_MPS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (tx_start_page(s)) - { - /* TODO: recover */ - break; - } - /*endif*/ - if (get_partial_ecm_page(s) > 0) - { - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - /*endif*/ - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - report_tx_result(s, true); - return_to_phase_b(s, false); - break; - case T30_PRI_EOP: - case T30_EOP: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - send_dcn(s); - report_tx_result(s, true); - break; - } - /*endswitch*/ - } - /*endif*/ - break; - case T30_PPR: - process_rx_ppr(s, msg, len); - break; - case T30_RNR: - if (s->timer_t5 == 0) - s->timer_t5 = ms_to_samples(DEFAULT_TIMER_T5); - /*endif*/ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_IV_PPS_RNR); - send_rr(s); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_TX_BADPG); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_PPS: - if (msg[3] == s->next_tx_step) - { - /* It looks like we have received an echo of what we just sent */ - span_log(&s->logging, SPAN_LOG_FLOW, "Received an echo of our own PPS-%s\n", t30_frametype(msg[3])); - timer_t4_start(s); - break; - } - /*endif*/ - /* Fall through */ - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - t30_set_status(s, T30_ERR_TX_ECMPHD); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_PIP: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - case T30_MCF: - s->retries = 0; - s->timer_t5 = 0; - /* Is there more of the current page to get, or do we move on? */ - span_log(&s->logging, SPAN_LOG_FLOW, "Is there more to send? - %d %d\n", s->ecm_frames, s->ecm_len[255]); - if (!s->ecm_at_page_end && get_partial_ecm_page(s) > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Additional image data to send\n"); - s->ecm_block++; - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_MPS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (tx_start_page(s)) - { - /* TODO: recover */ - break; - } - /*endif*/ - if (get_partial_ecm_page(s) > 0) - { - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - /*endif*/ - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - report_tx_result(s, true); - return_to_phase_b(s, false); - break; - case T30_PRI_EOP: - case T30_EOP: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - send_dcn(s); - report_tx_result(s, true); - break; - } - /*endswitch*/ - } - /*endif*/ - break; - case T30_RNR: - if (s->timer_t5 == 0) - s->timer_t5 = ms_to_samples(DEFAULT_TIMER_T5); - /*endif*/ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_IV_PPS_RNR); - send_rr(s); - break; - case T30_PPR: - process_rx_ppr(s, msg, len); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_TX_BADPG); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_PPS: - if (msg[3] == s->next_tx_step) - { - /* It looks like we have received an echo of what we just sent */ - span_log(&s->logging, SPAN_LOG_FLOW, "Received an echo of our own PPS-%s\n", t30_frametype(msg[3])); - timer_t4_start(s); - break; - } - /*endif*/ - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - t30_set_status(s, T30_ERR_TX_ECMPHD); - break; - case T30_PIN: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - t30_set_status(s, T30_ERR_TX_ECMPHD); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_PIP: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - case T30_MCF: - s->retries = 0; - s->timer_t5 = 0; - /* Is there more of the current page to get, or do we move on? */ - span_log(&s->logging, SPAN_LOG_FLOW, "Is there more to send? - %d %d\n", s->ecm_frames, s->ecm_len[255]); - if (!s->ecm_at_page_end && get_partial_ecm_page(s) > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Additional image data to send\n"); - s->ecm_block++; - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n"); - switch (s->next_tx_step) - { - case T30_PRI_MPS: - case T30_MPS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - if (tx_start_page(s)) - { - /* TODO: recover */ - break; - } - /*endif*/ - if (get_partial_ecm_page(s) > 0) - { - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - send_first_ecm_frame(s); - } - /*endif*/ - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - report_tx_result(s, true); - return_to_phase_b(s, false); - break; - case T30_PRI_EOP: - case T30_EOP: - tx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s->phase_d_user_data, fcf); - /*endif*/ - terminate_operation_in_progress(s); - send_dcn(s); - report_tx_result(s, true); - break; - } - /*endswitch*/ - } - /*endif*/ - break; - case T30_RNR: - if (s->timer_t5 == 0) - s->timer_t5 = ms_to_samples(DEFAULT_TIMER_T5); - /*endif*/ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_IV_PPS_RNR); - send_rr(s); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_RX_DCNRRD); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_PPS: - if (msg[3] == s->next_tx_step) - { - /* It looks like we have received an echo of what we just sent */ - span_log(&s->logging, SPAN_LOG_FLOW, "Received an echo of our own PPS-%s\n", t30_frametype(msg[3])); - timer_t4_start(s); - break; - } - /*endif*/ - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - case T30_PIN: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv_ctc(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_CTR: - /* Valid response to a CTC received */ - /* T.30 says we change back to long training here */ - 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); - send_first_ecm_frame(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_RNR: - if (s->timer_t5 == 0) - s->timer_t5 = ms_to_samples(DEFAULT_TIMER_T5); - /*endif*/ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_IV_EOR_RNR); - send_rr(s); - break; - case T30_ERR: - /* TODO: Continue with the next message if MPS or EOM? */ - t30_set_status(s, T30_ERR_RETRYDCN); - s->timer_t5 = 0; - send_dcn(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_PIN: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len) -{ - uint8_t fcf; - - fcf = msg[2] & 0xFE; - switch (fcf) - { - case T30_RNR: - if (s->timer_t5 == 0) - s->timer_t5 = ms_to_samples(DEFAULT_TIMER_T5); - /*endif*/ - queue_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_IV_EOR_RNR); - send_rr(s); - break; - case T30_ERR: - /* TODO: Continue with the next message if MPS or EOM? */ - t30_set_status(s, T30_ERR_RETRYDCN); - s->timer_t5 = 0; - send_dcn(s); - break; - case T30_DCN: - t30_set_status(s, T30_ERR_RX_DCNRRD); - terminate_call(s); - break; - case T30_CRP: - repeat_last_command(s); - break; - case T30_FNV: - process_rx_fnv(s, msg, len); - break; - case T30_PIN: - if (s->remote_interrupts_allowed) - { - s->retries = 0; - if (s->phase_d_handler) - { - s->phase_d_handler(s->phase_d_user_data, fcf); - s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3); - } - /*endif*/ - } - /*endif*/ - /* Fall through */ - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void process_state_call_finished(t30_state_t *s, const uint8_t *msg, int len) -{ - /* Simply ignore anything which comes in when we have declared the call - to have finished. */ -} -/*- End of function --------------------------------------------------------*/ - -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->real_time_frame_user_data, true, msg, len); - /*endif*/ - if ((msg[1] & 0x10) == 0) - { - /* This is not a final frame */ - /* It seems we should not restart the command or response timer when exchanging HDLC image - data. If the modem looses sync in the middle of the image, we should just wait until - the carrier goes away before proceeding. */ - if (s->phase != T30_PHASE_C_ECM_RX) - { - /* Restart the command or response timer, T2 or T4 */ - switch (s->timer_t2_t4_is) - { - case TIMER_IS_T1A: - case TIMER_IS_T2: - case TIMER_IS_T2_FLAGGED: - case TIMER_IS_T2_DROPPED: - timer_t2_flagged_start(s); - break; - case TIMER_IS_T4: - case TIMER_IS_T4_FLAGGED: - case TIMER_IS_T4_DROPPED: - timer_t4_flagged_start(s); - break; - } - /*endswitch*/ - } - /*endif*/ - /* The following handles all the message types we expect to get without - a final frame tag. If we get one that T.30 says we should not expect - in a particular context, its pretty harmless, so don't worry. */ - switch (msg[2] & 0xFE) - { - case (T30_CSI & 0xFE): - /* Called subscriber identification or Calling subscriber identification (T30_CIG) */ - /* OK in (NSF) (CSI) DIS */ - /* OK in (NSC) (CIG) DTC */ - /* OK in (PWD) (SEP) (CIG) DTC */ - decode_20digit_msg(s, s->rx_info.ident, &msg[2], len - 2); - break; - case (T30_NSF & 0xFE): - if (msg[2] == T30_NSF) - { - /* Non-standard facilities */ - /* OK in (NSF) (CSI) DIS */ - t35_decode(&msg[3], len - 3, &s->country, &s->vendor, &s->model); - if (s->country) - span_log(&s->logging, SPAN_LOG_FLOW, "The remote was made in '%s'\n", s->country); - /*endif*/ - if (s->vendor) - span_log(&s->logging, SPAN_LOG_FLOW, "The remote was made by '%s'\n", s->vendor); - /*endif*/ - if (s->model) - span_log(&s->logging, SPAN_LOG_FLOW, "The remote is a '%s'\n", s->model); - /*endif*/ - s->rx_info.nsf_len = decode_nsf_nss_nsc(s, &s->rx_info.nsf, &msg[2], len - 2); - } - else - { - /* NSC - Non-standard facilities command */ - /* OK in (NSC) (CIG) DTC */ - s->rx_info.nsc_len = decode_nsf_nss_nsc(s, &s->rx_info.nsc, &msg[2], len - 2); - } - /*endif*/ - break; - case (T30_PWD & 0xFE): - if (msg[2] == T30_PWD) - { - /* Password */ - /* OK in (SUB) (SID) (SEP) (PWD) (TSI) DCS */ - /* OK in (SUB) (SID) (SEP) (PWD) (CIG) DTC */ - decode_20digit_msg(s, s->rx_info.password, &msg[2], len - 2); - } - else - { - unexpected_non_final_frame(s, msg, len); - } - /*endif*/ - break; - case (T30_SEP & 0xFE): - if (msg[2] == T30_SEP) - { - /* Selective polling address */ - /* OK in (PWD) (SEP) (CIG) DTC */ - decode_20digit_msg(s, s->rx_info.selective_polling_address, &msg[2], len - 2); - } - else - { - unexpected_non_final_frame(s, msg, len); - } - /*endif*/ - break; - case (T30_PSA & 0xFE): - if (msg[2] == T30_PSA) - { - /* Polled sub-address */ - decode_20digit_msg(s, s->rx_info.polled_sub_address, &msg[2], len - 2); - } - else - { - unexpected_non_final_frame(s, msg, len); - } - /*endif*/ - break; - case (T30_CIA & 0xFE): - if (msg[2] == T30_CIA) - { - /* Calling subscriber internet address */ - decode_url_msg(s, NULL, &msg[2], len - 2); - } - else - { - unexpected_non_final_frame(s, msg, len); - } - /*endif*/ - break; - case (T30_ISP & 0xFE): - if (msg[2] == T30_ISP) - { - /* Internet selective polling address */ - decode_url_msg(s, NULL, &msg[2], len - 2); - } - else - { - unexpected_non_final_frame(s, msg, len); - } - /*endif*/ - break; - case (T30_TSI & 0xFE): - /* Transmitting subscriber identity */ - /* OK in (PWD) (SUB) (TSI) DCS */ - decode_20digit_msg(s, s->rx_info.ident, &msg[2], len - 2); - break; - case (T30_NSS & 0xFE): - /* Non-standard facilities set-up */ - s->rx_info.nss_len = decode_nsf_nss_nsc(s, &s->rx_info.nss, &msg[2], len - 2); - break; - case (T30_SUB & 0xFE): - /* Sub-address */ - /* OK in (PWD) (SUB) (TSI) DCS */ - decode_20digit_msg(s, s->rx_info.sub_address, &msg[2], len - 2); - break; - case (T30_SID & 0xFE): - /* Sender Identification */ - /* OK in (SUB) (SID) (SEP) (PWD) (TSI) DCS */ - /* OK in (SUB) (SID) (SEP) (PWD) (CIG) DTC */ - decode_20digit_msg(s, s->rx_info.sender_ident, &msg[2], len - 2); - break; - case (T30_CSA & 0xFE): - /* Calling subscriber internet address */ - decode_url_msg(s, NULL, &msg[2], len - 2); - break; - case (T30_TSA & 0xFE): - /* Transmitting subscriber internet address */ - decode_url_msg(s, NULL, &msg[2], len - 2); - break; - case (T30_IRA & 0xFE): - /* Internet routing address */ - decode_url_msg(s, NULL, &msg[2], len - 2); - break; - case T4_FCD: - process_rx_fcd(s, msg, len); - break; - case T4_RCP: - process_rx_rcp(s, msg, len); - break; - default: - unexpected_non_final_frame(s, msg, len); - break; - } - /*endswitch*/ - } - else - { - /* This is a final frame */ - /* Once we have any successful message from the far end, we - cancel timer T1 */ - s->timer_t0_t1 = 0; - - /* The following handles context sensitive message types, which should - occur at the end of message sequences. They should, therefore have - the final frame flag set. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Rx final frame in state %s\n", state_names[s->state]); - - switch (s->state) - { - case T30_STATE_ANSWERING: - process_state_answering(s, msg, len); - break; - case T30_STATE_B: - process_state_b(s, msg, len); - break; - case T30_STATE_C: - process_state_c(s, msg, len); - break; - case T30_STATE_D: - process_state_d(s, msg, len); - break; - case T30_STATE_D_TCF: - process_state_d_tcf(s, msg, len); - break; - case T30_STATE_D_POST_TCF: - process_state_d_post_tcf(s, msg, len); - break; - case T30_STATE_F_TCF: - process_state_f_tcf(s, msg, len); - break; - case T30_STATE_F_CFR: - process_state_f_cfr(s, msg, len); - break; - case T30_STATE_F_FTT: - process_state_f_ftt(s, msg, len); - break; - case T30_STATE_F_DOC_NON_ECM: - process_state_f_doc_non_ecm(s, msg, len); - break; - case T30_STATE_F_POST_DOC_NON_ECM: - process_state_f_post_doc_non_ecm(s, msg, len); - break; - case T30_STATE_F_DOC_ECM: - case T30_STATE_F_POST_DOC_ECM: - process_state_f_doc_and_post_doc_ecm(s, msg, len); - break; - case T30_STATE_F_POST_RCP_MCF: - process_state_f_post_rcp_mcf(s, msg, len); - break; - case T30_STATE_F_POST_RCP_PPR: - process_state_f_post_rcp_ppr(s, msg, len); - break; - case T30_STATE_F_POST_RCP_RNR: - process_state_f_post_rcp_rnr(s, msg, len); - break; - case T30_STATE_R: - process_state_r(s, msg, len); - break; - case T30_STATE_T: - process_state_t(s, msg, len); - break; - case T30_STATE_I: - process_state_i(s, msg, len); - break; - case T30_STATE_II: - process_state_ii(s, msg, len); - break; - case T30_STATE_II_Q: - process_state_ii_q(s, msg, len); - break; - case T30_STATE_III_Q: - process_state_iii_q(s, msg, len); - break; - case T30_STATE_IV: - process_state_iv(s, msg, len); - break; - case T30_STATE_IV_PPS_NULL: - process_state_iv_pps_null(s, msg, len); - break; - case T30_STATE_IV_PPS_Q: - process_state_iv_pps_q(s, msg, len); - break; - case T30_STATE_IV_PPS_RNR: - process_state_iv_pps_rnr(s, msg, len); - break; - case T30_STATE_IV_CTC: - process_state_iv_ctc(s, msg, len); - break; - case T30_STATE_IV_EOR: - process_state_iv_eor(s, msg, len); - break; - case T30_STATE_IV_EOR_RNR: - process_state_iv_eor_rnr(s, msg, len); - break; - case T30_STATE_CALL_FINISHED: - process_state_call_finished(s, msg, len); - break; - default: - /* We don't know what to do with this. */ - unexpected_final_frame(s, msg, len); - break; - } - /*endswitch*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void queue_phase(t30_state_t *s, int phase) -{ - if (s->rx_signal_present) - { - /* We need to wait for that signal to go away */ - if (s->next_phase != T30_PHASE_IDLE) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Flushing queued phase %s\n", phase_names[s->next_phase]); - /* Ensure nothing has been left in the queue that was scheduled to go out in the previous next - phase */ - if (s->send_hdlc_handler) - s->send_hdlc_handler(s->send_hdlc_user_data, NULL, -1); - /*endif*/ - } - /*endif*/ - s->next_phase = phase; - span_log(&s->logging, SPAN_LOG_FLOW, "Queuing phase %s\n", phase_names[s->next_phase]); - } - else - { - /* We don't need to queue the new phase. We can change to it immediately. */ - set_phase(s, phase); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void set_phase(t30_state_t *s, int phase) -{ - if (s->next_phase != phase && s->next_phase != T30_PHASE_IDLE) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Flushing queued phase %s\n", phase_names[s->next_phase]); - /* Ensure nothing has been left in the queue that was scheduled to go out in the previous next - phase */ - if (s->send_hdlc_handler) - s->send_hdlc_handler(s->send_hdlc_user_data, NULL, -1); - /*endif*/ - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Changing from phase %s to %s\n", phase_names[s->phase], phase_names[phase]); - /* We may be killing a receiver before it has declared the end of the - signal. Force the signal present indicator to off, because the - receiver will never be able to. */ - if (s->phase != T30_PHASE_A_CED && s->phase != T30_PHASE_A_CNG) - s->rx_signal_present = false; - /*endif*/ - s->rx_trained = false; - s->rx_frame_received = false; - s->phase = phase; - s->next_phase = T30_PHASE_IDLE; - switch (phase) - { - case T30_PHASE_A_CED: - if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, false, true); - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_CED, 0, false, false); - /*endif*/ - 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); - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_CNG, 0, false, false); - /*endif*/ - 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); - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, false, false); - /*endif*/ - break; - case T30_PHASE_B_TX: - case T30_PHASE_D_TX: - if (!s->far_end_detected && s->timer_t0_t1 > 0) - { - /* Switch from T0 to T1 */ - s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T1); - s->far_end_detected = true; - } - /*endif*/ - if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_V21, 300, false, true); - /*endif*/ - break; - case T30_PHASE_C_NON_ECM_RX: - if (s->set_rx_type_handler) - { - /* 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); - } - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, false, false); - /*endif*/ - break; - case T30_PHASE_C_NON_ECM_TX: - /* Pause before switching from anything to phase C */ - /* Always prime the training count for 1.5s of data at the current rate. Its harmless if - we prime it and are not doing TCF. */ - s->tcf_test_bits = (3*fallback_sequence[s->current_fallback].bit_rate)/2; - if (s->set_rx_type_handler) - { - /* 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); - } - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, false, false); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - break; - case T30_PHASE_E: - /* Send a little silence before ending things, to ensure the buffers are flushed all they way - through to the far end, and the far end has been able to see the last message we sent. */ - s->tcf_test_bits = 0; - 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); - /*endif*/ - 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); - /*endif*/ - 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); - /*endif*/ - if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_DONE, 0, false, false); - /*endif*/ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void set_state(t30_state_t *s, int state) -{ - if (s->state != state) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Changing from state %s to %s\n", state_names[s->state], state_names[state]); - s->state = state; - } - /*endif*/ - s->step = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void repeat_last_command(t30_state_t *s) -{ - s->step = 0; - /* If T0 or T1 are in progress we do not want to apply a limit to the maximum number of retries. We - let T0 or T1 terminate things if the far end doesn't communicate. */ - s->retries++; - if (s->timer_t0_t1 == 0 && s->retries >= MAX_COMMAND_TRIES) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Too many retries. Giving up.\n"); - switch (s->state) - { - case T30_STATE_D_POST_TCF: - /* Received no response to DCS or TCF */ - t30_set_status(s, T30_ERR_TX_PHBDEAD); - break; - case T30_STATE_II_Q: - case T30_STATE_IV_PPS_NULL: - case T30_STATE_IV_PPS_Q: - /* No response after sending a page */ - t30_set_status(s, T30_ERR_TX_PHDDEAD); - break; - default: - /* Disconnect after permitted retries */ - t30_set_status(s, T30_ERR_RETRYDCN); - break; - } - /*endswitch*/ - send_dcn(s); - return; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Retry number %d\n", s->retries); - switch (s->state) - { - case T30_STATE_R: - s->dis_received = false; - queue_phase(s, T30_PHASE_B_TX); - send_dis_or_dtc_sequence(s, true); - break; - case T30_STATE_F_DOC_NON_ECM: - case T30_STATE_III_Q: - queue_phase(s, T30_PHASE_D_TX); - send_simple_frame(s, s->last_rx_page_result); - break; - case T30_STATE_II_Q: - queue_phase(s, T30_PHASE_D_TX); - send_simple_frame(s, s->next_tx_step); - break; - case T30_STATE_IV_PPS_NULL: - case T30_STATE_IV_PPS_Q: - queue_phase(s, T30_PHASE_D_TX); - send_pps_frame(s); - break; - case T30_STATE_IV_PPS_RNR: - case T30_STATE_IV_EOR_RNR: - queue_phase(s, T30_PHASE_D_TX); - send_rr(s); - break; - case T30_STATE_D: - queue_phase(s, T30_PHASE_B_TX); - send_dcs_sequence(s, true); - break; - case T30_STATE_F_FTT: - queue_phase(s, T30_PHASE_B_TX); - send_simple_frame(s, T30_FTT); - break; - case T30_STATE_F_CFR: - queue_phase(s, T30_PHASE_B_TX); - send_cfr_sequence(s, true); - break; - case T30_STATE_D_POST_TCF: - /* Need to send the whole training thing again */ - s->short_train = false; - queue_phase(s, T30_PHASE_B_TX); - send_dcs_sequence(s, true); - break; - case T30_STATE_F_POST_RCP_PPR: - queue_phase(s, T30_PHASE_D_TX); - send_frame(s, s->ecm_frame_map, 3 + 32); - break; - case T30_STATE_F_POST_RCP_MCF: - queue_phase(s, T30_PHASE_D_TX); - send_simple_frame(s, T30_MCF); - break; - case T30_STATE_F_POST_RCP_RNR: - /* Just ignore */ - break; - default: - span_log(&s->logging, - SPAN_LOG_FLOW, - "Repeat command called with nothing to repeat - phase %s, state %s\n", - phase_names[s->phase], - state_names[s->state]); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_start(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Start T2\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T2); - s->timer_t2_t4_is = TIMER_IS_T2; -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_flagged_start(t30_state_t *s) -{ - /* T.30 Annex A says timeout T1 should be used in ECM phase C to time out the - first frame after the flags start. This seems a strange reuse of the name T1 - for a different purpose, but there it is. We distinguish it by calling it T1A. */ - if (s->phase == T30_PHASE_C_ECM_RX) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Start T1A\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T1A); - s->timer_t2_t4_is = TIMER_IS_T1A; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Start T2-flagged\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T2_FLAGGED); - s->timer_t2_t4_is = TIMER_IS_T2_FLAGGED; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_dropped_start(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Start T2-dropped\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T2_DROPPED); - s->timer_t2_t4_is = TIMER_IS_T2_DROPPED; -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t4_start(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Start T4\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T4); - s->timer_t2_t4_is = TIMER_IS_T4; -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t4_flagged_start(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Start T4-flagged\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T4_FLAGGED); - s->timer_t2_t4_is = TIMER_IS_T4_FLAGGED; -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t4_dropped_start(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Start T4-dropped\n"); - s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T4_DROPPED); - s->timer_t2_t4_is = TIMER_IS_T4_DROPPED; -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_t4_stop(t30_state_t *s) -{ - const char *tag; - - switch (s->timer_t2_t4_is) - { - case TIMER_IS_IDLE: - tag = "none"; - break; - case TIMER_IS_T1A: - tag = "T1A"; - break; - case TIMER_IS_T2: - tag = "T2"; - break; - case TIMER_IS_T2_FLAGGED: - tag = "T2-flagged"; - break; - case TIMER_IS_T2_DROPPED: - tag = "T2-dropped"; - break; - case TIMER_IS_T2C: - tag = "T2C"; - break; - case TIMER_IS_T4: - tag = "T4"; - break; - case TIMER_IS_T4_FLAGGED: - tag = "T4-flagged"; - break; - case TIMER_IS_T4_DROPPED: - tag = "T4-dropped"; - break; - case TIMER_IS_T4C: - tag = "T4C"; - break; - default: - tag = "T2/T4"; - break; - } - /*endswitch*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Stop %s (%d remaining)\n", tag, s->timer_t2_t4); - s->timer_t2_t4 = 0; - s->timer_t2_t4_is = TIMER_IS_IDLE; -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t0_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T0 expired in state %s\n", state_names[s->state]); - t30_set_status(s, T30_ERR_T0_EXPIRED); - /* Just end the call */ - terminate_call(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t1_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T1 expired in state %s\n", state_names[s->state]); - /* The initial connection establishment has timeout out. In other words, we - have been unable to communicate successfully with a remote machine. - It is time to abandon the call. */ - t30_set_status(s, T30_ERR_T1_EXPIRED); - switch (s->state) - { - case T30_STATE_T: - /* Just end the call */ - terminate_call(s); - break; - case T30_STATE_R: - /* Send disconnect, and then end the call. Since we have not - successfully contacted the far end, it is unclear why we should - send a disconnect message at this point. However, it is what T.30 - says we should do. */ - send_dcn(s); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t1a_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T1A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); - t30_set_status(s, T30_ERR_HDLC_CARRIER); - terminate_call(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_expired(t30_state_t *s) -{ - if (s->timer_t2_t4_is != TIMER_IS_T2_DROPPED) - span_log(&s->logging, SPAN_LOG_FLOW, "T2 expired in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); - /*endif*/ - switch (s->state) - { - case T30_STATE_III_Q: - case T30_STATE_F_POST_RCP_PPR: - case T30_STATE_F_POST_RCP_MCF: - switch (s->next_rx_step) - { - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - /* We didn't receive a response to our T30_MCF after T30_EOM, so we must be OK - to proceed to phase B, and pretty much act like its the beginning of a call. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Returning to phase B after %s\n", t30_frametype(s->next_rx_step)); - /* Run the T1 timer, like we do on first detecting the far end. */ - s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T1); - s->dis_received = false; - set_phase(s, T30_PHASE_B_TX); - timer_t2_start(s); - send_dis_or_dtc_sequence(s, true); - return; - } - /*endswitch*/ - break; - case T30_STATE_F_TCF: - span_log(&s->logging, SPAN_LOG_FLOW, "No TCF data received\n"); - set_phase(s, T30_PHASE_B_TX); - set_state(s, T30_STATE_F_FTT); - send_simple_frame(s, T30_FTT); - return; - case T30_STATE_F_DOC_ECM: - case T30_STATE_F_DOC_NON_ECM: - /* While waiting for FAX page */ - t30_set_status(s, T30_ERR_RX_T2EXPFAX); - break; - case T30_STATE_F_POST_DOC_ECM: - case T30_STATE_F_POST_DOC_NON_ECM: - /* While waiting for next FAX page */ - /* Figure 5-2b/T.30 and note 7 says we should allow 1 to 3 tries at this point. - The way we work now is effectively hard coding a 1 try limit */ - t30_set_status(s, T30_ERR_RX_T2EXPMPS); - break; -#if 0 - case ??????: - /* While waiting for DCN */ - t30_set_status(s, T30_ERR_RX_T2EXPDCN); - break; - case ??????: - /* While waiting for phase D */ - t30_set_status(s, T30_ERR_RX_T2EXPD); - break; -#endif - case T30_STATE_IV_PPS_RNR: - case T30_STATE_IV_EOR_RNR: - /* While waiting for RR command */ - t30_set_status(s, T30_ERR_RX_T2EXPRR); - break; - case T30_STATE_R: - /* While waiting for NSS, DCS or MCF */ - t30_set_status(s, T30_ERR_RX_T2EXP); - break; - case T30_STATE_F_FTT: - break; - } - /*endswitch*/ - queue_phase(s, T30_PHASE_B_TX); - start_receiving_document(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_flagged_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T2-flagged expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); - t30_set_status(s, T30_ERR_HDLC_CARRIER); - /* T.30 says we should retry at this point, but we can't. We would need to - wait for the far end to go quiet before sending. Experience says you only - get here when the far end is buggy, and it will not go quiet unless you - hang up. If we were to retry, how long should we wait for the line to go - quiet? T.30 doesn't specify things like that. The only effective strategy, - when trying to deal with problems found in logs from real world systems, - is to abandon the call. */ - terminate_call(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t2_dropped_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T2-dropped expired in phase %s, state %s. The line is now quiet.\n", phase_names[s->phase], state_names[s->state]); - timer_t2_expired(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t3_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T3 expired in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); - t30_set_status(s, T30_ERR_T3_EXPIRED); - terminate_call(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t4_expired(t30_state_t *s) -{ - /* There was no response (or only a corrupt response) to a command, - within the T4 timeout period. */ - if (s->timer_t2_t4_is == TIMER_IS_T4) - span_log(&s->logging, SPAN_LOG_FLOW, "T4 expired in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); - /*endif*/ - /* Of course, things might just be a little late, especially if there are T.38 - links in the path. There is no point in simply timing out, and resending, - if we are currently receiving something from the far end - its a half-duplex - path, so the two transmissions will conflict. Our best strategy is to wait - until there is nothing being received, or give up after a long backstop timeout. - In the meantime, if we get a meaningful, if somewhat delayed, response, we - should accept it and carry on. */ - repeat_last_command(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t4_flagged_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T4-flagged expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); - t30_set_status(s, T30_ERR_HDLC_CARRIER); - terminate_call(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t4_dropped_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T4-dropped expired in phase %s, state %s. The line is now quiet.\n", phase_names[s->phase], state_names[s->state]); - timer_t4_expired(s); -} -/*- End of function --------------------------------------------------------*/ - -static void timer_t5_expired(t30_state_t *s) -{ - /* Give up waiting for the receiver to become ready in error correction mode */ - span_log(&s->logging, SPAN_LOG_FLOW, "T5 expired in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); - t30_set_status(s, T30_ERR_TX_T5EXP); -} -/*- End of function --------------------------------------------------------*/ - -static void decode_20digit_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len) -{ - int p; - int k; - char text[T30_MAX_IDENT_LEN + 1]; - - if (msg == NULL) - msg = text; - /*endif*/ - if (len > T30_MAX_IDENT_LEN + 1) - { - unexpected_frame_length(s, pkt, len); - msg[0] = '\0'; - return; - } - /*endif*/ - p = len; - /* Strip trailing spaces */ - while (p > 1 && pkt[p - 1] == ' ') - p--; - /*endwhile*/ - /* The string is actually backwards in the message */ - k = 0; - while (p > 1) - msg[k++] = pkt[--p]; - /*endwhile*/ - msg[k] = '\0'; - span_log(&s->logging, SPAN_LOG_FLOW, "Remote gave %s as: \"%s\"\n", t30_frametype(pkt[0]), msg); -} -/*- End of function --------------------------------------------------------*/ - -static void decode_url_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len) -{ - char text[77 + 1]; - - /* TODO: decode properly, as per T.30 5.3.6.2.12 */ - if (msg == NULL) - msg = text; - /*endif*/ - if (len < 3 || len > 77 + 3 || len != pkt[2] + 3) - { - unexpected_frame_length(s, pkt, len); - msg[0] = '\0'; - return; - } - /*endif*/ - /* First octet is the sequence number of the packet. - Bit 7 = 1 for more follows, 0 for last packet in the sequence. - Bits 6-0 = The sequence number, 0 to 0x7F - Second octet is the type of internet address. - Bits 7-4 = reserved - Bits 3-0 = type: - 0 = reserved - 1 = e-mail address - 2 = URL - 3 = TCP/IP V4 - 4 = TCP/IP V6 - 5 = international phone number, in the usual +... format - 6-15 = reserved - Third octet is the length of the internet address - Bit 7 = 1 for more follows, 0 for last packet in the sequence. - Bits 6-0 = length - */ - memcpy(msg, &pkt[3], len - 3); - msg[len - 3] = '\0'; - span_log(&s->logging, SPAN_LOG_FLOW, "Remote fax gave %s as: %d, %d, \"%s\"\n", t30_frametype(pkt[0]), pkt[0], pkt[1], msg); -} -/*- End of function --------------------------------------------------------*/ - -static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt, int len) -{ - uint8_t *t; - - if ((t = span_alloc(len - 1)) == NULL) - return 0; - /*endif*/ - memcpy(t, &pkt[1], len - 1); - *msg = t; - return len - 1; -} -/*- End of function --------------------------------------------------------*/ - -static void t30_non_ecm_rx_status(void *user_data, int status) -{ - t30_state_t *s; - int was_trained; - - s = (t30_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM signal status is %s (%d) in state %s\n", signal_status_to_str(status), status, state_names[s->state]); - switch (status) - { - case SIG_STATUS_TRAINING_IN_PROGRESS: - s->image_carrier_attempted = true; - break; - case SIG_STATUS_TRAINING_FAILED: - s->rx_trained = false; - break; - case SIG_STATUS_TRAINING_SUCCEEDED: - /* The modem is now trained */ - /* In case we are in trainability test mode... */ - s->tcf_test_bits = 0; - s->tcf_current_zeros = 0; - s->tcf_most_zeros = 0; - 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; - switch (s->state) - { - case T30_STATE_F_TCF: - /* Only respond if we managed to actually sync up with the source. We don't - want to respond just because we saw a click. These often occur just - before the real signal, with many modems. Presumably this is due to switching - within the far end modem. We also want to avoid the possibility of responding - to the tail end of any slow modem signal. If there was a genuine data signal - which we failed to train on it should not matter. If things are that bad, we - do not stand much chance of good quality communications. */ - if (was_trained) - { - /* Although T.30 says the training test should be 1.5s of all 0's, some FAX - machines send a burst of all 1's before the all 0's. Tolerate this. */ - if (s->tcf_current_zeros > s->tcf_most_zeros) - s->tcf_most_zeros = s->tcf_current_zeros; - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Trainability (TCF) test result - %d total bits. longest run of zeros was %d\n", s->tcf_test_bits, s->tcf_most_zeros); - if (s->tcf_most_zeros < fallback_sequence[s->current_fallback].bit_rate) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Trainability (TCF) test failed - longest run of zeros was %d\n", s->tcf_most_zeros); - set_phase(s, T30_PHASE_B_TX); - set_state(s, T30_STATE_F_FTT); - send_simple_frame(s, T30_FTT); - } - else - { - /* The training went OK */ - 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); - } - /*endif*/ - } - /*endif*/ - break; - case T30_STATE_F_POST_DOC_NON_ECM: - /* Page ended cleanly */ - /* We have received something, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - t30_set_status(s, T30_ERR_OK); - /*endif*/ - break; - default: - if (was_trained) - { - span_log(&s->logging, SPAN_LOG_WARNING, "Page did not end cleanly\n"); - /* We trained OK, so we should have some kind of received page, even though - it did not end cleanly. */ - set_state(s, T30_STATE_F_POST_DOC_NON_ECM); - set_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - /* We have received something, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - t30_set_status(s, T30_ERR_OK); - /*endif*/ - } - else - { - span_log(&s->logging, SPAN_LOG_WARNING, "Non-ECM carrier not found\n"); - t30_set_status(s, T30_ERR_RX_NOCARRIER); - } - /*endif*/ - break; - } - /*endswitch*/ - if (s->next_phase != T30_PHASE_IDLE) - set_phase(s, s->next_phase); - /*endif*/ - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected non-ECM rx status - %d!\n", status); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_non_ecm_put_bit(void *user_data, int bit) -{ - t30_state_t *s; - int res; - - if (bit < 0) - { - t30_non_ecm_rx_status(user_data, bit); - return; - } - /*endif*/ - s = (t30_state_t *) user_data; - switch (s->state) - { - case T30_STATE_F_TCF: - /* Trainability test */ - s->tcf_test_bits++; - if (bit) - { - if (s->tcf_current_zeros > s->tcf_most_zeros) - s->tcf_most_zeros = s->tcf_current_zeros; - /*endif*/ - s->tcf_current_zeros = 0; - } - else - { - s->tcf_current_zeros++; - } - /*endif*/ - break; - case T30_STATE_F_DOC_NON_ECM: - /* Image transfer */ - if ((res = t4_rx_put_bit(&s->t4.rx, bit)) != T4_DECODE_MORE_DATA) - { - /* 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); - /*endif*/ - set_state(s, T30_STATE_F_POST_DOC_NON_ECM); - queue_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - } - /*endif*/ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -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) - { - case T30_STATE_F_TCF: - /* Trainability test */ - /* This makes counting zeros fast, but approximate. That really doesn't matter */ - s->tcf_test_bits += 8*len; - for (i = 0; i < len; i++) - { - if (buf[i]) - { - if (s->tcf_current_zeros > s->tcf_most_zeros) - s->tcf_most_zeros = s->tcf_current_zeros; - /*endif*/ - s->tcf_current_zeros = 0; - } - else - { - s->tcf_current_zeros += 8; - } - /*endif*/ - } - /*endfor*/ - break; - case T30_STATE_F_DOC_NON_ECM: - /* Image transfer */ - if ((res = t4_rx_put(&s->t4.rx, buf, len)) != T4_DECODE_MORE_DATA) - { - /* 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); - /*endif*/ - set_state(s, T30_STATE_F_POST_DOC_NON_ECM); - queue_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - } - /*endif*/ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_non_ecm_get_bit(void *user_data) -{ - int bit; - t30_state_t *s; - - s = (t30_state_t *) user_data; - switch (s->state) - { - case T30_STATE_D_TCF: - /* Trainability test. */ - bit = 0; - if (s->tcf_test_bits-- < 0) - { - /* Finished sending training test. */ - bit = SIG_STATUS_END_OF_DATA; - } - /*endif*/ - break; - case T30_STATE_I: - /* Transferring real data. */ - bit = t4_tx_get_bit(&s->t4.tx); - break; - case T30_STATE_D_POST_TCF: - case T30_STATE_II_Q: - /* We should be padding out a block of samples if we are here */ - bit = 0; - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "t30_non_ecm_get_bit in bad state %s\n", state_names[s->state]); - bit = SIG_STATUS_END_OF_DATA; - break; - } - /*endswitch*/ - return bit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_non_ecm_get(void *user_data, uint8_t buf[], int max_len) -{ - int len; - t30_state_t *s; - - s = (t30_state_t *) user_data; - switch (s->state) - { - case T30_STATE_D_TCF: - /* Trainability test. */ - for (len = 0; len < max_len; len++) - { - buf[len] = 0; - if ((s->tcf_test_bits -= 8) < 0) - break; - /*endif*/ - } - /*endfor*/ - break; - case T30_STATE_I: - /* Transferring real data. */ - len = t4_tx_get(&s->t4.tx, buf, max_len); - break; - case T30_STATE_D_POST_TCF: - case T30_STATE_II_Q: - /* We should be padding out a block of samples if we are here */ - len = 0; - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "t30_non_ecm_get in bad state %s\n", state_names[s->state]); - len = -1; - break; - } - /*endswitch*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void t30_hdlc_rx_status(void *user_data, int status) -{ - t30_state_t *s; - int was_trained; - - s = (t30_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC signal status is %s (%d) in state %s\n", signal_status_to_str(status), status, state_names[s->state]); - switch (status) - { - case SIG_STATUS_TRAINING_IN_PROGRESS: - break; - case SIG_STATUS_TRAINING_FAILED: - s->rx_trained = false; - break; - case SIG_STATUS_TRAINING_SUCCEEDED: - /* The modem is now trained */ - s->rx_signal_present = true; - s->rx_trained = true; - break; - case SIG_STATUS_CARRIER_UP: - s->rx_signal_present = true; - switch (s->timer_t2_t4_is) - { - case TIMER_IS_T2_DROPPED: - timer_t2_t4_stop(s); - s->timer_t2_t4_is = TIMER_IS_T2C; - break; - case TIMER_IS_T4_DROPPED: - timer_t2_t4_stop(s); - s->timer_t2_t4_is = TIMER_IS_T4C; - break; - } - /*endswitch*/ - break; - case SIG_STATUS_CARRIER_DOWN: - was_trained = s->rx_trained; - s->rx_signal_present = false; - s->rx_trained = false; - /* If a phase change has been queued to occur after the receive signal drops, - its time to change. */ - if (s->state == T30_STATE_F_DOC_ECM) - { - /* We should be receiving a document right now, but we haven't seen an RCP at the end of - transmission. */ - if (was_trained) - { - /* We trained OK, so we should have some kind of received page, possibly with - zero good HDLC frames. It just did'nt end cleanly with an RCP. */ - span_log(&s->logging, SPAN_LOG_WARNING, "ECM signal did not end cleanly\n"); - /* Fake the existance of an RCP, and proceed */ - set_state(s, T30_STATE_F_POST_DOC_ECM); - queue_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - /* We at least trained, so any missing carrier status is out of date */ - if (s->current_status == T30_ERR_RX_NOCARRIER) - t30_set_status(s, T30_ERR_OK); - /*endif*/ - } - else - { - /* Either there was no image carrier, or we failed to train to it. */ - span_log(&s->logging, SPAN_LOG_WARNING, "ECM carrier not found\n"); - t30_set_status(s, T30_ERR_RX_NOCARRIER); - } - /*endif*/ - } - /*endif*/ - if (s->next_phase != T30_PHASE_IDLE) - { - /* The appropriate timer for the next phase should already be in progress */ - set_phase(s, s->next_phase); - } - else - { - switch (s->timer_t2_t4_is) - { - case TIMER_IS_T1A: - case TIMER_IS_T2_FLAGGED: - case TIMER_IS_T2C: - timer_t2_dropped_start(s); - break; - case TIMER_IS_T4_FLAGGED: - case TIMER_IS_T4C: - timer_t4_dropped_start(s); - break; - } - /*endswitch*/ - } - /*endif*/ - break; - case SIG_STATUS_FRAMING_OK: - if (!s->far_end_detected && s->timer_t0_t1 > 0) - { - /* Switch from T0 to T1 */ - s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T1); - 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); - /*endif*/ - } - /*endif*/ - /* 5.4.3.1 Timer T2 is reset if flag is received. Timer T2_FLAGGED must be started. */ - /* Unstated, but implied, is that timer T4 and T4_FLAGGED are handled the same way. */ - if (s->timer_t2_t4 > 0) - { - switch(s->timer_t2_t4_is) - { - case TIMER_IS_T1A: - case TIMER_IS_T2: - case TIMER_IS_T2_FLAGGED: - timer_t2_flagged_start(s); - break; - case TIMER_IS_T4: - case TIMER_IS_T4_FLAGGED: - timer_t4_flagged_start(s); - break; - } - /*endswitch*/ - } - /*endif*/ - break; - case SIG_STATUS_ABORT: - /* Just ignore these */ - break; - default: - span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected HDLC special length - %d!\n", status); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) -{ - t30_state_t *s; - - if (len < 0) - { - t30_hdlc_rx_status(user_data, len); - return; - } - /*endif*/ - - s = (t30_state_t *) user_data; - /* The spec. says a command or response is not valid if: - - any of the frames, optional or mandatory, have an FCS error. - - any single frame exceeds 3s +- 15% (i.e. no frame should exceed 2.55s) - - the final frame is not tagged as a final frame - - the final frame is not a recognised one. - The first point seems benign. If we accept an optional frame, and a later - frame is bad, having accepted the optional frame should be harmless. - The 2.55s maximum seems to limit signalling frames to no more than 95 octets, - including FCS, and flag octets (assuming the use of V.21). - */ - if (!ok) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad HDLC CRC received\n"); - if (s->phase != T30_PHASE_C_ECM_RX) - { - /* We either force a resend, or we wait until a resend occurs through a timeout. */ - if ((s->supported_t30_features & T30_SUPPORT_COMMAND_REPEAT)) - { - s->step = 0; - if (s->phase == T30_PHASE_B_RX) - queue_phase(s, T30_PHASE_B_TX); - else - queue_phase(s, T30_PHASE_D_TX); - /*endif*/ - send_simple_frame(s, T30_CRP); - } - else - { - /* Cancel the command or response timer (if one is running) */ - span_log(&s->logging, SPAN_LOG_FLOW, "Bad CRC and timer is %d\n", s->timer_t2_t4_is); - if (s->timer_t2_t4_is == TIMER_IS_T2_FLAGGED) - timer_t2_t4_stop(s); - /*endif*/ - } - /*endif*/ - } - /*endif*/ - return; - } - /*endif*/ - - if (len < 3) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad HDLC frame length - %d\n", len); - /* Cancel the command or response timer (if one is running) */ - timer_t2_t4_stop(s); - return; - } - /*endif*/ - if (msg[0] != ADDRESS_FIELD - || - !(msg[1] == CONTROL_FIELD_NON_FINAL_FRAME || msg[1] == CONTROL_FIELD_FINAL_FRAME)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad HDLC frame header - %02x %02x\n", msg[0], msg[1]); - /* Cancel the command or response timer (if one is running) */ - timer_t2_t4_stop(s); - return; - } - /*endif*/ - 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); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) -{ - t30_state_t *s; - - s = (t30_state_t *) user_data; - - switch (status) - { - case T30_FRONT_END_SEND_STEP_COMPLETE: - span_log(&s->logging, SPAN_LOG_FLOW, "Send complete in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); - /* We have finished sending our messages, so move on to the next operation. */ - switch (s->state) - { - case T30_STATE_ANSWERING: - span_log(&s->logging, SPAN_LOG_FLOW, "Starting answer mode\n"); - s->dis_received = false; - set_phase(s, T30_PHASE_B_TX); - timer_t2_start(s); - send_dis_or_dtc_sequence(s, true); - break; - case T30_STATE_R: - if (send_dis_or_dtc_sequence(s, false)) - { - /* Wait for an acknowledgement. */ - set_phase(s, T30_PHASE_B_RX); - timer_t4_start(s); - } - /*endif*/ - break; - case T30_STATE_F_CFR: - if (send_cfr_sequence(s, false)) - { - s->image_carrier_attempted = false; - s->last_rx_page_result = -1; - if (s->error_correcting_mode) - { - set_state(s, T30_STATE_F_DOC_ECM); - queue_phase(s, T30_PHASE_C_ECM_RX); - } - else - { - set_state(s, T30_STATE_F_DOC_NON_ECM); - queue_phase(s, T30_PHASE_C_NON_ECM_RX); - } - /*endif*/ - timer_t2_start(s); - s->next_rx_step = T30_MPS; - } - /*endif*/ - break; - case T30_STATE_F_FTT: - if (s->step == 0) - { - shut_down_hdlc_tx(s); - s->step++; - } - else - { - set_phase(s, T30_PHASE_B_RX); - timer_t2_start(s); - } - /*endif*/ - break; - case T30_STATE_F_DOC_NON_ECM: - case T30_STATE_III_Q: - case T30_STATE_F_POST_RCP_PPR: - case T30_STATE_F_POST_RCP_MCF: - if (s->step == 0) - { - shut_down_hdlc_tx(s); - s->step++; - } - else - { - switch (s->next_rx_step) - { - case T30_PRI_MPS: - case T30_MPS: - /* We should now start to get another page */ - s->image_carrier_attempted = false; - if (s->error_correcting_mode) - { - set_state(s, T30_STATE_F_DOC_ECM); - queue_phase(s, T30_PHASE_C_ECM_RX); - } - else - { - set_state(s, T30_STATE_F_DOC_NON_ECM); - queue_phase(s, T30_PHASE_C_NON_ECM_RX); - } - /*endif*/ - timer_t2_start(s); - break; - case T30_PRI_EOM: - case T30_EOM: - case T30_EOS: - /* See if we get something back, before moving to phase B. */ - set_phase(s, T30_PHASE_D_RX); - timer_t2_start(s); - break; - case T30_PRI_EOP: - case T30_EOP: - /* Wait for a DCN. */ - set_phase(s, T30_PHASE_D_RX); - timer_t4_start(s); - break; - default: - span_log(&s->logging, SPAN_LOG_FLOW, "Unknown next rx step - %d\n", s->next_rx_step); - terminate_call(s); - break; - } - /*endswitch*/ - } - /*endif*/ - break; - case T30_STATE_II_Q: - case T30_STATE_IV_PPS_NULL: - case T30_STATE_IV_PPS_Q: - case T30_STATE_IV_PPS_RNR: - case T30_STATE_IV_EOR_RNR: - case T30_STATE_F_POST_RCP_RNR: - case T30_STATE_IV_EOR: - case T30_STATE_IV_CTC: - if (s->step == 0) - { - shut_down_hdlc_tx(s); - s->step++; - } - else - { - /* We have finished sending the post image message. Wait for an - acknowledgement. */ - set_phase(s, T30_PHASE_D_RX); - timer_t4_start(s); - } - /*endif*/ - break; - case T30_STATE_B: - /* We have now allowed time for the last message to flush through - the system, so it is safe to report the end of the call. */ - terminate_call(s); - break; - case T30_STATE_C: - if (s->step == 0) - { - shut_down_hdlc_tx(s); - s->step++; - } - else - { - /* We just sent the disconnect message. Now it is time to clean up and - end the call. */ - start_final_pause(s); - } - /*endif*/ - break; - case T30_STATE_D: - 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; - if (s->error_correcting_mode) - { - set_state(s, T30_STATE_IV); - queue_phase(s, T30_PHASE_C_ECM_TX); - } - else - { - set_state(s, T30_STATE_I); - queue_phase(s, T30_PHASE_C_NON_ECM_TX); - } - /*endif*/ - } - else - { - /* Do the trainability test */ - /* TCF is always sent with long training */ - s->short_train = false; - set_state(s, T30_STATE_D_TCF); - set_phase(s, T30_PHASE_C_NON_ECM_TX); - } - /*endif*/ - } - /*endif*/ - break; - case T30_STATE_D_TCF: - /* Finished sending training test. Listen for the response. */ - set_phase(s, T30_PHASE_B_RX); - timer_t4_start(s); - set_state(s, T30_STATE_D_POST_TCF); - break; - case T30_STATE_I: - /* Send the end of page message */ - set_phase(s, T30_PHASE_D_TX); - set_state(s, T30_STATE_II_Q); - /* We might need to resend the page we are on, but we need to check if there - are any more pages to send, so we can send the correct signal right now. */ - send_simple_frame(s, s->next_tx_step = check_next_tx_step(s)); - break; - case T30_STATE_IV: - /* We have finished sending an FCD frame */ - if (s->step == 0) - { - if (send_next_ecm_frame(s)) - { - shut_down_hdlc_tx(s); - s->step++; - } - /*endif*/ - } - else - { - /* Send the end of page or partial page message */ - set_phase(s, T30_PHASE_D_TX); - if (s->ecm_at_page_end) - s->next_tx_step = check_next_tx_step(s); - /*endif*/ - if (send_pps_frame(s) == T30_NULL) - set_state(s, T30_STATE_IV_PPS_NULL); - else - set_state(s, T30_STATE_IV_PPS_Q); - /*endif*/ - } - /*endif*/ - break; - case T30_STATE_F_DOC_ECM: - /* This should be the end of a CTR being sent. */ - if (s->step == 0) - { - shut_down_hdlc_tx(s); - s->step++; - } - else - { - /* We have finished sending the CTR. Wait for image data again. */ - queue_phase(s, T30_PHASE_C_ECM_RX); - timer_t2_start(s); - } - /*endif*/ - break; - case T30_STATE_CALL_FINISHED: - /* Just ignore anything that happens now. We might get here if a premature - disconnect from the far end overlaps something. */ - break; - default: - span_log(&s->logging, SPAN_LOG_FLOW, "Bad state for send complete in t30_front_end_status - %s\n", state_names[s->state]); - break; - } - /*endswitch*/ - break; - case T30_FRONT_END_RECEIVE_COMPLETE: - span_log(&s->logging, SPAN_LOG_FLOW, "Receive complete in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); - /* Usually receive complete is notified by a carrier down signal. However, - in cases like a T.38 packet stream dying in the middle of reception - there needs to be a means to stop things. */ - switch (s->phase) - { - case T30_PHASE_C_NON_ECM_RX: - t30_non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN); - break; - default: - t30_hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN); - break; - } - /*endswitch*/ - break; - case T30_FRONT_END_SIGNAL_PRESENT: - span_log(&s->logging, SPAN_LOG_FLOW, "A signal is present\n"); - /* The front end is explicitly telling us the signal we expect is present. This might - be a premature indication from a T.38 implementation, but we have to believe it. - if we don't we can time out improperly. For example, we might get an image modem - carrier signal, but the first HDLC frame might only occur several seconds later. - Many ECM senders idle on HDLC flags while waiting for the paper or filing system - to become ready. T.38 offers no specific indication of correct carrier training, so - if we don't kill the timer on the initial carrier starting signal, we will surely - time out quite often before the next thing we receive. */ - switch (s->phase) - { - case T30_PHASE_A_CED: - case T30_PHASE_A_CNG: - case T30_PHASE_B_RX: - case T30_PHASE_D_RX: - /* We are running a V.21 receive modem, where an explicit training indication - will not occur. */ - t30_hdlc_rx_status(s, SIG_STATUS_CARRIER_UP); - t30_hdlc_rx_status(s, SIG_STATUS_FRAMING_OK); - break; - default: - /* Cancel any receive timeout, and declare that a receive signal is present, - since the front end is explicitly telling us we have seen something. */ - s->rx_signal_present = true; - break; - } - /*endswitch*/ - break; - case T30_FRONT_END_SIGNAL_ABSENT: - span_log(&s->logging, SPAN_LOG_FLOW, "No signal is present\n"); - /* TODO: Should we do anything here? */ - break; - case T30_FRONT_END_CED_PRESENT: - span_log(&s->logging, SPAN_LOG_FLOW, "CED tone is present\n"); - /* TODO: Should we do anything here? */ - break; - case T30_FRONT_END_CNG_PRESENT: - span_log(&s->logging, SPAN_LOG_FLOW, "CNG tone is present\n"); - /* TODO: Should we do anything here? */ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_timer_update(t30_state_t *s, int samples) -{ - int previous; - - if (s->timer_t0_t1 > 0) - { - if ((s->timer_t0_t1 -= samples) <= 0) - { - s->timer_t0_t1 = 0; - if (s->far_end_detected) - timer_t1_expired(s); - else - timer_t0_expired(s); - /*endif*/ - } - /*endif*/ - } - /*endif*/ - if (s->timer_t3 > 0) - { - if ((s->timer_t3 -= samples) <= 0) - { - s->timer_t3 = 0; - timer_t3_expired(s); - } - /*endif*/ - } - /*endif*/ - if (s->timer_t2_t4 > 0) - { - if ((s->timer_t2_t4 -= samples) <= 0) - { - previous = s->timer_t2_t4_is; - /* Don't allow the count to be left at a small negative number. - It looks cosmetically bad in the logs. */ - s->timer_t2_t4 = 0; - s->timer_t2_t4_is = TIMER_IS_IDLE; - switch (previous) - { - case TIMER_IS_T1A: - timer_t1a_expired(s); - break; - case TIMER_IS_T2: - timer_t2_expired(s); - break; - case TIMER_IS_T2_FLAGGED: - timer_t2_flagged_expired(s); - break; - case TIMER_IS_T2_DROPPED: - timer_t2_dropped_expired(s); - break; - case TIMER_IS_T4: - timer_t4_expired(s); - break; - case TIMER_IS_T4_FLAGGED: - timer_t4_flagged_expired(s); - break; - case TIMER_IS_T4_DROPPED: - timer_t4_dropped_expired(s); - break; - } - /*endswitch*/ - } - /*endif*/ - } - /*endif*/ - if (s->timer_t5 > 0) - { - if ((s->timer_t5 -= samples) <= 0) - { - s->timer_t5 = 0; - timer_t5_expired(s); - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_terminate(t30_state_t *s) -{ - if (s->phase != T30_PHASE_CALL_FINISHED) - { - /* The far end disconnected early, but was it just a tiny bit too early, - as we were just tidying up, or seriously early as in a failure? */ - switch (s->state) - { - case T30_STATE_C: - /* We were sending the final disconnect, so just hussle things along. */ - break; - case T30_STATE_B: - /* We were in the final pause, waiting for everything to flush through, - so just hussle things along. */ - break; - default: - /* If we have seen a genuine EOP or PRI_EOP, and that's good enough for us. - The far end might not agree, as it might not have seen the MCF we sent - in response to EOP or PRI_EOP. This might cause it to say the call did - not complete properly. However, if this function has been called we can - do no more. */ - if (!s->end_of_procedure_detected) - { - /* The call terminated prematurely. */ - t30_set_status(s, T30_ERR_CALLDROPPED); - } - /*endif*/ - break; - } - /*endswitch*/ - terminate_call(s); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t) -{ - t4_stats_t stats; - - t->bit_rate = fallback_sequence[s->current_fallback].bit_rate; - t->error_correcting_mode = s->error_correcting_mode; - t->error_correcting_mode_retries = s->error_correcting_mode_retries; - switch (s->operation_in_progress) - { - case OPERATION_IN_PROGRESS_T4_TX: - case OPERATION_IN_PROGRESS_POST_T4_TX: - t4_tx_get_transfer_statistics(&s->t4.tx, &stats); - break; - case OPERATION_IN_PROGRESS_T4_RX: - case OPERATION_IN_PROGRESS_POST_T4_RX: - t4_rx_get_transfer_statistics(&s->t4.rx, &stats); - break; - default: - memset(&stats, 0, sizeof(stats)); - break; - } - /*endswitch*/ - t->pages_tx = s->tx_page_number; - t->pages_rx = s->rx_page_number; - t->pages_in_file = stats.pages_in_file; - t->bad_rows = stats.bad_rows; - t->longest_bad_row_run = stats.longest_bad_row_run; - - t->image_type = stats.image_type; - t->image_x_resolution = stats.image_x_resolution; - t->image_y_resolution = stats.image_y_resolution; - t->image_width = stats.image_width; - t->image_length = stats.image_length; - - t->type = stats.type; - t->x_resolution = stats.x_resolution; - t->y_resolution = stats.y_resolution; - t->width = stats.width; - t->length = stats.length; - - t->compression = stats.compression; - t->image_size = stats.line_image_size; - t->current_status = s->current_status; - t->rtn_events = s->rtn_events; - t->rtp_events = s->rtp_events; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state) -{ - if (s->timer_t3 > 0) - { - /* Accept the far end's outstanding request for interrupt. */ - /* TODO: */ - send_simple_frame(s, (state) ? T30_PIP : T30_PIN); - } - /*endif*/ - s->local_interrupt_pending = state; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state) -{ - s->remote_interrupts_allowed = state; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_restart(t30_state_t *s, bool calling_party) -{ - release_resources(s); - s->calling_party = calling_party; - s->state = T30_STATE_IDLE; - 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->current_status = T30_ERR_OK; - s->ppr_count = 0; - s->ecm_progress = 0; - s->receiver_not_ready_count = 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)); - /* The page number is only reset at call establishment */ - s->rx_page_number = 0; - 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->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0); - if (s->calling_party) - { - set_state(s, T30_STATE_T); - set_phase(s, T30_PHASE_A_CNG); - } - else - { - set_state(s, T30_STATE_ANSWERING); - set_phase(s, T30_PHASE_A_CED); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s, - bool calling_party, - t30_set_handler_t set_rx_type_handler, - void *set_rx_type_user_data, - t30_set_handler_t set_tx_type_handler, - void *set_tx_type_user_data, - t30_send_hdlc_handler_t send_hdlc_handler, - void *send_hdlc_user_data) -{ - if (s == NULL) - { - if ((s = (t30_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - s->set_rx_type_handler = set_rx_type_handler; - s->set_rx_type_user_data = set_rx_type_user_data; - s->set_tx_type_handler = set_tx_type_handler; - s->set_tx_type_user_data = set_tx_type_user_data; - s->send_hdlc_handler = send_hdlc_handler; - s->send_hdlc_user_data = send_hdlc_user_data; - - /* Default to the basic modems. */ - s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; - 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"); - t30_restart(s, calling_party); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_release(t30_state_t *s) -{ - /* Make sure any FAX in progress is tidied up. If the tidying up has - already happened, repeating it here is harmless. */ - terminate_operation_in_progress(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_free(t30_state_t *s) -{ - t30_release(s); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_call_active(t30_state_t *s) -{ - return (s->phase != T30_PHASE_CALL_FINISHED); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c deleted file mode 100644 index 23c2d49375..0000000000 --- a/libs/spandsp/src/t30_api.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_api.c - ITU T.30 FAX transfer processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 -#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/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/queue.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/hdlc.h" -#include "spandsp/fsk.h" -#include "spandsp/v29rx.h" -#include "spandsp/v29tx.h" -#include "spandsp/v27ter_rx.h" -#include "spandsp/v27ter_tx.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/t30_fcf.h" -#include "spandsp/t35.h" -#include "spandsp/t30.h" -#include "spandsp/t30_api.h" -#include "spandsp/t30_logging.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/timezone.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" -#include "spandsp/private/t30.h" - -#include "t30_local.h" - -SPAN_DECLARE(int) t33_sub_address_extract_field(uint8_t num[21], const uint8_t t33[], int field_no) -{ - int i; - int j; - int k; - int ch; - int type; - - num[0] = '\0'; - k = 0; - for (i = 0; t33[i]; ) - { - if (k++ == field_no) - { - ch = t33[i++]; - j = 0; - if (ch != '#') - { - num[j++] = ch; - type = T33_EXT; - } - else - { - type = T33_SST; - } - /*endif*/ - while (t33[i]) - { - ch = t33[i++]; - if (ch == '#') - break; - /*endif*/ - num[j++] = ch; - if (j >= 20) - return -1; - /*endif*/ - } - /*endwhile*/ - num[j] = '\0'; - return type; - } - /*endif*/ - /* Skip this field */ - i++; - while (t33[i]) - { - if (t33[i++] == '#') - break; - /*endif*/ - } - /*endwhile*/ - } - /*endfor*/ - return T33_NONE; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t33_sub_address_add_field(uint8_t t33[], const uint8_t field[], int type) -{ - if (t33[0] != '\0') - strcat((char *) t33, "#"); - /*endif*/ - if (type == T33_SST) - strcat((char *) t33, "#"); - /*endif*/ - strcat((char *) t33, (const char *) field); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_ident(t30_state_t *s, const char *id) -{ - if (id == NULL) - { - s->tx_info.ident[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(id) > T30_MAX_IDENT_LEN) - return -1; - /*endif*/ - strcpy(s->tx_info.ident, id); - t4_tx_set_local_ident(&s->t4.tx, s->tx_info.ident); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_tx_ident(t30_state_t *s) -{ - if (s->tx_info.ident[0] == '\0') - return NULL; - /*endif*/ - return s->tx_info.ident; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_ident(t30_state_t *s) -{ - if (s->rx_info.ident[0] == '\0') - return NULL; - /*endif*/ - return s->rx_info.ident; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_sub_address(t30_state_t *s, const char *sub_address) -{ - if (sub_address == NULL) - { - s->tx_info.sub_address[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(sub_address) > T30_MAX_IDENT_LEN) - return -1; - /*endif*/ - strcpy(s->tx_info.sub_address, sub_address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_tx_sub_address(t30_state_t *s) -{ - if (s->tx_info.sub_address[0] == '\0') - return NULL; - /*endif*/ - return s->tx_info.sub_address; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_sub_address(t30_state_t *s) -{ - if (s->rx_info.sub_address[0] == '\0') - return NULL; - /*endif*/ - return s->rx_info.sub_address; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_selective_polling_address(t30_state_t *s, const char *selective_polling_address) -{ - if (selective_polling_address == NULL) - { - s->tx_info.selective_polling_address[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(selective_polling_address) > T30_MAX_IDENT_LEN) - return -1; - /*endif*/ - strcpy(s->tx_info.selective_polling_address, selective_polling_address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_tx_selective_polling_address(t30_state_t *s) -{ - if (s->tx_info.selective_polling_address[0] == '\0') - return NULL; - /*endif*/ - return s->tx_info.selective_polling_address; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_selective_polling_address(t30_state_t *s) -{ - if (s->rx_info.selective_polling_address[0] == '\0') - return NULL; - /*endif*/ - return s->rx_info.selective_polling_address; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_polled_sub_address(t30_state_t *s, const char *polled_sub_address) -{ - if (polled_sub_address == NULL) - { - s->tx_info.polled_sub_address[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(polled_sub_address) > T30_MAX_IDENT_LEN) - return -1; - /*endif*/ - strcpy(s->tx_info.polled_sub_address, polled_sub_address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_tx_polled_sub_address(t30_state_t *s) -{ - if (s->tx_info.polled_sub_address[0] == '\0') - return NULL; - /*endif*/ - return s->tx_info.polled_sub_address; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_polled_sub_address(t30_state_t *s) -{ - if (s->rx_info.polled_sub_address[0] == '\0') - return NULL; - /*endif*/ - return s->rx_info.polled_sub_address; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_sender_ident(t30_state_t *s, const char *sender_ident) -{ - if (sender_ident == NULL) - { - s->tx_info.sender_ident[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(sender_ident) > T30_MAX_IDENT_LEN) - return -1; - /*endif*/ - strcpy(s->tx_info.sender_ident, sender_ident); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_tx_sender_ident(t30_state_t *s) -{ - if (s->tx_info.sender_ident[0] == '\0') - return NULL; - /*endif*/ - return s->tx_info.sender_ident; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_sender_ident(t30_state_t *s) -{ - if (s->rx_info.sender_ident[0] == '\0') - return NULL; - /*endif*/ - return s->rx_info.sender_ident; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_password(t30_state_t *s, const char *password) -{ - if (password == NULL) - { - s->tx_info.password[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(password) > T30_MAX_IDENT_LEN) - return -1; - /*endif*/ - strcpy(s->tx_info.password, password); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_tx_password(t30_state_t *s) -{ - if (s->tx_info.password[0] == '\0') - return NULL; - /*endif*/ - return s->tx_info.password; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_password(t30_state_t *s) -{ - if (s->rx_info.password[0] == '\0') - return NULL; - /*endif*/ - return s->rx_info.password; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_nsf(t30_state_t *s, const uint8_t *nsf, int len) -{ - if (s->tx_info.nsf) - span_free(s->tx_info.nsf); - /*endif*/ - 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; - } - else - { - s->tx_info.nsf = NULL; - s->tx_info.nsf_len = 0; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_nsf(t30_state_t *s, const uint8_t *nsf[]) -{ - if (nsf) - *nsf = s->tx_info.nsf; - /*endif*/ - return s->tx_info.nsf_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_nsf(t30_state_t *s, const uint8_t *nsf[]) -{ - if (nsf) - *nsf = s->rx_info.nsf; - /*endif*/ - return s->rx_info.nsf_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_nsc(t30_state_t *s, const uint8_t *nsc, int len) -{ - if (s->tx_info.nsc) - span_free(s->tx_info.nsc); - /*endif*/ - 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; - } - else - { - s->tx_info.nsc = NULL; - s->tx_info.nsc_len = 0; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_nsc(t30_state_t *s, const uint8_t *nsc[]) -{ - if (nsc) - *nsc = s->tx_info.nsc; - /*endif*/ - return s->tx_info.nsc_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_nsc(t30_state_t *s, const uint8_t *nsc[]) -{ - if (nsc) - *nsc = s->rx_info.nsc; - /*endif*/ - return s->rx_info.nsc_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_nss(t30_state_t *s, const uint8_t *nss, int len) -{ - if (s->tx_info.nss) - span_free(s->tx_info.nss); - /*endif*/ - 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; - } - else - { - s->tx_info.nss = NULL; - s->tx_info.nss_len = 0; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_nss(t30_state_t *s, const uint8_t *nss[]) -{ - if (nss) - *nss = s->tx_info.nss; - /*endif*/ - return s->tx_info.nss_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_nss(t30_state_t *s, const uint8_t *nss[]) -{ - if (nss) - *nss = s->rx_info.nss; - /*endif*/ - return s->rx_info.nss_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_tsa(t30_state_t *s, int type, const char *address, int len) -{ - if (s->tx_info.tsa) - span_free(s->tx_info.tsa); - /*endif*/ - if (address == NULL || len == 0) - { - s->tx_info.tsa = NULL; - s->tx_info.tsa_len = 0; - return 0; - } - /*endif*/ - s->tx_info.tsa_type = type; - if (len < 0) - len = strlen(address); - /*endif*/ - if ((s->tx_info.tsa = span_alloc(len))) - { - memcpy(s->tx_info.tsa, address, len); - s->tx_info.tsa_len = len; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_tsa(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->tx_info.tsa_type; - /*endif*/ - if (address) - *address = s->tx_info.tsa; - /*endif*/ - return s->tx_info.tsa_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_tsa(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->rx_info.tsa_type; - /*endif*/ - if (address) - *address = s->rx_info.tsa; - /*endif*/ - return s->rx_info.tsa_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_ira(t30_state_t *s, int type, const char *address, int len) -{ - if (s->tx_info.ira) - span_free(s->tx_info.ira); - /*endif*/ - if (address == NULL) - { - s->tx_info.ira = NULL; - return 0; - } - /*endif*/ - s->tx_info.ira = strdup(address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_ira(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->tx_info.ira_type; - /*endif*/ - if (address) - *address = s->tx_info.ira; - /*endif*/ - return s->tx_info.ira_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_ira(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->rx_info.ira_type; - /*endif*/ - if (address) - *address = s->rx_info.ira; - /*endif*/ - return s->rx_info.ira_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_cia(t30_state_t *s, int type, const char *address, int len) -{ - if (s->tx_info.cia) - span_free(s->tx_info.cia); - /*endif*/ - if (address == NULL) - { - s->tx_info.cia = NULL; - return 0; - } - /*endif*/ - s->tx_info.cia = strdup(address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_cia(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->tx_info.cia_type; - /*endif*/ - if (address) - *address = s->tx_info.cia; - /*endif*/ - return s->tx_info.cia_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_cia(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->rx_info.cia_type; - /*endif*/ - if (address) - *address = s->rx_info.cia; - /*endif*/ - return s->rx_info.cia_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_isp(t30_state_t *s, int type, const char *address, int len) -{ - if (s->tx_info.isp) - span_free(s->tx_info.isp); - /*endif*/ - if (address == NULL) - { - s->tx_info.isp = NULL; - return 0; - } - /*endif*/ - s->tx_info.isp = strdup(address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_isp(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->tx_info.isp_type; - /*endif*/ - if (address) - *address = s->tx_info.isp; - /*endif*/ - return s->tx_info.isp_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_isp(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->rx_info.isp_type; - /*endif*/ - if (address) - *address = s->rx_info.isp; - /*endif*/ - return s->rx_info.isp_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_csa(t30_state_t *s, int type, const char *address, int len) -{ - if (s->tx_info.csa) - span_free(s->tx_info.csa); - /*endif*/ - if (address == NULL) - { - s->tx_info.csa = NULL; - return 0; - } - /*endif*/ - s->tx_info.csa = strdup(address); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_csa(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->tx_info.csa_type; - /*endif*/ - if (address) - *address = s->tx_info.csa; - /*endif*/ - return s->tx_info.csa_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_rx_csa(t30_state_t *s, int *type, const char *address[]) -{ - if (type) - *type = s->rx_info.csa_type; - /*endif*/ - if (address) - *address = s->rx_info.csa; - /*endif*/ - return s->rx_info.csa_len; -} -/*- End of function --------------------------------------------------------*/ - -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); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_tx_page_header_info(t30_state_t *s, const char *info) -{ - if (info == NULL) - { - s->header_info[0] = '\0'; - return 0; - } - /*endif*/ - if (strlen(info) > T30_MAX_PAGE_HEADER_INFO) - return -1; - /*endif*/ - strcpy(s->header_info, info); - t4_tx_set_header_info(&s->t4.tx, s->header_info); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(size_t) t30_get_tx_page_header_info(t30_state_t *s, char *info) -{ - if (info) - strcpy(info, s->header_info); - /*endif*/ - return strlen(s->header_info); -} -/*- End of function --------------------------------------------------------*/ - -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; - t4_tx_set_header_tz(&s->t4.tx, &s->tz); - return 0; - } - /*endif*/ - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_country(t30_state_t *s) -{ - return s->country; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_vendor(t30_state_t *s) -{ - return s->vendor; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t30_get_rx_model(t30_state_t *s) -{ - return s->model; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_rx_file(t30_state_t *s, const char *file, int stop_page) -{ - strncpy(s->rx_file, file, sizeof(s->rx_file)); - s->rx_file[sizeof(s->rx_file) - 1] = '\0'; - s->rx_stop_page = stop_page; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_tx_file(t30_state_t *s, const char *file, int start_page, int stop_page) -{ - strncpy(s->tx_file, file, sizeof(s->tx_file)); - s->tx_file[sizeof(s->tx_file) - 1] = '\0'; - s->tx_start_page = start_page; - s->tx_stop_page = stop_page; -} -/*- End of function --------------------------------------------------------*/ - -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, bool enabled) -{ - s->ecm_allowed = enabled; - t30_build_dis_or_dtc(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_keep_bad_quality_pages(t30_state_t *s, bool keep_bad_pages) -{ - 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 --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_minimum_scan_line_time(t30_state_t *s, int min_time) -{ - /* There are only certain possible times supported, so we need to select - the code which best matches the request. */ - if (min_time == 0) - s->local_min_scan_time_code = 7; - else if (min_time <= 5) - s->local_min_scan_time_code = 1; - else if (min_time <= 10) - s->local_min_scan_time_code = 2; - else if (min_time <= 20) - s->local_min_scan_time_code = 0; - else if (min_time <= 40) - s->local_min_scan_time_code = 4; - else - return -1; - /*endif*/ - t30_build_dis_or_dtc(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_supported_modems(t30_state_t *s, int supported_modems) -{ - s->supported_modems = supported_modems; - t30_build_dis_or_dtc(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_supported_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_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_bilevel_resolutions(t30_state_t *s, int 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; -} -/*- End of function --------------------------------------------------------*/ - -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; - /*endif*/ - if ((supported_image_sizes & T4_SUPPORT_WIDTH_303MM)) - supported_image_sizes |= T4_SUPPORT_WIDTH_255MM; - /*endif*/ - s->supported_image_sizes = supported_image_sizes; - t30_build_dis_or_dtc(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_supported_t30_features(t30_state_t *s, int supported_t30_features) -{ - s->supported_t30_features = supported_t30_features; - t30_build_dis_or_dtc(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_status(t30_state_t *s, int status) -{ - if (s->current_status != status) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Status changing to '%s'\n", t30_completion_code_to_str(status)); - s->current_status = status; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t30_set_receiver_not_ready(t30_state_t *s, int count) -{ - s->receiver_not_ready_count = count; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_phase_b_handler(t30_state_t *s, t30_phase_b_handler_t handler, void *user_data) -{ - s->phase_b_handler = handler; - s->phase_b_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_phase_d_handler(t30_state_t *s, t30_phase_d_handler_t handler, void *user_data) -{ - s->phase_d_handler = handler; - s->phase_d_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_phase_e_handler(t30_state_t *s, t30_phase_e_handler_t handler, void *user_data) -{ - s->phase_e_handler = handler; - s->phase_e_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_document_handler(t30_state_t *s, t30_document_handler_t handler, void *user_data) -{ - s->document_handler = handler; - s->document_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_set_real_time_frame_handler(t30_state_t *s, t30_real_time_frame_handler_t handler, void *user_data) -{ - s->real_time_frame_handler = handler; - s->real_time_frame_user_data = user_data; -} -/*- 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; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30_local.h b/libs/spandsp/src/t30_local.h deleted file mode 100644 index 3152ad94ea..0000000000 --- a/libs/spandsp/src/t30_local.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_local.h - definitions for T.30 fax processing - * - * 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 */ - -#if !defined(_T30_LOCAL_H_) -#define _T30_LOCAL_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -int t30_build_dis_or_dtc(t30_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30_logging.c b/libs/spandsp/src/t30_logging.c deleted file mode 100644 index 9e7d99f330..0000000000 --- a/libs/spandsp/src/t30_logging.c +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t30_logging.c - ITU T.30 FAX transfer processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 -#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/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/queue.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/hdlc.h" -#include "spandsp/fsk.h" -#include "spandsp/v29rx.h" -#include "spandsp/v29tx.h" -#include "spandsp/v27ter_rx.h" -#include "spandsp/v27ter_tx.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/t30_fcf.h" -#include "spandsp/t35.h" -#include "spandsp/t30.h" -#include "spandsp/t30_logging.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/timezone.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" -#include "spandsp/private/t30.h" - -#include "t30_local.h" - -/*! Value string pair structure */ -typedef struct -{ - int val; - const char *str; -} value_string_t; - -enum -{ - DISBIT1 = 0x01, - DISBIT2 = 0x02, - DISBIT3 = 0x04, - DISBIT4 = 0x08, - DISBIT5 = 0x10, - DISBIT6 = 0x20, - DISBIT7 = 0x40, - DISBIT8 = 0x80 -}; - -SPAN_DECLARE(const char *) t30_completion_code_to_str(int result) -{ - switch (result) - { - case T30_ERR_OK: - return "OK"; - case T30_ERR_CEDTONE: - return "The CED tone exceeded 5s"; - case T30_ERR_T0_EXPIRED: - return "Timed out waiting for initial communication"; - case T30_ERR_T1_EXPIRED: - return "Timed out waiting for the first message"; - case T30_ERR_T3_EXPIRED: - return "Timed out waiting for procedural interrupt"; - case T30_ERR_HDLC_CARRIER: - return "The HDLC carrier did not stop in a timely manner"; - case T30_ERR_CANNOT_TRAIN: - return "Failed to train with any of the compatible modems"; - case T30_ERR_OPER_INT_FAIL: - return "Operator intervention failed"; - case T30_ERR_INCOMPATIBLE: - return "Far end is not compatible"; - case T30_ERR_RX_INCAPABLE: - return "Far end is not able to receive"; - case T30_ERR_TX_INCAPABLE: - return "Far end is not able to transmit"; - case T30_ERR_NORESSUPPORT: - return "Far end cannot receive at the resolution of the image"; - case T30_ERR_NOSIZESUPPORT: - return "Far end cannot receive at the size of image"; - case T30_ERR_UNEXPECTED: - return "Unexpected message received"; - case T30_ERR_TX_BADDCS: - return "Received bad response to DCS or training"; - case T30_ERR_TX_BADPG: - return "Received a DCN from remote after sending a page"; - case T30_ERR_TX_ECMPHD: - return "Invalid ECM response received from receiver"; - case T30_ERR_TX_GOTDCN: - return "Received a DCN while waiting for a DIS"; - case T30_ERR_TX_INVALRSP: - return "Invalid response after sending a page"; - case T30_ERR_TX_NODIS: - return "Received other than DIS while waiting for DIS"; - case T30_ERR_TX_PHBDEAD: - return "Received no response to DCS or TCF"; - case T30_ERR_TX_PHDDEAD: - return "No response after sending a page"; - case T30_ERR_TX_T5EXP: - return "Timed out waiting for receiver ready (ECM mode)"; - case T30_ERR_RX_ECMPHD: - return "Invalid ECM response received from transmitter"; - case T30_ERR_RX_GOTDCS: - return "DCS received while waiting for DTC"; - case T30_ERR_RX_INVALCMD: - return "Unexpected command after page received"; - case T30_ERR_RX_NOCARRIER: - return "Carrier lost during fax receive"; - case T30_ERR_RX_NOEOL: - return "Timed out while waiting for EOL (end Of line)"; - case T30_ERR_RX_NOFAX: - return "Timed out while waiting for first line"; - case T30_ERR_RX_T2EXPDCN: - return "Timer T2 expired while waiting for DCN"; - case T30_ERR_RX_T2EXPD: - return "Timer T2 expired while waiting for phase D"; - case T30_ERR_RX_T2EXPFAX: - return "Timer T2 expired while waiting for fax page"; - case T30_ERR_RX_T2EXPMPS: - return "Timer T2 expired while waiting for next fax page"; - case T30_ERR_RX_T2EXPRR: - return "Timer T2 expired while waiting for RR command"; - case T30_ERR_RX_T2EXP: - return "Timer T2 expired while waiting for NSS, DCS or MCF"; - case T30_ERR_RX_DCNWHY: - return "Unexpected DCN while waiting for DCS or DIS"; - case T30_ERR_RX_DCNDATA: - return "Unexpected DCN while waiting for image data"; - case T30_ERR_RX_DCNFAX: - return "Unexpected DCN while waiting for EOM, EOP or MPS"; - case T30_ERR_RX_DCNPHD: - return "Unexpected DCN after EOM or MPS sequence"; - case T30_ERR_RX_DCNRRD: - return "Unexpected DCN after RR/RNR sequence"; - case T30_ERR_RX_DCNNORTN: - return "Unexpected DCN after requested retransmission"; - case T30_ERR_FILEERROR: - return "TIFF/F file cannot be opened"; - case T30_ERR_NOPAGE: - return "TIFF/F page not found"; - case T30_ERR_BADTIFF: - return "TIFF/F format is not compatible"; - case T30_ERR_BADPAGE: - return "TIFF/F page number tag missing"; - case T30_ERR_BADTAG: - return "Incorrect values for TIFF/F tags"; - case T30_ERR_BADTIFFHDR: - return "Bad TIFF/F header - incorrect values in fields"; - case T30_ERR_NOMEM: - return "Cannot allocate memory for more pages"; - case T30_ERR_RETRYDCN: - return "Disconnected after permitted retries"; - case T30_ERR_CALLDROPPED: - return "The call dropped prematurely"; - case T30_ERR_NOPOLL: - return "Poll not accepted"; - case T30_ERR_IDENT_UNACCEPTABLE: - return "Ident not accepted"; - case T30_ERR_PSA_UNACCEPTABLE: - return "Polled sub-address not accepted"; - case T30_ERR_SEP_UNACCEPTABLE: - return "Selective polling address not accepted"; - case T30_ERR_SID_UNACCEPTABLE: - return "Sender identification not accepted"; - case T30_ERR_PWD_UNACCEPTABLE: - return "Password not accepted"; - case T30_ERR_SUB_UNACCEPTABLE: - return "Sub-address not accepted"; - case T30_ERR_TSA_UNACCEPTABLE: - return "Transmitting subscriber internet address not accepted"; - case T30_ERR_IRA_UNACCEPTABLE: - return "Internet routing address not accepted"; - case T30_ERR_CIA_UNACCEPTABLE: - return "Calling subscriber internet address not accepted"; - case T30_ERR_ISP_UNACCEPTABLE: - return "Internet selective polling address not accepted"; - case T30_ERR_CSA_UNACCEPTABLE: - return "Called subscriber internet address not accepted"; - } - /*endswitch*/ - return "???"; -} -/*- 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) - { - case T30_DIS: - return "DIS"; - case T30_CSI: - return "CSI"; - case T30_NSF: - return "NSF"; - case T30_DTC: - return "DTC"; - case T30_CIG: - return "CIG"; - case T30_NSC: - return "NSC"; - case T30_PWD: - return "PWD"; - case T30_SEP: - return "SEP"; - case T30_PSA: - return "PSA"; - case T30_CIA: - return "CIA"; - case T30_ISP: - return "ISP"; - case T30_DCS: - case T30_DCS | 0x01: - return "DCS"; - case T30_TSI: - case T30_TSI | 0x01: - return "TSI"; - case T30_NSS: - case T30_NSS | 0x01: - return "NSS"; - case T30_SUB: - case T30_SUB | 0x01: - return "SUB"; - case T30_SID: - case T30_SID | 0x01: - return "SID"; - case T30_CTC: - case T30_CTC | 0x01: - return "CTC"; - case T30_TSA: - case T30_TSA | 0x01: - return "TSA"; - case T30_IRA: - case T30_IRA | 0x01: - return "IRA"; - case T30_CFR: - case T30_CFR | 0x01: - return "CFR"; - case T30_FTT: - case T30_FTT | 0x01: - return "FTT"; - case T30_CTR: - case T30_CTR | 0x01: - return "CTR"; - case T30_CSA: - case T30_CSA | 0x01: - return "CSA"; - case T30_EOM: - case T30_EOM | 0x01: - return "EOM"; - case T30_MPS: - case T30_MPS | 0x01: - return "MPS"; - case T30_EOP: - case T30_EOP | 0x01: - return "EOP"; - case T30_PRI_EOM: - case T30_PRI_EOM | 0x01: - return "PRI-EOM"; - case T30_PRI_MPS: - case T30_PRI_MPS | 0x01: - return "PRI-MPS"; - case T30_PRI_EOP: - case T30_PRI_EOP | 0x01: - return "PRI-EOP"; - case T30_EOS: - case T30_EOS | 0x01: - return "EOS"; - case T30_PPS: - case T30_PPS | 0x01: - return "PPS"; - case T30_EOR: - case T30_EOR | 0x01: - return "EOR"; - case T30_RR: - case T30_RR | 0x01: - return "RR"; - case T30_MCF: - case T30_MCF | 0x01: - return "MCF"; - case T30_RTP: - case T30_RTP | 0x01: - return "RTP"; - case T30_RTN: - case T30_RTN | 0x01: - return "RTN"; - case T30_PIP: - case T30_PIP | 0x01: - return "PIP"; - case T30_PIN: - case T30_PIN | 0x01: - return "PIN"; - case T30_PPR: - case T30_PPR | 0x01: - return "PPR"; - case T30_RNR: - case T30_RNR | 0x01: - return "RNR"; - case T30_ERR: - case T30_ERR | 0x01: - return "ERR"; - case T30_FDM: - case T30_FDM | 0x01: - return "FDM"; - case T30_DCN: - case T30_DCN | 0x01: - return "DCN"; - case T30_CRP: - case T30_CRP | 0x01: - return "CRP"; - case T30_FNV: - case T30_FNV | 0x01: - return "FNV"; - case T30_TNR: - case T30_TNR | 0x01: - return "TNR"; - case T30_TR: - case T30_TR | 0x01: - return "TR"; - case T30_TK: - return "TK"; - case T30_RK: - return "RK"; -#if 0 - case T30_PSS: - return "PSS"; -#endif - case T30_DES: - return "DES"; - case T30_DEC: - return "DEC"; - case T30_DER: - return "DER"; -#if 0 - case T30_DTR: - return "DTR"; -#endif - case T30_DNK: - case T30_DNK | 0x01: - return "DNK"; - case T30_PID: - case T30_PID | 0x01: - return "PID"; - case T30_NULL: - return "NULL"; - case T4_FCD: - return "FCD"; - case T4_CCD: - return "CCD"; - case T4_RCP: - return "RCP"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -static void octet_reserved_bit(logging_state_t *log, - const uint8_t *msg, - int bit_no, - int expected) -{ - char s[10] = ".... ...."; - int bit; - uint8_t octet; - - /* Break out the octet and the bit number within it. */ - octet = msg[((bit_no - 1) >> 3) + 3]; - bit_no = (bit_no - 1) & 7; - /* Now get the actual bit. */ - bit = (octet >> bit_no) & 1; - /* Is it what it should be. */ - if (bit ^ expected) - { - /* Only log unexpected values. */ - s[7 - bit_no + ((bit_no < 4) ? 1 : 0)] = (uint8_t) (bit + '0'); - span_log(log, SPAN_LOG_FLOW, " %s= Unexpected state for reserved bit: %d\n", s, bit); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void octet_bit_field(logging_state_t *log, - const uint8_t *msg, - int bit_no, - const char *desc, - const char *yeah, - const char *neigh) -{ - char s[10] = ".... ...."; - int bit; - uint8_t octet; - const char *tag; - - /* Break out the octet and the bit number within it. */ - octet = msg[((bit_no - 1) >> 3) + 3]; - bit_no = (bit_no - 1) & 7; - /* Now get the actual bit. */ - bit = (octet >> bit_no) & 1; - /* Edit the bit string for display. */ - s[7 - bit_no + ((bit_no < 4) ? 1 : 0)] = (uint8_t) (bit + '0'); - /* Find the right tag to display. */ - if (bit) - { - if ((tag = yeah) == NULL) - tag = "Set"; - /*endif*/ - } - else - { - if ((tag = neigh) == NULL) - tag = "Not set"; - /*endif*/ - } - /*endif*/ - /* Eh, voila! */ - span_log(log, SPAN_LOG_FLOW, " %s= %s: %s\n", s, desc, tag); -} -/*- End of function --------------------------------------------------------*/ - -static void octet_field(logging_state_t *log, - const uint8_t *msg, - int start, - int end, - const char *desc, - const value_string_t tags[]) -{ - char s[10] = ".... ...."; - int i; - uint8_t octet; - const char *tag; - - /* Break out the octet and the bit number range within it. */ - octet = msg[((start - 1) >> 3) + 3]; - start = (start - 1) & 7; - end = ((end - 1) & 7) + 1; - - /* Edit the bit string for display. */ - for (i = start; i < end; i++) - s[7 - i + ((i < 4) ? 1 : 0)] = (uint8_t) ((octet >> i) & 1) + '0'; - /*endfor*/ - - /* Find the right tag to display. */ - octet = (uint8_t) ((octet >> start) & ((0xFF + (1 << (end - start))) & 0xFF)); - tag = "Invalid"; - for (i = 0; tags[i].str; i++) - { - if (octet == tags[i].val) - { - tag = tags[i].str; - break; - } - /*endif*/ - } - /*endfor*/ - /* Eh, voila! */ - span_log(log, SPAN_LOG_FLOW, " %s= %s: %s\n", s, desc, tag); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *pkt, int len) -{ - logging_state_t *log; - uint8_t frame_type; - static const value_string_t available_signalling_rate_tags[] = - { - { 0x00, "V.27 ter fall-back mode" }, - { 0x01, "V.29" }, - { 0x02, "V.27 ter" }, - { 0x03, "V.27 ter and V.29" }, - { 0x0B, "V.27 ter, V.29, and V.17" }, - { 0x06, "Reserved" }, - { 0x0A, "Reserved" }, - { 0x0E, "Reserved" }, - { 0x0F, "Reserved" }, - { 0x04, "Not used" }, - { 0x05, "Not used" }, - { 0x08, "Not used" }, - { 0x09, "Not used" }, - { 0x0C, "Not used" }, - { 0x0D, "Not used" }, - { 0x00, NULL } - }; - static const value_string_t selected_signalling_rate_tags[] = - { - { 0x00, "V.27ter 2400bps" }, - { 0x01, "V.29, 9600bps" }, - { 0x02, "V.27ter 4800bps" }, - { 0x03, "V.29 7200bps" }, - { 0x08, "V.17 14400bps" }, - { 0x09, "V.17 9600bps" }, - { 0x0A, "V.17 12000bps" }, - { 0x0B, "V.17 7200bps" }, - { 0x05, "Reserved" }, - { 0x07, "Reserved" }, - { 0x0C, "Reserved" }, - { 0x0D, "Reserved" }, - { 0x0E, "Reserved" }, - { 0x0F, "Reserved" }, - { 0x00, NULL } - }; - static const value_string_t available_scan_line_length_tags[] = - { - { 0x00, "215mm +- 1%" }, - { 0x01, "215mm +- 1% and 255mm +- 1%" }, - { 0x02, "215mm +- 1%, 255mm +- 1% and 303mm +- 1%" }, - { 0x00, NULL } - }; - static const value_string_t selected_scan_line_length_tags[] = - { - { 0x00, "215mm +- 1%" }, - { 0x01, "255mm +- 1%" }, - { 0x02, "303mm +- 1%" }, - { 0x00, NULL } - }; - static const value_string_t available_recording_length_tags[] = - { - { 0x00, "A4 (297mm)" }, - { 0x01, "A4 (297mm) and B4 (364mm)" }, - { 0x02, "Unlimited" }, - { 0x00, NULL } - }; - static const value_string_t selected_recording_length_tags[] = - { - { 0x00, "A4 (297mm)" }, - { 0x01, "B4 (364mm)" }, - { 0x02, "Unlimited" }, - { 0x00, NULL } - }; - static const value_string_t available_minimum_scan_line_time_tags[] = - { - { 0x00, "20ms at 3.85 l/mm; T7.7 = T3.85" }, - { 0x01, "5ms at 3.85 l/mm; T7.7 = T3.85" }, - { 0x02, "10ms at 3.85 l/mm; T7.7 = T3.85" }, - { 0x03, "20ms at 3.85 l/mm; T7.7 = 1/2 T3.85" }, - { 0x04, "40ms at 3.85 l/mm; T7.7 = T3.85" }, - { 0x05, "40ms at 3.85 l/mm; T7.7 = 1/2 T3.85" }, - { 0x06, "10ms at 3.85 l/mm; T7.7 = 1/2 T3.85" }, - { 0x07, "0ms at 3.85 l/mm; T7.7 = T3.85" }, - { 0x00, NULL } - }; - static const value_string_t selected_minimum_scan_line_time_tags[] = - { - { 0x00, "20ms" }, - { 0x01, "5ms" }, - { 0x02, "10ms" }, - { 0x04, "40ms" }, - { 0x07, "0ms" }, - { 0x00, NULL } - }; - static const value_string_t shared_data_memory_capacity_tags[] = - { - { 0x00, "Not available" }, - { 0x01, "Level 2 = 2.0 Mbytes" }, - { 0x02, "Level 1 = 1.0 Mbytes" }, - { 0x03, "Level 3 = unlimited (i.e. >= 32 Mbytes)" }, - { 0x00, NULL } - }; - static const value_string_t t89_profile_tags[] = - { - { 0x00, "Not used" }, - { 0x01, "Profiles 2 and 3" }, - { 0x02, "Profile 2" }, - { 0x04, "Profile 1" }, - { 0x06, "Profile 3" }, - { 0x03, "Reserved" }, - { 0x05, "Reserved" }, - { 0x07, "Reserved" }, - { 0x00, NULL } - }; - static const value_string_t t44_mixed_raster_content_tags[] = - { - { 0x00, "0" }, - { 0x01, "1" }, - { 0x02, "2" }, - { 0x32, "3" }, - { 0x04, "4" }, - { 0x05, "5" }, - { 0x06, "6" }, - { 0x07, "7" }, - { 0x00, NULL } - }; - - if (!span_log_test(&s->logging, SPAN_LOG_FLOW)) - return; - /*endif*/ - frame_type = pkt[2] & 0xFE; - log = &s->logging; - if (len <= 2) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - span_log(log, SPAN_LOG_FLOW, "%s:\n", t30_frametype(pkt[2])); - if (len <= 3) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - octet_bit_field(log, pkt, 1, "Store and forward Internet fax (T.37)", NULL, NULL); - octet_reserved_bit(log, pkt, 2, 0); - octet_bit_field(log, pkt, 3, "Real-time Internet fax (T.38)", NULL, NULL); - octet_bit_field(log, pkt, 4, "3G mobile network", NULL, NULL); - octet_reserved_bit(log, pkt, 5, 0); - if (frame_type == T30_DCS) - { - octet_reserved_bit(log, pkt, 6, 0); - octet_reserved_bit(log, pkt, 7, 0); - } - else - { - octet_bit_field(log, pkt, 6, "V.8 capabilities", NULL, NULL); - octet_bit_field(log, pkt, 7, "Preferred octets", "64 octets", "256 octets"); - } - /*endif*/ - octet_reserved_bit(log, pkt, 8, 0); - if (len <= 4) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - if (frame_type == T30_DCS) - { - octet_reserved_bit(log, pkt, 9, 0); - octet_bit_field(log, pkt, 10, "Receive fax", NULL, NULL); - octet_field(log, pkt, 11, 14, "Selected data signalling rate", selected_signalling_rate_tags); - } - else - { - octet_bit_field(log, pkt, 9, "Ready to transmit a fax document (polling)", NULL, NULL); - octet_bit_field(log, pkt, 10, "Can receive fax", NULL, NULL); - octet_field(log, pkt, 11, 14, "Supported data signalling rates", available_signalling_rate_tags); - } - /*endif*/ - octet_bit_field(log, pkt, 15, "R8x7.7lines/mm and/or 200x200pels/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 16, "2-D coding", NULL, NULL); - if (len <= 5) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - if (frame_type == T30_DCS) - { - octet_field(log, pkt, 17, 18, "Recording width", selected_scan_line_length_tags); - octet_field(log, pkt, 19, 20, "Recording length", selected_recording_length_tags); - octet_field(log, pkt, 21, 23, "Minimum scan line time", selected_minimum_scan_line_time_tags); - } - else - { - octet_field(log, pkt, 17, 18, "Recording width", available_scan_line_length_tags); - octet_field(log, pkt, 19, 20, "Recording length", available_recording_length_tags); - octet_field(log, pkt, 21, 23, "Receiver's minimum scan line time", available_minimum_scan_line_time_tags); - } - /*endif*/ - octet_bit_field(log, pkt, 24, "Extension indicator", NULL, NULL); - if (!(pkt[5] & DISBIT8)) - return; - /*endif*/ - if (len <= 6) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_reserved_bit(log, pkt, 25, 0); - octet_bit_field(log, pkt, 26, "Compressed/uncompressed mode", "Uncompressed", "Compressed"); - octet_bit_field(log, pkt, 27, "Error correction mode (ECM)", "ECM", "Non-ECM"); - if (frame_type == T30_DCS) - octet_bit_field(log, pkt, 28, "Frame size", "64 octets", "256 octets"); - else - octet_reserved_bit(log, pkt, 28, 0); - /*endif*/ - octet_reserved_bit(log, pkt, 29, 0); - octet_reserved_bit(log, pkt, 30, 0); - octet_bit_field(log, pkt, 31, "T.6 coding", NULL, NULL); - octet_bit_field(log, pkt, 32, "Extension indicator", NULL, NULL); - if (!(pkt[6] & DISBIT8)) - return; - /*endif*/ - if (len <= 7) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 33, "\"Field not valid\" supported", NULL, NULL); - if (frame_type == T30_DCS) - { - octet_reserved_bit(log, pkt, 34, 0); - octet_reserved_bit(log, pkt, 35, 0); - } - else - { - octet_bit_field(log, pkt, 34, "Multiple selective polling", NULL, NULL); - octet_bit_field(log, pkt, 35, "Polled sub-address", NULL, NULL); - } - /*endif*/ - octet_bit_field(log, pkt, 36, "T.43 coding", NULL, NULL); - octet_bit_field(log, pkt, 37, "Plane interleave", NULL, NULL); - octet_bit_field(log, pkt, 38, "Voice coding with 32kbit/s ADPCM (Rec. G.726)", NULL, NULL); - octet_bit_field(log, pkt, 39, "Reserved for the use of extended voice coding set", NULL, NULL); - octet_bit_field(log, pkt, 40, "Extension indicator", NULL, NULL); - if (!(pkt[7] & DISBIT8)) - return; - /*endif*/ - if (len <= 8) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - octet_bit_field(log, pkt, 41, "R8x15.4lines/mm", NULL, NULL); - octet_bit_field(log, pkt, 42, "300x300pels/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 43, "R16x15.4lines/mm and/or 400x400pels/25.4mm", NULL, NULL); - if (frame_type == T30_DCS) - { - octet_bit_field(log, pkt, 44, "Resolution type selection", "Inch", "Metric"); - octet_reserved_bit(log, pkt, 45, 0); - octet_reserved_bit(log, pkt, 46, 0); - octet_reserved_bit(log, pkt, 47, 0); - } - else - { - octet_bit_field(log, pkt, 44, "Inch-based resolution preferred", NULL, NULL); - octet_bit_field(log, pkt, 45, "Metric-based resolution preferred", NULL, NULL); - octet_bit_field(log, pkt, 46, "Minimum scan line time for higher resolutions", "T15.4 = 1/2 T7.7", "T15.4 = T7.7"); - octet_bit_field(log, pkt, 47, "Selective polling", NULL, NULL); - } - /*endif*/ - octet_bit_field(log, pkt, 48, "Extension indicator", NULL, NULL); - if (!(pkt[8] & DISBIT8)) - return; - /*endif*/ - if (len <= 9) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 49, "Sub-addressing", NULL, NULL); - if (frame_type == T30_DCS) - { - octet_bit_field(log, pkt, 50, "Sender identification transmission", NULL, NULL); - octet_reserved_bit(log, pkt, 51, 0); - } - else - { - octet_bit_field(log, pkt, 50, "Password", NULL, NULL); - octet_bit_field(log, pkt, 51, "Ready to transmit a data file (polling)", NULL, NULL); - } - /*endif*/ - octet_reserved_bit(log, pkt, 52, 0); - octet_bit_field(log, pkt, 53, "Binary file transfer (BFT)", NULL, NULL); - octet_bit_field(log, pkt, 54, "Document transfer mode (DTM)", NULL, NULL); - octet_bit_field(log, pkt, 55, "Electronic data interchange (EDI)", NULL, NULL); - octet_bit_field(log, pkt, 56, "Extension indicator", NULL, NULL); - if (!(pkt[9] & DISBIT8)) - return; - /*endif*/ - if (len <= 10) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 57, "Basic transfer mode (BTM)", NULL, NULL); - octet_reserved_bit(log, pkt, 58, 0); - if (frame_type == T30_DCS) - octet_reserved_bit(log, pkt, 59, 0); - else - octet_bit_field(log, pkt, 59, "Ready to transfer a character or mixed mode document (polling)", NULL, NULL); - /*endif*/ - octet_bit_field(log, pkt, 60, "Character mode", NULL, NULL); - octet_reserved_bit(log, pkt, 61, 0); - octet_bit_field(log, pkt, 62, "Mixed mode (Annex E/T.4)", NULL, NULL); - octet_reserved_bit(log, pkt, 63, 0); - octet_bit_field(log, pkt, 64, "Extension indicator", NULL, NULL); - if (!(pkt[10] & DISBIT8)) - return; - /*endif*/ - if (len <= 11) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 65, "Processable mode 26 (Rec. T.505)", NULL, NULL); - octet_bit_field(log, pkt, 66, "Digital network capability", NULL, NULL); - octet_bit_field(log, pkt, 67, "Duplex capability", "Full", "Half only"); - if (frame_type == T30_DCS) - octet_bit_field(log, pkt, 68, "Full colour mode", NULL, NULL); - else - octet_bit_field(log, pkt, 68, "JPEG coding", NULL, NULL); - /*endif*/ - octet_bit_field(log, pkt, 69, "Full colour mode", NULL, NULL); - if (frame_type == T30_DCS) - octet_bit_field(log, pkt, 70, "Preferred Huffman tables", NULL, NULL); - else - octet_reserved_bit(log, pkt, 70, 0); - /*endif*/ - octet_bit_field(log, pkt, 71, "12bits/pel component", NULL, NULL); - octet_bit_field(log, pkt, 72, "Extension indicator", NULL, NULL); - if (!(pkt[11] & DISBIT8)) - return; - /*endif*/ - if (len <= 12) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 73, "No subsampling (1:1:1)", NULL, NULL); - octet_bit_field(log, pkt, 74, "Custom illuminant", NULL, NULL); - octet_bit_field(log, pkt, 75, "Custom gamut range", NULL, NULL); - octet_bit_field(log, pkt, 76, "North American Letter (215.9mm x 279.4mm)", NULL, NULL); - octet_bit_field(log, pkt, 77, "North American Legal (215.9mm x 355.6mm)", NULL, NULL); - octet_bit_field(log, pkt, 78, "Single-progression sequential coding (Rec. T.85) basic", NULL, NULL); - octet_bit_field(log, pkt, 79, "Single-progression sequential coding (Rec. T.85) optional L0", NULL, NULL); - octet_bit_field(log, pkt, 80, "Extension indicator", NULL, NULL); - if (!(pkt[12] & DISBIT8)) - return; - /*endif*/ - if (len <= 13) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 81, "HKM key management", NULL, NULL); - octet_bit_field(log, pkt, 82, "RSA key management", NULL, NULL); - octet_bit_field(log, pkt, 83, "Override", NULL, NULL); - octet_bit_field(log, pkt, 84, "HFX40 cipher", NULL, NULL); - octet_bit_field(log, pkt, 85, "Alternative cipher number 2", NULL, NULL); - octet_bit_field(log, pkt, 86, "Alternative cipher number 3", NULL, NULL); - octet_bit_field(log, pkt, 87, "HFX40-I hashing", NULL, NULL); - octet_bit_field(log, pkt, 88, "Extension indicator", NULL, NULL); - if (!(pkt[13] & DISBIT8)) - return; - /*endif*/ - if (len <= 14) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 89, "Alternative hashing system 2", NULL, NULL); - octet_bit_field(log, pkt, 90, "Alternative hashing system 3", NULL, NULL); - octet_bit_field(log, pkt, 91, "Reserved for future security features", NULL, NULL); - octet_field(log, pkt, 92, 94, "T.44 (Mixed Raster Content)", t44_mixed_raster_content_tags); - octet_bit_field(log, pkt, 95, "Page length maximum stripe size for T.44 (Mixed Raster Content)", NULL, NULL); - octet_bit_field(log, pkt, 96, "Extension indicator", NULL, NULL); - if (!(pkt[14] & DISBIT8)) - return; - /*endif*/ - if (len <= 15) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 97, "Colour/gray-scale 300pels/25.4mm x 300lines/25.4mm or 400pels/25.4mm x 400lines/25.4mm resolution", NULL, NULL); - octet_bit_field(log, pkt, 98, "100pels/25.4mm x 100lines/25.4mm for colour/gray scale", NULL, NULL); - octet_bit_field(log, pkt, 99, "Simple phase C BFT negotiations", NULL, NULL); - if (frame_type == T30_DCS) - { - octet_reserved_bit(log, pkt, 100, 0); - octet_reserved_bit(log, pkt, 101, 0); - } - else - { - octet_bit_field(log, pkt, 100, "Extended BFT Negotiations capable", NULL, NULL); - octet_bit_field(log, pkt, 101, "Internet Selective Polling address (ISP)", NULL, NULL); - } - /*endif*/ - octet_bit_field(log, pkt, 102, "Internet Routing Address (IRA)", NULL, NULL); - octet_reserved_bit(log, pkt, 103, 0); - octet_bit_field(log, pkt, 104, "Extension indicator", NULL, NULL); - if (!(pkt[15] & DISBIT8)) - return; - /*endif*/ - if (len <= 16) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 105, "600pels/25.4mm x 600lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 106, "1200pels/25.4mm x 1200lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 107, "300pels/25.4mm x 600lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 108, "400pels/25.4mm x 800lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 109, "600pels/25.4mm x 1200lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 110, "Colour/gray scale 600pels/25.4mm x 600lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 111, "Colour/gray scale 1200pels/25.4mm x 1200lines/25.4mm", NULL, NULL); - octet_bit_field(log, pkt, 112, "Extension indicator", NULL, NULL); - if (!(pkt[16] & DISBIT8)) - return; - /*endif*/ - if (len <= 17) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 113, "Double sided printing capability (alternate mode)", NULL, NULL); - octet_bit_field(log, pkt, 114, "Double sided printing capability (continuous mode)", NULL, NULL); - if (frame_type == T30_DCS) - octet_bit_field(log, pkt, 115, "Black and white mixed raster content profile (MRCbw)", NULL, NULL); - else - octet_reserved_bit(log, pkt, 115, 0); - /*endif*/ - octet_bit_field(log, pkt, 116, "T.45 (run length colour encoded)", NULL, NULL); - octet_field(log, pkt, 117, 118, "Shared memory", shared_data_memory_capacity_tags); - octet_bit_field(log, pkt, 119, "T.44 colour space", NULL, NULL); - octet_bit_field(log, pkt, 120, "Extension indicator", NULL, NULL); - if (!(pkt[17] & DISBIT8)) - return; - /*endif*/ - if (len <= 18) - { - span_log(log, SPAN_LOG_FLOW, " Frame is short\n"); - return; - } - /*endif*/ - - octet_bit_field(log, pkt, 121, "Flow control capability for T.38 communication", NULL, NULL); - octet_bit_field(log, pkt, 122, "K>4", NULL, NULL); - octet_bit_field(log, pkt, 123, "Internet aware T.38 mode fax (not affected by data signal rate bits)", NULL, NULL); - octet_field(log, pkt, 124, 126, "T.89 (Application profiles for ITU-T Rec T.88)", t89_profile_tags); - octet_bit_field(log, pkt, 127, "sYCC-JPEG coding", NULL, NULL); - octet_bit_field(log, pkt, 128, "Extension indicator", NULL, NULL); - if (!(pkt[18] & DISBIT8)) - return; - /*endif*/ - - span_log(log, SPAN_LOG_FLOW, " Extended beyond the current T.30 specification!\n"); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c deleted file mode 100644 index 91e1e8063c..0000000000 --- a/libs/spandsp/src/t31.c +++ /dev/null @@ -1,3090 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t31.c - A T.31 compatible class 1 FAX modem interface. - * - * Written by Steve Underwood - * - * Special thanks to Lee Howard - * for his great work debugging and polishing this code. - * - * Copyright (C) 2004, 2005, 2006, 2008 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 -#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 "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" -#include "spandsp/complex.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/crc.h" -#include "spandsp/hdlc.h" -#include "spandsp/vector_int.h" -#include "spandsp/silence_gen.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/fsk.h" -#include "spandsp/modem_connect_tones.h" -#include "spandsp/v8.h" -#include "spandsp/v29tx.h" -#include "spandsp/v29rx.h" -#include "spandsp/v27ter_tx.h" -#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/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/t30.h" -#include "spandsp/t30_logging.h" -#include "spandsp/t38_core.h" - -#include "spandsp/at_interpreter.h" -#include "spandsp/fax_modems.h" -#include "spandsp/t31.h" -#include "spandsp/t30_fcf.h" - -#include "spandsp/private/logging.h" -#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" -#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" -#include "spandsp/private/v27ter_rx.h" -#include "spandsp/private/v29tx.h" -#include "spandsp/private/v29rx.h" -#include "spandsp/private/hdlc.h" -#include "spandsp/private/fax_modems.h" -#include "spandsp/private/at_interpreter.h" -#include "spandsp/private/t31.h" - -/* Settings suitable for paced transmission over a UDP transport */ -/*! The default number of milliseconds per transmitted IFP when sending bulk T.38 data */ -#define US_PER_TX_CHUNK 30000 -/*! The number of transmissions of indicator IFP packets */ -#define INDICATOR_TX_COUNT 3 -/*! The number of transmissions of data IFP packets */ -#define DATA_TX_COUNT 1 -/*! The number of transmissions of terminating data IFP packets */ -#define DATA_END_TX_COUNT 3 -/*! The default DTE timeout, in seconds */ -#define DEFAULT_DTE_TIMEOUT 5 - -/* Settings suitable for unpaced transmission over a TCP transport */ -#define MAX_OCTETS_PER_UNPACED_CHUNK 300 - -/* Backstop timeout if reception of packets stops in the middle of a burst */ -#define MID_RX_TIMEOUT 15000 - -#define HDLC_FRAMING_OK_THRESHOLD 5 - -typedef const char *(*at_cmd_service_t)(t31_state_t *s, const char *cmd); - -enum -{ - ETX = 0x03, - DLE = 0x10, - SUB = 0x1A -}; - -enum -{ - DISBIT1 = 0x01, - DISBIT2 = 0x02, - DISBIT3 = 0x04, - DISBIT4 = 0x08, - DISBIT5 = 0x10, - DISBIT6 = 0x20, - DISBIT7 = 0x40, - DISBIT8 = 0x80 -}; - -enum -{ - T38_CHUNKING_MERGE_FCS_WITH_DATA = 0x0001, - T38_CHUNKING_WHOLE_FRAMES = 0x0002, - T38_CHUNKING_ALLOW_TEP_TIME = 0x0004, - T38_CHUNKING_SEND_REGULAR_INDICATORS = 0x0008, - T38_CHUNKING_SEND_2S_REGULAR_INDICATORS = 0x0010 -}; - -enum -{ - T38_TIMED_STEP_NONE = 0, - T38_TIMED_STEP_NON_ECM_MODEM = 0x10, - T38_TIMED_STEP_NON_ECM_MODEM_2 = 0x11, - T38_TIMED_STEP_NON_ECM_MODEM_3 = 0x12, - T38_TIMED_STEP_NON_ECM_MODEM_4 = 0x13, - T38_TIMED_STEP_NON_ECM_MODEM_5 = 0x14, - T38_TIMED_STEP_HDLC_MODEM = 0x20, - T38_TIMED_STEP_HDLC_MODEM_2 = 0x21, - T38_TIMED_STEP_HDLC_MODEM_3 = 0x22, - T38_TIMED_STEP_HDLC_MODEM_4 = 0x23, - T38_TIMED_STEP_HDLC_MODEM_5 = 0x24, - T38_TIMED_STEP_CED = 0x30, - T38_TIMED_STEP_CED_2 = 0x31, - T38_TIMED_STEP_CED_3 = 0x32, - T38_TIMED_STEP_CNG = 0x40, - T38_TIMED_STEP_CNG_2 = 0x41, - T38_TIMED_STEP_PAUSE = 0x50, - T38_TIMED_STEP_NO_SIGNAL = 0x60 -}; - -static int restart_modem(t31_state_t *s, int new_modem); -static void hdlc_accept_frame(void *user_data, const uint8_t *msg, int len, int ok); -static void hdlc_accept_t38_frame(void *user_data, const uint8_t *msg, int len, int ok); -static void hdlc_accept_non_ecm_frame(void *user_data, const uint8_t *msg, int len, int ok); -static int silence_rx(void *user_data, const int16_t amp[], int len); -static int initial_timed_rx(void *user_data, const int16_t amp[], int len); -static void non_ecm_put_bit(void *user_data, int bit); -static void non_ecm_put(void *user_data, const uint8_t buf[], int len); -static int non_ecm_get(void *user_data, uint8_t buf[], int len); -static void non_ecm_rx_status(void *user_data, int status); -static void hdlc_rx_status(void *user_data, int status); - -static __inline__ void t31_set_at_rx_mode(t31_state_t *s, int new_mode) -{ - s->at_state.at_rx_mode = new_mode; -} -/*- End of function --------------------------------------------------------*/ - -static int front_end_status(t31_state_t *s, int status) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Front end status %d\n", status); - switch (status) - { - case T30_FRONT_END_SEND_STEP_COMPLETE: - switch (s->modem) - { - case FAX_MODEM_SILENCE_TX: - s->modem = FAX_MODEM_NONE; - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - if (s->at_state.do_hangup) - { - 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; - } - else - { - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - } - /*endif*/ - break; - case FAX_MODEM_CED_TONE_TX: - /* Go directly to V.21/HDLC transmit. */ - s->modem = FAX_MODEM_NONE; - restart_modem(s, FAX_MODEM_V21_TX); - t31_set_at_rx_mode(s, AT_MODE_HDLC); - break; - case FAX_MODEM_V21_TX: - case FAX_MODEM_V17_TX: - case FAX_MODEM_V27TER_TX: - case FAX_MODEM_V29_TX: - s->modem = FAX_MODEM_NONE; - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - restart_modem(s, FAX_MODEM_SILENCE_TX); - break; - } - /*endswitch*/ - break; - case T30_FRONT_END_RECEIVE_COMPLETE: - break; - } - /*endswitch*/ - if (s->t38_fe.timed_step == T38_TIMED_STEP_NONE) - return -1; - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int extra_bits_in_stuffed_frame(const uint8_t buf[], int len) -{ - int bitstream; - int ones; - int stuffed; - int i; - int j; - - ones = 0; - stuffed = 0; - /* We should really append the CRC, and include the stuffed bits for that, to get - the exact number of bits in the frame. */ - //len = crc_itu16_append(buf, len); - for (i = 0; i < len; i++) - { - bitstream = buf[i]; - for (j = 0; j < 8; j++) - { - if ((bitstream & 1)) - { - if (++ones >= 5) - { - ones = 0; - stuffed++; - } - /*endif*/ - } - else - { - ones = 0; - } - /*endif*/ - bitstream >>= 1; - } - /*endfor*/ - } - /*endfor*/ - /* The total length of the frame is: - the number of bits in the body - + the number of additional bits in the body due to stuffing - + the number of bits in the CRC - + the number of additional bits in the CRC due to stuffing - + 16 bits for the two terminating flag octets. - Lets just allow 3 bits for the CRC, which is the worst case. It - avoids calculating the real CRC, and the worst it can do is cause - a flag octet's worth of additional output. - */ - return stuffed + 16 + 3 + 16; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_no, int expected_seq_no) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - s->t38_fe.rx_data_missing = true; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator) -{ - t31_state_t *s; - t31_t38_front_end_state_t *fe; - - s = (t31_state_t *) user_data; - fe = &s->t38_fe; - - if (t->current_rx_indicator == indicator) - { - /* This is probably due to the far end repeating itself, or slipping - preamble messages in between HDLC frames. T.38/V.1.3 tells us to - ignore it. Its harmless. */ - return 0; - } - /*endif*/ - /* In termination mode we don't care very much about indicators telling us training - is starting. We only care about V.21 preamble starting, for timeout control, and - the actual data. */ - switch (indicator) - { - case T38_IND_NO_SIGNAL: - if (t->current_rx_indicator == T38_IND_V21_PREAMBLE - && - (fe->current_rx_type == T30_MODEM_V21 || fe->current_rx_type == T30_MODEM_CNG)) - { - hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN); - } - /*endif*/ - fe->timeout_rx_samples = 0; - front_end_status(s, T30_FRONT_END_SIGNAL_ABSENT); - break; - case T38_IND_CNG: - front_end_status(s, T30_FRONT_END_CNG_PRESENT); - break; - case T38_IND_CED: - front_end_status(s, T30_FRONT_END_CED_PRESENT); - break; - case T38_IND_V21_PREAMBLE: - /* Some T.38 implementations insert these preamble indicators between HDLC frames, so - we need to be tolerant of that. */ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); - break; - case T38_IND_V27TER_2400_TRAINING: - case T38_IND_V27TER_4800_TRAINING: - case T38_IND_V29_7200_TRAINING: - case T38_IND_V29_9600_TRAINING: - case T38_IND_V17_7200_SHORT_TRAINING: - case T38_IND_V17_7200_LONG_TRAINING: - case T38_IND_V17_9600_SHORT_TRAINING: - case T38_IND_V17_9600_LONG_TRAINING: - case T38_IND_V17_12000_SHORT_TRAINING: - case T38_IND_V17_12000_LONG_TRAINING: - case T38_IND_V17_14400_SHORT_TRAINING: - case T38_IND_V17_14400_LONG_TRAINING: - case T38_IND_V33_12000_TRAINING: - case T38_IND_V33_14400_TRAINING: - /* We really don't care what kind of modem is delivering the following image data. - We only care that some kind of fast modem signal is coming next. */ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); - break; - case T38_IND_V8_ANSAM: - case T38_IND_V8_SIGNAL: - case T38_IND_V34_CNTL_CHANNEL_1200: - case T38_IND_V34_PRI_CHANNEL: - case T38_IND_V34_CC_RETRAIN: - /* V.34 support is a work in progress. */ - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); - break; - default: - front_end_status(s, T30_FRONT_END_SIGNAL_ABSENT); - break; - } - /*endswitch*/ - fe->hdlc_rx.len = 0; - fe->rx_data_missing = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void process_hdlc_data(t31_t38_front_end_state_t *fe, const uint8_t *buf, int len) -{ - if (fe->hdlc_rx.len + len <= T31_T38_MAX_HDLC_LEN) - { - bit_reverse(fe->hdlc_rx.buf + fe->hdlc_rx.len, buf, len); - fe->hdlc_rx.len += len; - } - else - { - fe->rx_data_missing = true; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len) -{ - t31_state_t *s; - t31_t38_front_end_state_t *fe; -#if defined(_MSC_VER) - uint8_t *buf2 = (uint8_t *) _alloca(len); -#else - uint8_t buf2[len]; -#endif - - s = (t31_state_t *) user_data; - fe = &s->t38_fe; -#if 0 - /* In termination mode we don't care very much what the data type is. */ - switch (data_type) - { - case T38_DATA_V21: - case T38_DATA_V27TER_2400: - case T38_DATA_V27TER_4800: - case T38_DATA_V29_7200: - case T38_DATA_V29_9600: - case T38_DATA_V17_7200: - case T38_DATA_V17_9600: - case T38_DATA_V17_12000: - case T38_DATA_V17_14400: - case T38_DATA_V8: - case T38_DATA_V34_PRI_RATE: - case T38_DATA_V34_CC_1200: - case T38_DATA_V34_PRI_CH: - case T38_DATA_V33_12000: - case T38_DATA_V33_14400: - default: - break; - } - /*endswitch*/ -#endif - switch (field_type) - { - case T38_FIELD_HDLC_DATA: - if (fe->timeout_rx_samples == 0) - { - /* HDLC can just start without any signal indicator on some platforms, even when - there is zero packet lost. Nasty, but true. Its a good idea to be tolerant of - loss, though, so accepting a sudden start of HDLC data is the right thing to do. */ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); - /* 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; - /*endif*/ - } - /*endif*/ - if (len > 0) - { - process_hdlc_data(fe, buf, len); - } - /*endif*/ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - break; - case T38_FIELD_HDLC_FCS_OK: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (fe->hdlc_rx.len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK (%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) - { - if (fe->hdlc_rx.len >= 3) - { - if ((fe->hdlc_rx.buf[2] & 0xFE) == T30_DCS) - { - /* We need to know if ECM is about to be used, so we can fake HDLC stuff. */ - fe->ecm_mode = (fe->hdlc_rx.len >= 7 && (fe->hdlc_rx.buf[6] & DISBIT3)) ? 1 : 0; - span_log(&s->logging, SPAN_LOG_FLOW, "ECM mode: %d\n", fe->ecm_mode); - } - else if (s->t38_fe.ecm_mode == 1 && (fe->hdlc_rx.buf[2] & 0xFE) == T30_CFR) - { - s->t38_fe.ecm_mode = 2; - } - /*endif*/ - } - /*endif*/ - crc_itu16_append(fe->hdlc_rx.buf, fe->hdlc_rx.len); - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing); - } - else - { - hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing); - } - /*endif*/ - fe->hdlc_rx.len = 0; - } - /*endif*/ - fe->rx_data_missing = false; - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - break; - case T38_FIELD_HDLC_FCS_BAD: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (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"); - if (data_type == T38_DATA_V21) - 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); - /*endif*/ - fe->hdlc_rx.len = 0; - } - /*endif*/ - 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: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (fe->hdlc_rx.len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK, sig end (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean"); - if (data_type == T38_DATA_V21) - { - if (fe->hdlc_rx.len >= 3) - { - if ((fe->hdlc_rx.buf[2] & 0xFE) == T30_DCS) - { - /* We need to know if ECM is about to be used, so we can fake HDLC stuff. */ - fe->ecm_mode = (fe->hdlc_rx.len >= 7 && (fe->hdlc_rx.buf[6] & DISBIT3)) ? 1 : 0; - span_log(&s->logging, SPAN_LOG_FLOW, "ECM mode: %d\n", fe->ecm_mode); - } - else if (s->t38_fe.ecm_mode == 1 && (fe->hdlc_rx.buf[2] & 0xFE) == T30_CFR) - { - s->t38_fe.ecm_mode = 2; - } - /*endif*/ - } - /*endif*/ - crc_itu16_append(fe->hdlc_rx.buf, fe->hdlc_rx.len); - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing); - } - else - { - hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing); - } - /*endif*/ - fe->hdlc_rx.len = 0; - } - /*endif*/ - 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) - hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN); - else - non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN); - /*endif*/ - } - /*endif*/ - fe->timeout_rx_samples = 0; - break; - case T38_FIELD_HDLC_FCS_BAD_SIG_END: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - 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"); - if (data_type == T38_DATA_V21) - 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); - /*endif*/ - fe->hdlc_rx.len = 0; - } - /*endif*/ - 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) - hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN); - else - non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN); - /*endif*/ - } - /*endif*/ - fe->timeout_rx_samples = 0; - break; - case T38_FIELD_HDLC_SIG_END: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_SIG_END!\n"); - /* The sender has incorrectly included data in this message, but there seems nothing meaningful - it could be. There could not be an FCS good/bad report beyond this. */ - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - /* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send this message at the - end of non-ECM data. We need to tolerate this. We use the generic receive complete - indication, rather than the specific HDLC carrier down. */ - /* This message is expected under 2 circumstances. One is as an alternative to T38_FIELD_HDLC_FCS_OK_SIG_END - - i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops. - The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */ - fe->hdlc_rx.len = 0; - fe->rx_data_missing = false; - fe->timeout_rx_samples = 0; - if (data_type == T38_DATA_V21) - hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN); - else - non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN); - /*endif*/ - } - /*endif*/ - break; - case T38_FIELD_T4_NON_ECM_DATA: - if (len > 0) - { - if (!s->at_state.rx_signal_present) - { - non_ecm_rx_status(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->at_state.rx_signal_present = true; - } - /*endif*/ - bit_reverse(buf2, buf, len); - non_ecm_put(s, buf2, len); - } - /*endif*/ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - break; - case T38_FIELD_T4_NON_ECM_SIG_END: - /* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - if (len > 0) - { - if (!s->at_state.rx_signal_present) - { - non_ecm_rx_status(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->at_state.rx_signal_present = true; - } - /*endif*/ - bit_reverse(buf2, buf, len); - non_ecm_put(s, buf2, len); - } - /*endif*/ - /* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send HDLC signal end where - they should send non-ECM signal end. It is possible they also do the opposite. - We need to tolerate this, so we use the generic receive complete - indication, rather than the specific non-ECM carrier down. */ - non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN); - } - /*endif*/ - s->at_state.rx_signal_present = false; - fe->timeout_rx_samples = 0; - break; - case T38_FIELD_CM_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_JM_MESSAGE: - if (len >= 2) - span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_CI_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_V34RATE: - if (len >= 3) - { - fe->t38.v34_rate = t38_v34rate_to_bps(buf, len); - span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", fe->t38.v34_rate); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); - } - /*endif*/ - break; - default: - break; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void send_hdlc(void *user_data, const uint8_t *msg, int len) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - if (len <= 0) - { - s->hdlc_tx.len = -1; - } - else - { - if (len >= 3) - { - if ((s->hdlc_tx.buf[2] & 0xFE) == T30_DCS) - { - /* We need to know if ECM is about to be used, so we can fake HDLC stuff. */ - s->t38_fe.ecm_mode = (len >= 7 && (s->hdlc_tx.buf[6] & DISBIT3)) ? 1 : 0; - span_log(&s->logging, SPAN_LOG_FLOW, "ECM mode: %d\n", s->t38_fe.ecm_mode); - } - else if (s->t38_fe.ecm_mode == 1 && (s->hdlc_tx.buf[2] & 0xFE) == T30_CFR) - { - s->t38_fe.ecm_mode = 2; - } - /*endif*/ - } - /*endif*/ - s->t38_fe.hdlc_tx.extra_bits = extra_bits_in_stuffed_frame(msg, len); - bit_reverse(s->hdlc_tx.buf, msg, len); - s->hdlc_tx.len = len; - s->hdlc_tx.ptr = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int bits_to_us(t31_state_t *s, int bits) -{ - if (s->t38_fe.us_per_tx_chunk == 0 || s->t38_fe.tx_bit_rate == 0) - return 0; - /*endif*/ - return bits*1000000/s->t38_fe.tx_bit_rate; -} -/*- End of function --------------------------------------------------------*/ - -static void set_octets_per_data_packet(t31_state_t *s, int bit_rate) -{ - s->t38_fe.tx_bit_rate = bit_rate; - if (s->t38_fe.us_per_tx_chunk) - { - s->t38_fe.octets_per_data_packet = (s->t38_fe.us_per_tx_chunk/1000)*bit_rate/(8*1000); - /* Make sure we have a positive number (i.e. we didn't truncate to zero). */ - if (s->t38_fe.octets_per_data_packet < 1) - s->t38_fe.octets_per_data_packet = 1; - /*endif*/ - } - else - { - s->t38_fe.octets_per_data_packet = MAX_OCTETS_PER_UNPACED_CHUNK; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int set_no_signal(t31_state_t *s) -{ - int delay; - - if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS)) - { - if ((delay = t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - s->t38_fe.timed_step = T38_TIMED_STEP_NO_SIGNAL; - if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_2S_REGULAR_INDICATORS)) - s->t38_fe.timeout_tx_samples = s->t38_fe.next_tx_samples + us_to_samples(2000000); - else - s->t38_fe.timeout_tx_samples = 0; - /*endif*/ - return s->t38_fe.us_per_tx_chunk; - } - /*endif*/ - if ((delay = t38_core_send_indicator(&s->t38_fe.t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - s->t38_fe.timed_step = T38_TIMED_STEP_NONE; - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_no_signal(t31_state_t *s) -{ - int delay; - - if ((delay = t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - if (s->t38_fe.timeout_tx_samples && s->t38_fe.next_tx_samples >= s->t38_fe.timeout_tx_samples) - s->t38_fe.timed_step = T38_TIMED_STEP_NONE; - /*endif*/ - return s->t38_fe.us_per_tx_chunk; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_non_ecm(t31_state_t *s) -{ - t31_t38_front_end_state_t *fe; - uint8_t buf[MAX_OCTETS_PER_UNPACED_CHUNK + 50]; - int res; - int delay; - int len; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_NON_ECM_MODEM: - /* Create a 75ms silence */ - if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL) - { - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - } - else - { - if (fe->us_per_tx_chunk) - delay = 75000; - /*endif*/ - } - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_2; - fe->timeout_tx_samples = fe->next_tx_samples - + us_to_samples(t38_core_send_training_delay(&fe->t38, fe->next_tx_indicator)); - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_NON_ECM_MODEM_2: - /* Switch on a fast modem, and give the training time to complete */ - if ((fe->chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS)) - { - if ((delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - if (fe->next_tx_samples >= fe->timeout_tx_samples) - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_3; - /*endif*/ - return fe->us_per_tx_chunk; - } - /*endif*/ - if ((delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_3; - break; - case T38_TIMED_STEP_NON_ECM_MODEM_3: - /* Send a chunk of non-ECM image data */ - /* T.38 says it is OK to send the last of the non-ECM data in the signal end message. - However, I think the early versions of T.38 said the signal end message should not - contain data. Hopefully, following the current spec will not cause compatibility - issues. */ - len = non_ecm_get(s, buf, fe->octets_per_data_packet); - if (len > 0) - bit_reverse(buf, buf, len); - /*endif*/ - if (len < fe->octets_per_data_packet) - { - /* That's the end of the image data. */ - if (fe->us_per_tx_chunk) - { - /* Pad the end of the data with some zeros. If we just stop abruptly - at the end of the EOLs, some ATAs fail to clean up properly before - shutting down their transmit modem, and the last few rows of the image - are lost or corrupted. Simply delaying the no-signal message does not - help for all implentations. It is usually ignored, which is probably - the right thing to do after receiving a message saying the signal has - ended. */ - memset(&buf[len], 0, fe->octets_per_data_packet - len); - fe->non_ecm_trailer_bytes = 3*fe->octets_per_data_packet + len; - len = fe->octets_per_data_packet; - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_4; - } - else - { - /* If we are sending quickly there seems no point in doing any padding */ - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_5; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - break; - } - /*endif*/ - } - /*endif*/ - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA)) < 0) - return res; - /*endif*/ - if (fe->us_per_tx_chunk) - delay = bits_to_us(s, 8*len); - /*endif*/ - break; - case T38_TIMED_STEP_NON_ECM_MODEM_4: - /* Send padding */ - len = fe->octets_per_data_packet; - fe->non_ecm_trailer_bytes -= fe->octets_per_data_packet; - if (fe->non_ecm_trailer_bytes <= 0) - { - len += fe->non_ecm_trailer_bytes; - memset(buf, 0, len); - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_5; - /* Allow a bit more time than the data will take to play out, to ensure the far ATA does not - cut things short. */ - if (fe->us_per_tx_chunk) - delay = bits_to_us(s, 8*len) + 60000; - /*endif*/ - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - break; - } - /*endif*/ - memset(buf, 0, len); - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA)) < 0) - return res; - /*endif*/ - if (fe->us_per_tx_chunk) - delay = bits_to_us(s, 8*len); - /*endif*/ - break; - case T38_TIMED_STEP_NON_ECM_MODEM_5: - /* This should not be needed, since the message above indicates the end of the signal, but it - seems like it can improve compatibility with quirky implementations. */ - delay = set_no_signal(s); - fe->timed_step = T38_TIMED_STEP_NONE; - return delay; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_hdlc(t31_state_t *s) -{ - t31_t38_front_end_state_t *fe; - uint8_t buf[MAX_OCTETS_PER_UNPACED_CHUNK + 50]; - t38_data_field_t data_fields[2]; - int category; - int previous; - int res; - int delay; - int i; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_HDLC_MODEM: - /* Create a 75ms silence */ - if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL) - { - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - } - else - { - delay = (fe->us_per_tx_chunk) ? 75000 : 0; - } - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_2; - fe->timeout_tx_samples = fe->next_tx_samples - + us_to_samples(t38_core_send_training_delay(&fe->t38, fe->next_tx_indicator)) - + us_to_samples(t38_core_send_flags_delay(&fe->t38, fe->next_tx_indicator)) - + us_to_samples(delay); - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_HDLC_MODEM_2: - /* Send HDLC preambling */ - if ((fe->chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS)) - { - if ((delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - if (fe->next_tx_samples >= fe->timeout_tx_samples) - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - /*endif*/ - return fe->us_per_tx_chunk; - } - /*endif*/ - if ((delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - delay += t38_core_send_flags_delay(&fe->t38, fe->next_tx_indicator); - if (fe->current_tx_data_type == T38_DATA_V21) - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - break; - case T38_TIMED_STEP_HDLC_MODEM_3: - /* Send a chunk of HDLC data */ - if (s->hdlc_tx.len == 0) - { - /* We don't have a frame ready yet, so wait a little */ - if (fe->current_tx_data_type != T38_DATA_V21 - && - s->t38_fe.hdlc_from_t31.in != s->t38_fe.hdlc_from_t31.out) - { - bit_reverse(s->hdlc_tx.buf, s->t38_fe.hdlc_from_t31.buf[s->t38_fe.hdlc_from_t31.out].buf, s->t38_fe.hdlc_from_t31.buf[s->t38_fe.hdlc_from_t31.out].len); - s->hdlc_tx.len = s->t38_fe.hdlc_from_t31.buf[s->t38_fe.hdlc_from_t31.out].len; - s->hdlc_tx.ptr = 0; - if (++s->t38_fe.hdlc_from_t31.out >= T31_TX_HDLC_BUFS) - s->t38_fe.hdlc_from_t31.out = 0; - /*endif*/ - if (s->t38_fe.hdlc_from_t31.in == s->t38_fe.hdlc_from_t31.out) - s->hdlc_tx.final = s->non_ecm_tx.final; - /*endif*/ - } - else - { - delay = US_PER_TX_CHUNK; - break; - } - /*endif*/ - } - /*endif*/ - i = s->hdlc_tx.len - s->hdlc_tx.ptr; - if (fe->octets_per_data_packet >= i) - { - /* The last part of an HDLC frame */ - if ((fe->chunking_modes & T38_CHUNKING_MERGE_FCS_WITH_DATA)) - { - /* Copy the data, as we might be about to refill the buffer it is in */ - memcpy(buf, &s->hdlc_tx.buf[s->hdlc_tx.ptr], i); - data_fields[0].field_type = T38_FIELD_HDLC_DATA; - data_fields[0].field = buf; - data_fields[0].field_len = i; - - /* Now see about the next HDLC frame. This will tell us whether to send FCS_OK or FCS_OK_SIG_END */ - s->hdlc_tx.ptr = 0; - s->hdlc_tx.len = 0; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - if (!s->hdlc_tx.final) - { - data_fields[1].field_type = T38_FIELD_HDLC_FCS_OK; - data_fields[1].field = NULL; - data_fields[1].field_len = 0; - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - delay = bits_to_us(s, i*8 + fe->hdlc_tx.extra_bits); - if (fe->current_tx_data_type == T38_DATA_V21) - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - /*endif*/ - } - else - { - data_fields[1].field_type = T38_FIELD_HDLC_FCS_OK_SIG_END; - data_fields[1].field = NULL; - data_fields[1].field_len = 0; - 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_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_5; - /* We add a bit of extra time here, as with some implementations - the carrier falling too abruptly causes data loss. */ - delay = bits_to_us(s, i*8 + fe->hdlc_tx.extra_bits); - if (fe->us_per_tx_chunk) - delay += 100000; - /*endif*/ - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - } - /*endif*/ - break; - } - /*endif*/ - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &s->hdlc_tx.buf[s->hdlc_tx.ptr], i, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_4; - } - else - { - i = fe->octets_per_data_packet; - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &s->hdlc_tx.buf[s->hdlc_tx.ptr], i, category)) < 0) - return res; - /*endif*/ - s->hdlc_tx.ptr += i; - } - /*endif*/ - delay = bits_to_us(s, i*8); - break; - case T38_TIMED_STEP_HDLC_MODEM_4: - /* End of HDLC frame */ - previous = fe->current_tx_data_type; - s->hdlc_tx.ptr = 0; - s->hdlc_tx.len = 0; - if (!s->hdlc_tx.final) - { - /* Finish the current frame off, and prepare for the next one. */ - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK, NULL, 0, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - if (fe->current_tx_data_type == T38_DATA_V21) - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - /*endif*/ - /* We should now wait enough time for everything to clear through an analogue modem at the far end. */ - delay = bits_to_us(s, fe->hdlc_tx.extra_bits); - } - else - { - /* End of transmission */ - 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; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_5; - /* We add a bit of extra time here, as with some implementations - the carrier falling too abruptly causes data loss. */ - delay = bits_to_us(s, fe->hdlc_tx.extra_bits); - if (fe->us_per_tx_chunk) - delay += 100000; - /*endif*/ - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - } - /*endif*/ - break; - case T38_TIMED_STEP_HDLC_MODEM_5: - /* Note that some boxes do not like us sending a T38_FIELD_HDLC_SIG_END at this point. - A T38_IND_NO_SIGNAL should always be OK. */ - delay = set_no_signal(s); - fe->timed_step = T38_TIMED_STEP_NONE; - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - return delay; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_ced(t31_state_t *s) -{ - t31_t38_front_end_state_t *fe; - int delay; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_CED: - /* It seems common practice to start with a no signal indicator, though - this is not a specified requirement. Since we should be sending 200ms - of silence, starting the delay with a no signal indication makes sense. - We do need a 200ms delay, as that is a specification requirement. */ - fe->timed_step = T38_TIMED_STEP_CED_2; - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - delay = (fe->us_per_tx_chunk) ? 200000 : 0; - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_CED_2: - /* Initial 200ms delay over. Send the CED indicator */ - fe->timed_step = T38_TIMED_STEP_CED_3; - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_CED)) < 0) - return delay; - /*endif*/ - fe->current_tx_data_type = T38_DATA_NONE; - break; - case T38_TIMED_STEP_CED_3: - /* End of CED */ - fe->timed_step = T38_TIMED_STEP_NONE; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - return 0; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_cng(t31_state_t *s) -{ - t31_t38_front_end_state_t *fe; - int delay; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_CNG: - /* It seems common practice to start with a no signal indicator, though - this is not a specified requirement of the T.38 spec. Since we should - be sending 200ms of silence, according to T.30, starting that delay with - a no signal indication makes sense. */ - fe->timed_step = T38_TIMED_STEP_CNG_2; - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - delay = (fe->us_per_tx_chunk) ? 200000 : 0; - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_CNG_2: - /* Initial short delay over. Send the CNG indicator. CNG persists until something - coming the other way interrupts it, or a long timeout controlled by the T.30 engine - expires. */ - delay = t38_core_send_indicator(&fe->t38, T38_IND_CNG); - fe->timed_step = T38_TIMED_STEP_NONE; - fe->current_tx_data_type = T38_DATA_NONE; - return delay; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples) -{ - t31_t38_front_end_state_t *fe; - int delay; - - fe = &s->t38_fe; - if (fe->current_rx_type == T30_MODEM_DONE || fe->current_tx_type == T30_MODEM_DONE) - return true; - /*endif*/ - - fe->samples += samples; - if (fe->timeout_rx_samples && fe->samples > fe->timeout_rx_samples) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Timeout mid-receive\n"); - fe->timeout_rx_samples = 0; - front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - } - /*endif*/ - if (fe->timed_step == T38_TIMED_STEP_NONE) - 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; - /*endif*/ - /* Its time to send something */ - delay = 0; - switch (fe->timed_step & 0xFFF0) - { - case T38_TIMED_STEP_NON_ECM_MODEM: - delay = stream_non_ecm(s); - break; - case T38_TIMED_STEP_HDLC_MODEM: - delay = stream_hdlc(s); - break; - case T38_TIMED_STEP_CED: - delay = stream_ced(s); - break; - case T38_TIMED_STEP_CNG: - delay = stream_cng(s); - break; - case T38_TIMED_STEP_PAUSE: - /* End of timed pause */ - fe->timed_step = T38_TIMED_STEP_NONE; - front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE); - break; - case T38_TIMED_STEP_NO_SIGNAL: - delay = stream_no_signal(s); - break; - } - /*endswitch*/ - fe->next_tx_samples += us_to_samples(delay); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static int t31_modem_control_handler(void *user_data, int op, const char *num) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - switch (op) - { - case AT_MODEM_CONTROL_CALL: - s->call_samples = 0; - t38_core_restart(&s->t38_fe.t38); - break; - case AT_MODEM_CONTROL_ANSWER: - s->call_samples = 0; - t38_core_restart(&s->t38_fe.t38); - break; - case AT_MODEM_CONTROL_ONHOOK: - if (s->non_ecm_tx.holding) - { - 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*/ - if (s->at_state.rx_signal_present) - { - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - s->at_state.rx_data[s->at_state.rx_data_bytes++] = ETX; - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, - s->at_state.rx_data, - s->at_state.rx_data_bytes); - s->at_state.rx_data_bytes = 0; - } - /*endif*/ - restart_modem(s, FAX_MODEM_SILENCE_TX); - break; - case AT_MODEM_CONTROL_RESTART: - restart_modem(s, (int) (intptr_t) num); - return 0; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - if (num) - s->dte_data_timeout = s->call_samples + ms_to_samples((intptr_t) num); - else - s->dte_data_timeout = 0; - /*endif*/ - return 0; - } - /*endswitch*/ - return s->modem_control_handler(s, s->modem_control_user_data, op, num); -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_rx_status(void *user_data, int status) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - switch (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; - 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; - break; - case SIG_STATUS_CARRIER_UP: - break; - case SIG_STATUS_CARRIER_DOWN: - if (s->at_state.rx_signal_present) - { - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - s->at_state.rx_data[s->at_state.rx_data_bytes++] = ETX; - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, - s->at_state.rx_data, - s->at_state.rx_data_bytes); - s->at_state.rx_data_bytes = 0; - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_NO_CARRIER); - 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; - break; - default: - if (s->at_state.p.result_code_format) - span_log(&s->logging, SPAN_LOG_FLOW, "Eh!\n"); - /*endif*/ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_put_bit(void *user_data, int bit) -{ - t31_state_t *s; - - if (bit < 0) - { - non_ecm_rx_status(user_data, bit); - return; - } - /*endif*/ - s = (t31_state_t *) user_data; - s->audio.current_byte = (s->audio.current_byte >> 1) | (bit << 7); - if (++s->audio.bit_no >= 8) - { - if (s->audio.current_byte == DLE) - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - /*endif*/ - s->at_state.rx_data[s->at_state.rx_data_bytes++] = (uint8_t) s->audio.current_byte; - if (s->at_state.rx_data_bytes >= 250) - { - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, - s->at_state.rx_data, - s->at_state.rx_data_bytes); - s->at_state.rx_data_bytes = 0; - } - /*endif*/ - s->audio.bit_no = 0; - s->audio.current_byte = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_put(void *user_data, const uint8_t buf[], int len) -{ - t31_state_t *s; - int i; - - s = (t31_state_t *) user_data; - if (!s->at_state.rx_signal_present) - { - non_ecm_rx_status(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->at_state.rx_signal_present = true; - } - /*endif*/ - /* Ignore any fractional bytes which may have accumulated */ - for (i = 0; i < len; i++) - { - if (buf[i] == DLE) - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - /*endif*/ - s->at_state.rx_data[s->at_state.rx_data_bytes++] = buf[i]; - if (s->at_state.rx_data_bytes >= 250) - { - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, - s->at_state.rx_data, - s->at_state.rx_data_bytes); - s->at_state.rx_data_bytes = 0; - } - /*endif*/ - } - /*endfor*/ - s->audio.bit_no = 0; - s->audio.current_byte = 0; -} -/*- End of function --------------------------------------------------------*/ - -static int non_ecm_get_bit(void *user_data) -{ - t31_state_t *s; - int bit; - - s = (t31_state_t *) user_data; - if (s->audio.bit_no <= 0) - { - if (s->non_ecm_tx.out_bytes != s->non_ecm_tx.in_bytes) - { - /* There is real data available to send */ - s->audio.current_byte = s->non_ecm_tx.buf[s->non_ecm_tx.out_bytes++]; - if (s->non_ecm_tx.out_bytes > T31_TX_BUF_LEN - 1) - { - s->non_ecm_tx.out_bytes = T31_TX_BUF_LEN - 1; - span_log(&s->logging, SPAN_LOG_FLOW, "End of transmit buffer reached!\n"); - } - /*endif*/ - if (s->non_ecm_tx.holding) - { - /* 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; - /* 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; - } - else - { - if (s->non_ecm_tx.final) - { - 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; - } - /*endif*/ - /* Fill with 0xFF bytes at the start of transmission, or 0x00 if we are in - the middle of transmission. This follows T.31 and T.30 practice. */ - s->audio.current_byte = (s->non_ecm_tx.data_started) ? 0x00 : 0xFF; - } - /*endif*/ - s->audio.bit_no = 8; - } - /*endif*/ - s->audio.bit_no--; - bit = s->audio.current_byte & 1; - s->audio.current_byte >>= 1; - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static int non_ecm_get(void *user_data, uint8_t buf[], int len) -{ - t31_state_t *s; - int i; - - s = (t31_state_t *) user_data; - for (i = 0; i < len; i++) - { - if (s->non_ecm_tx.out_bytes != s->non_ecm_tx.in_bytes) - { - /* There is real data available to send */ - buf[i] = s->non_ecm_tx.buf[s->non_ecm_tx.out_bytes++]; - if (s->non_ecm_tx.out_bytes > T31_TX_BUF_LEN - 1) - { - s->non_ecm_tx.out_bytes = T31_TX_BUF_LEN - 1; - span_log(&s->logging, SPAN_LOG_FLOW, "End of transmit buffer reached!\n"); - } - /*endif*/ - if (s->non_ecm_tx.holding) - { - /* 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; - /* 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; - } - else - { - if (s->non_ecm_tx.final) - { - 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; - } - /*endif*/ - /* Fill with 0xFF bytes at the start of transmission, or 0x00 if we are in - the middle of transmission. This follows T.31 and T.30 practice. */ - buf[i] = (s->non_ecm_tx.data_started) ? 0x00 : 0xFF; - } - /*endif*/ - } - /*endfor*/ - s->audio.bit_no = 0; - s->audio.current_byte = 0; - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void tone_detected(void *user_data, int tone, int level, int delay) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level); -} -/*- End of function --------------------------------------------------------*/ - -static void v8_handler(void *user_data, v8_parms_t *result) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "V.8 report received\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_tx_underflow(void *user_data) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - if (s->hdlc_tx.final) - { - s->hdlc_tx.final = false; - /* Schedule an orderly shutdown of the modem */ - hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0); - } - else - { - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_tx_underflow2(void *user_data) -{ -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_rx_status(void *user_data, int status) -{ - t31_state_t *s; - uint8_t buf[2]; - - s = (t31_state_t *) user_data; - switch (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; - 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; - 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; - } - /*endif*/ - break; - case SIG_STATUS_CARRIER_DOWN: - if (s->rx_frame_received) - { - if (s->at_state.dte_is_waiting) - { - 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; - } - else - { - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_NO_CARRIER); - } - /*endif*/ - s->at_state.dte_is_waiting = false; - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - } - else - { - buf[0] = AT_RESPONSE_CODE_NO_CARRIER; - queue_write_msg(s->rx_queue, buf, 1); - } - /*endif*/ - } - /*endif*/ - 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) - { - /* 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; - } - /*endif*/ - if (s->modem == FAX_MODEM_V17_RX || s->modem == FAX_MODEM_V27TER_RX || s->modem == FAX_MODEM_V29_RX) - { - /* V.21 has been detected while expecting a different carrier. - If +FAR=0 then result +FCERROR and return to command-mode. - If +FAR=1 then report +FRH:3 and CONNECT, switching to - 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->modem = FAX_MODEM_V21_RX; - 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); - } - else - { - 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; - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_FCERROR); - } - /*endif*/ - } - else - { - if (!s->rx_frame_received) - { - if (s->at_state.dte_is_waiting) - { - /* 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; - } - else - { - buf[0] = AT_RESPONSE_CODE_CONNECT; - queue_write_msg(s->rx_queue, buf, 1); - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ - break; - case SIG_STATUS_ABORT: - /* Just ignore these */ - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected HDLC rx status - %d!\n", status); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_accept_frame(void *user_data, const uint8_t *msg, int len, int ok) -{ - t31_state_t *s; - uint8_t buf[256]; - int i; - - if (len < 0) - { - hdlc_rx_status(user_data, len); - return; - } - /*endif*/ - s = (t31_state_t *) user_data; - if (!s->rx_frame_received) - { - if (s->at_state.dte_is_waiting) - { - /* 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; - } - else - { - buf[0] = AT_RESPONSE_CODE_CONNECT; - queue_write_msg(s->rx_queue, buf, 1); - } - /*endif*/ - } - /*endif*/ - /* If OK is pending then we just ignore whatever comes in */ - if (!s->at_state.ok_is_pending) - { - if (s->at_state.dte_is_waiting) - { - /* Send straight away */ - /* It is safe to look at the two bytes beyond the length of the message, - and expect to find the FCS there. */ - for (i = 0; i < len + 2; i++) - { - if (msg[i] == DLE) - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - /*endif*/ - s->at_state.rx_data[s->at_state.rx_data_bytes++] = msg[i]; - } - /*endfor*/ - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - s->at_state.rx_data[s->at_state.rx_data_bytes++] = ETX; - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, s->at_state.rx_data, s->at_state.rx_data_bytes); - s->at_state.rx_data_bytes = 0; - if (msg[1] == 0x13 && ok) - { - /* 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; - } - 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; - } - /*endif*/ - } - else - { - /* Queue it */ - buf[0] = (ok) ? AT_RESPONSE_CODE_OK : AT_RESPONSE_CODE_ERROR; - /* It is safe to look at the two bytes beyond the length of the message, - and expect to find the FCS there. */ - memcpy(&buf[1], msg, len + 2); - queue_write_msg(s->rx_queue, buf, len + 3); - } - /*endif*/ - } - /*endif*/ - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_accept_t38_frame(void *user_data, const uint8_t *msg, int len, int ok) -{ - t31_state_t *s; - int i; - int byte_in_progress; - int txbyte; - int pos; - int ptr; - uint16_t crc; -#if defined(_MSC_VER) - uint8_t *buf2 = (uint8_t *) _alloca(2*len + 20); -#else - uint8_t buf2[2*len + 20]; -#endif - - /* Accept an ECM image mode HDLC frame, received as T.38, and convert to an HDLC - bit stream to be fed to the FAX software. */ - if (len < 0) - return; - /*endif*/ - s = (t31_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "Accept2 %d %d\n", len, ok); - crc = crc_itu16_calc(msg, len, 0xFFFF); - /* If the frame is not good, don't flip the CRC to the correct value */ - if (ok) - crc ^= 0xFFFF; - /*endif*/ - ptr = 0; - buf2[ptr++] = s->t38_fe.hdlc_tx_non_ecm.idle_octet; - buf2[ptr++] = s->t38_fe.hdlc_tx_non_ecm.idle_octet; - for (pos = 0; pos < len; pos++) - { - byte_in_progress = msg[pos]; - i = bottom_bit(byte_in_progress | 0x100); - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress <<= i; - byte_in_progress >>= i; - for ( ; i < 8; i++) - { - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress = (s->t38_fe.hdlc_tx_non_ecm.octets_in_progress << 1) | (byte_in_progress & 0x01); - byte_in_progress >>= 1; - if ((s->t38_fe.hdlc_tx_non_ecm.octets_in_progress & 0x1F) == 0x1F) - { - /* There are 5 ones - stuff */ - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress <<= 1; - s->t38_fe.hdlc_tx_non_ecm.num_bits++; - } - /*endif*/ - } - /*endfor*/ - /* An input byte will generate between 8 and 10 output bits */ - buf2[ptr++] = (s->t38_fe.hdlc_tx_non_ecm.octets_in_progress >> s->t38_fe.hdlc_tx_non_ecm.num_bits) & 0xFF; - if (s->t38_fe.hdlc_tx_non_ecm.num_bits >= 8) - { - s->t38_fe.hdlc_tx_non_ecm.num_bits -= 8; - buf2[ptr++] = (s->t38_fe.hdlc_tx_non_ecm.octets_in_progress >> s->t38_fe.hdlc_tx_non_ecm.num_bits) & 0xFF; - } - /*endif*/ - } - /*endfor*/ - - for (pos = 0; pos < 2; pos++) - { - byte_in_progress = crc & 0xFF; - crc >>= 8; - i = bottom_bit(byte_in_progress | 0x100); - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress <<= i; - byte_in_progress >>= i; - for ( ; i < 8; i++) - { - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress = (s->t38_fe.hdlc_tx_non_ecm.octets_in_progress << 1) | (byte_in_progress & 0x01); - byte_in_progress >>= 1; - if ((s->t38_fe.hdlc_tx_non_ecm.octets_in_progress & 0x1F) == 0x1F) - { - /* There are 5 ones - stuff */ - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress <<= 1; - s->t38_fe.hdlc_tx_non_ecm.num_bits++; - } - /*endif*/ - } - /*endfor*/ - /* An input byte will generate between 8 and 10 output bits */ - buf2[ptr++] = (s->t38_fe.hdlc_tx_non_ecm.octets_in_progress >> s->t38_fe.hdlc_tx_non_ecm.num_bits) & 0xFF; - if (s->t38_fe.hdlc_tx_non_ecm.num_bits >= 8) - { - s->t38_fe.hdlc_tx_non_ecm.num_bits -= 8; - buf2[ptr++] = (s->t38_fe.hdlc_tx_non_ecm.octets_in_progress >> s->t38_fe.hdlc_tx_non_ecm.num_bits) & 0xFF; - } - /*endif*/ - } - /*endif*/ - - /* Finish off the current byte with some flag bits. If we are at the - start of a byte we need a at least one whole byte of flag to ensure - we cannot end up with back to back frames, and no flag octet at all */ - txbyte = (uint8_t) ((s->t38_fe.hdlc_tx_non_ecm.octets_in_progress << (8 - s->t38_fe.hdlc_tx_non_ecm.num_bits)) | (0x7E >> s->t38_fe.hdlc_tx_non_ecm.num_bits)); - /* Create a rotated octet of flag for idling... */ - s->t38_fe.hdlc_tx_non_ecm.idle_octet = (0x7E7E >> s->t38_fe.hdlc_tx_non_ecm.num_bits) & 0xFF; - /* ...and the partial flag octet needed to start off the next message. */ - s->t38_fe.hdlc_tx_non_ecm.octets_in_progress = s->t38_fe.hdlc_tx_non_ecm.idle_octet >> (8 - s->t38_fe.hdlc_tx_non_ecm.num_bits); - buf2[ptr++] = txbyte; - - buf2[ptr++] = s->t38_fe.hdlc_tx_non_ecm.idle_octet; - buf2[ptr++] = s->t38_fe.hdlc_tx_non_ecm.idle_octet; - bit_reverse(buf2, buf2, ptr); - non_ecm_put(s, buf2, ptr); -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_accept_non_ecm_frame(void *user_data, const uint8_t *msg, int len, int ok) -{ - t31_state_t *s; - - /* Accept an ECM image mode HDLC frame received as a bit stream from the FAX software, - and to be send as T.38 HDLC data. */ - if (len < 0) - return; - /*endif*/ - s = (t31_state_t *) user_data; - memcpy(s->t38_fe.hdlc_from_t31.buf[s->t38_fe.hdlc_from_t31.in].buf, msg, len); - s->t38_fe.hdlc_from_t31.buf[s->t38_fe.hdlc_from_t31.in].len = len; - if (++s->t38_fe.hdlc_from_t31.in >= T31_TX_HDLC_BUFS) - s->t38_fe.hdlc_from_t31.in = 0; - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void t31_v21_rx(t31_state_t *s) -{ - s->at_state.ok_is_pending = false; - s->hdlc_tx.len = 0; - s->hdlc_tx.final = false; - s->dled = false; - fax_modems_start_slow_modem(&s->audio.modems, FAX_MODEM_V21_RX); - hdlc_rx_init(&s->audio.modems.hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept_frame, s); - s->at_state.transmit = true; -} -/*- End of function --------------------------------------------------------*/ - -static int restart_modem(t31_state_t *s, int new_modem) -{ - int use_hdlc; - int res; - fax_modems_state_t *t; - - t = &s->audio.modems; - span_log(&s->logging, SPAN_LOG_FLOW, "Restart modem %d\n", new_modem); - if (s->modem == new_modem) - return 0; - /*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; - 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; - switch (s->modem) - { - case FAX_MODEM_CNG_TONE_TX: - if (s->t38_mode) - { - s->t38_fe.next_tx_samples = s->t38_fe.samples; - s->t38_fe.timed_step = T38_TIMED_STEP_CNG; - s->t38_fe.current_tx_data_type = T38_DATA_NONE; - } - else - { - fax_modems_start_slow_modem(t, FAX_MODEM_CNG_TONE_TX); - /* CNG is special, since we need to receive V.21 HDLC messages while sending the - tone. Everything else in FAX processing sends only one way at a time. */ - /* Do V.21/HDLC receive in parallel. The other end may send its - first message at any time. The CNG tone will continue until - we get a valid preamble. */ - t31_v21_rx(s); - fax_modems_set_rx_handler(t, (span_rx_handler_t) &initial_timed_rx, s, (span_rx_fillin_handler_t) &span_dummy_rx_fillin, NULL); - fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - } - /*endif*/ - s->at_state.transmit = true; - break; - case FAX_MODEM_NOCNG_TONE_TX: - if (s->t38_mode) - { - } - else - { - t31_v21_rx(s); - fax_modems_set_rx_handler(t, (span_rx_handler_t) &initial_timed_rx, s, (span_rx_fillin_handler_t) &span_dummy_rx_fillin, NULL); - silence_gen_set(&t->silence_gen, 0); - fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); - } - /*endif*/ - s->at_state.transmit = false; - break; - case FAX_MODEM_CED_TONE_TX: - if (s->t38_mode) - { - s->t38_fe.next_tx_samples = s->t38_fe.samples; - s->t38_fe.timed_step = T38_TIMED_STEP_CED; - s->t38_fe.current_tx_data_type = T38_DATA_NONE; - } - else - { - fax_modems_start_slow_modem(t, FAX_MODEM_CED_TONE_TX); - fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - } - /*endif*/ - s->at_state.transmit = true; - break; - case FAX_MODEM_V21_RX: - if (s->t38_mode) - { - } - else - { - t31_v21_rx(s); - 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); - } - /*endif*/ - break; - case FAX_MODEM_V21_TX: - if (s->t38_mode) - { - s->t38_fe.next_tx_indicator = T38_IND_V21_PREAMBLE; - s->t38_fe.current_tx_data_type = T38_DATA_V21; - s->t38_fe.timed_step = T38_TIMED_STEP_HDLC_MODEM; - set_octets_per_data_packet(s, 300); - } - else - { - 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); - fax_modems_set_tx_handler(t, (span_tx_handler_t) &fsk_tx, &t->v21_tx); - fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - } - /*endif*/ - s->hdlc_tx.len = 0; - s->hdlc_tx.final = false; - s->dled = false; - s->at_state.transmit = true; - break; - case FAX_MODEM_V17_RX: - case FAX_MODEM_V27TER_RX: - case FAX_MODEM_V29_RX: - if (!s->t38_mode) - { - /* Allow for +FCERROR/+FRH:3 */ - t31_v21_rx(s); - fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); - } - /*endif*/ - s->at_state.transmit = false; - break; - case FAX_MODEM_V17_TX: - if (s->t38_mode) - { - switch (s->bit_rate) - { - case 7200: - s->t38_fe.next_tx_indicator = (s->short_train) ? T38_IND_V17_7200_SHORT_TRAINING : T38_IND_V17_7200_LONG_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V17_7200; - break; - case 9600: - s->t38_fe.next_tx_indicator = (s->short_train) ? T38_IND_V17_9600_SHORT_TRAINING : T38_IND_V17_9600_LONG_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V17_9600; - break; - case 12000: - s->t38_fe.next_tx_indicator = (s->short_train) ? T38_IND_V17_12000_SHORT_TRAINING : T38_IND_V17_12000_LONG_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V17_12000; - break; - case 14400: - s->t38_fe.next_tx_indicator = (s->short_train) ? T38_IND_V17_14400_SHORT_TRAINING : T38_IND_V17_14400_LONG_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V17_14400; - break; - } - /*endswitch*/ - set_octets_per_data_packet(s, s->bit_rate); - s->t38_fe.timed_step = (s->t38_fe.ecm_mode == 2) ? T38_TIMED_STEP_HDLC_MODEM : T38_TIMED_STEP_NON_ECM_MODEM; - } - else - { - fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); - } - /*endif*/ - s->non_ecm_tx.out_bytes = 0; - s->non_ecm_tx.data_started = false; - s->at_state.transmit = true; - break; - case FAX_MODEM_V27TER_TX: - if (s->t38_mode) - { - switch (s->bit_rate) - { - case 2400: - s->t38_fe.next_tx_indicator = T38_IND_V27TER_2400_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V27TER_2400; - break; - case 4800: - s->t38_fe.next_tx_indicator = T38_IND_V27TER_4800_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V27TER_4800; - break; - } - /*endswitch*/ - set_octets_per_data_packet(s, s->bit_rate); - s->t38_fe.timed_step = (s->t38_fe.ecm_mode == 2) ? T38_TIMED_STEP_HDLC_MODEM : T38_TIMED_STEP_NON_ECM_MODEM; - } - else - { - fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); - } - /*endif*/ - s->non_ecm_tx.out_bytes = 0; - s->non_ecm_tx.data_started = false; - s->at_state.transmit = true; - break; - case FAX_MODEM_V29_TX: - if (s->t38_mode) - { - switch (s->bit_rate) - { - case 7200: - s->t38_fe.next_tx_indicator = T38_IND_V29_7200_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V29_7200; - break; - case 9600: - s->t38_fe.next_tx_indicator = T38_IND_V29_9600_TRAINING; - s->t38_fe.current_tx_data_type = T38_DATA_V29_9600; - break; - } - /*endswitch*/ - set_octets_per_data_packet(s, s->bit_rate); - s->t38_fe.timed_step = (s->t38_fe.ecm_mode == 2) ? T38_TIMED_STEP_HDLC_MODEM : T38_TIMED_STEP_NON_ECM_MODEM; - } - else - { - fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); - } - /*endif*/ - s->non_ecm_tx.out_bytes = 0; - s->non_ecm_tx.data_started = false; - s->at_state.transmit = true; - break; - case FAX_MODEM_SILENCE_TX: - if (s->t38_mode) - { - if ((res = t38_core_send_indicator(&s->t38_fe.t38, T38_IND_NO_SIGNAL)) < 0) - return res; - /*endif*/ - s->t38_fe.next_tx_samples = s->t38_fe.samples + ms_to_samples(700); - s->t38_fe.timed_step = T38_TIMED_STEP_PAUSE; - s->t38_fe.current_tx_data_type = T38_DATA_NONE; - } - else - { - silence_gen_set(&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); - } - /*endif*/ - s->at_state.transmit = false; - break; - case FAX_MODEM_SILENCE_RX: - if (!s->t38_mode) - { - fax_modems_set_rx_handler(t, (span_rx_handler_t) &silence_rx, s, (span_rx_fillin_handler_t) &span_dummy_rx_fillin, NULL); - silence_gen_set(&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); - } - /*endif*/ - s->at_state.transmit = false; - break; - case FAX_MODEM_FLUSH: - /* Send 200ms of silence to "push" the last audio out */ - if (s->t38_mode) - { - if ((res = t38_core_send_indicator(&s->t38_fe.t38, T38_IND_NO_SIGNAL)) < 0) - return res; - /*endif*/ - } - else - { - s->modem = FAX_MODEM_SILENCE_TX; - 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; - } - /*endif*/ - break; - } - /*endswitch*/ - s->audio.bit_no = 0; - s->audio.current_byte = 0xFF; - s->non_ecm_tx.in_bytes = 0; - s->non_ecm_tx.out_bytes = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void dle_unstuff_hdlc(t31_state_t *s, const char *stuffed, int len) -{ - int i; - - for (i = 0; i < len; i++) - { - if (s->dled) - { - s->dled = false; - if (stuffed[i] == ETX) - { - s->hdlc_tx.final = (s->hdlc_tx.buf[1] & 0x10); - if (s->t38_mode) - { - send_hdlc(s, s->hdlc_tx.buf, s->hdlc_tx.len); - } - else - { - hdlc_tx_frame(&s->audio.modems.hdlc_tx, s->hdlc_tx.buf, s->hdlc_tx.len); - s->hdlc_tx.len = 0; - } - /*endif*/ - } - else if (s->at_state.p.double_escape && stuffed[i] == SUB) - { - s->hdlc_tx.buf[s->hdlc_tx.len++] = DLE; - s->hdlc_tx.buf[s->hdlc_tx.len++] = DLE; - } - else - { - s->hdlc_tx.buf[s->hdlc_tx.len++] = stuffed[i]; - } - /*endif*/ - } - else - { - if (stuffed[i] == DLE) - s->dled = true; - else - s->hdlc_tx.buf[s->hdlc_tx.len++] = stuffed[i]; - /*endif*/ - } - /*endif*/ - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void dle_unstuff_fake_hdlc(t31_state_t *s, const char *stuffed, int len) -{ - int i; - - for (i = 0; i < len; i++) - { - if (s->dled) - { - s->dled = false; - if (stuffed[i] == ETX) - { - s->non_ecm_tx.final = true; - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - return; - } - else if (s->at_state.p.double_escape && stuffed[i] == SUB) - { - hdlc_rx_put_byte(&s->t38_fe.hdlc_rx_non_ecm, bit_reverse8(DLE)); - hdlc_rx_put_byte(&s->t38_fe.hdlc_rx_non_ecm, bit_reverse8(DLE)); - } - else - { - hdlc_rx_put_byte(&s->t38_fe.hdlc_rx_non_ecm, bit_reverse8(stuffed[i])); - } - /*endif*/ - } - else - { - if (stuffed[i] == DLE) - s->dled = true; - else - hdlc_rx_put_byte(&s->t38_fe.hdlc_rx_non_ecm, bit_reverse8(stuffed[i])); - /*endif*/ - } - /*endif*/ - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void dle_unstuff(t31_state_t *s, const char *stuffed, int len) -{ - int i; - - for (i = 0; i < len; i++) - { - if (s->dled) - { - s->dled = false; - if (stuffed[i] == ETX) - { - s->non_ecm_tx.final = true; - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - return; - } - /*endif*/ - if (s->at_state.p.double_escape && stuffed[i] == SUB) - { - s->non_ecm_tx.buf[s->non_ecm_tx.in_bytes++] = DLE; - s->non_ecm_tx.buf[s->non_ecm_tx.in_bytes++] = DLE; - } - else - { - s->non_ecm_tx.buf[s->non_ecm_tx.in_bytes++] = stuffed[i]; - } - /*endif*/ - } - else - { - if (stuffed[i] == DLE) - s->dled = true; - else - s->non_ecm_tx.buf[s->non_ecm_tx.in_bytes++] = stuffed[i]; - /*endif*/ - } - /*endif*/ - if (s->non_ecm_tx.in_bytes > T31_TX_BUF_LEN - 2) - { - /* Oops. We hit the end of the buffer. Give up. Loose stuff. :-( */ - span_log(&s->logging, SPAN_LOG_FLOW, "No room in buffer for new data!\n"); - return; - } - /*endif*/ - } - /*endfor*/ - if (!s->non_ecm_tx.holding) - { - /* 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; - /* Tell the application to hold further data */ - at_modem_control(&s->at_state, AT_MODEM_CONTROL_CTS, (void *) 0); - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int process_class1_cmd(void *user_data, int direction, int operation, int val) -{ - int new_modem; - int new_transmit; - int i; - int len; - t31_state_t *s; - uint8_t msg[256]; - - s = (t31_state_t *) user_data; - new_transmit = direction; - switch (operation) - { - case 'S': - s->at_state.transmit = new_transmit; - if (new_transmit) - { - /* Send a specified period of silence, to space transmissions. */ - restart_modem(s, FAX_MODEM_SILENCE_TX); - if (s->t38_mode) - s->t38_fe.next_tx_samples = s->t38_fe.samples + ms_to_samples(val*10); - else - silence_gen_alter(&s->audio.modems.silence_gen, ms_to_samples(val*10)); - /*endif*/ - s->at_state.transmit = true; - } - else - { - /* Wait until we have received a specified period of silence. */ - queue_flush(s->rx_queue); - s->silence_awaited = ms_to_samples(val*10); - t31_set_at_rx_mode(s, AT_MODE_DELIVERY); - if (s->t38_mode) - { - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - } - else - { - restart_modem(s, FAX_MODEM_SILENCE_RX); - } - /*endif*/ - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Silence %dms\n", val*10); - break; - case 'H': - switch (val) - { - case 3: - new_modem = (new_transmit) ? FAX_MODEM_V21_TX : FAX_MODEM_V21_RX; - s->short_train = false; - s->bit_rate = 300; - break; - default: - return -1; - } - /*endswitch*/ - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC\n"); - if (new_modem != s->modem) - restart_modem(s, new_modem); - /*endif*/ - s->at_state.transmit = new_transmit; - if (new_transmit) - { - t31_set_at_rx_mode(s, AT_MODE_HDLC); - if (!s->t38_mode) - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - /*endif*/ - } - else - { - /* 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; - do - { - if (!queue_empty(s->rx_queue)) - { - len = queue_read_msg(s->rx_queue, msg, 256); - if (len > 1) - { - if (msg[0] == AT_RESPONSE_CODE_OK) - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - /*endif*/ - for (i = 1; i < len; i++) - { - if (msg[i] == DLE) - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - /*endif*/ - s->at_state.rx_data[s->at_state.rx_data_bytes++] = msg[i]; - } - /*endfor*/ - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - s->at_state.rx_data[s->at_state.rx_data_bytes++] = ETX; - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, s->at_state.rx_data, s->at_state.rx_data_bytes); - s->at_state.rx_data_bytes = 0; - } - /*endif*/ - at_put_response_code(&s->at_state, msg[0]); - } - else - { - s->at_state.dte_is_waiting = true; - break; - } - /*endif*/ - } - while (msg[0] == AT_RESPONSE_CODE_CONNECT); - } - /*endif*/ - break; - default: - switch (val) - { - case 24: - 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->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->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->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->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->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->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->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->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->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->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->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->bit_rate = 14400; - break; - default: - return -1; - } - /*endswitch*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Short training = %d, bit rate = %d\n", s->short_train, s->bit_rate); - if (new_transmit) - { - t31_set_at_rx_mode(s, AT_MODE_STUFFED); - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - } - else - { - t31_set_at_rx_mode(s, AT_MODE_DELIVERY); - } - /*endif*/ - restart_modem(s, new_modem); - break; - } - /*endswitch*/ - return false; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t31_call_event(t31_state_t *s, int event) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "Call event %s (%d) received\n", at_call_state_to_str(event), event); - at_call_event(&s->at_state, event); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_at_rx_free_space(t31_state_t *s) -{ - return T31_TX_BUF_LEN - (s->non_ecm_tx.in_bytes - s->non_ecm_tx.out_bytes) - 1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_at_rx(t31_state_t *s, const char *t, int len) -{ - if (s->dte_data_timeout) - s->dte_data_timeout = s->call_samples + ms_to_samples(5000); - /*endif*/ - switch (s->at_state.at_rx_mode) - { - case AT_MODE_ONHOOK_COMMAND: - case AT_MODE_OFFHOOK_COMMAND: - at_interpreter(&s->at_state, t, len); - break; - case AT_MODE_DELIVERY: - /* Data from the DTE in this state returns us to command mode */ - if (len) - { - if (s->at_state.rx_signal_present) - { - s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE; - s->at_state.rx_data[s->at_state.rx_data_bytes++] = ETX; - s->at_state.at_tx_handler(s->at_state.at_tx_user_data, s->at_state.rx_data, s->at_state.rx_data_bytes); - } - /*endif*/ - s->at_state.rx_data_bytes = 0; - 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); - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - } - /*endif*/ - break; - case AT_MODE_HDLC: - dle_unstuff_hdlc(s, t, len); - break; - case AT_MODE_STUFFED: - if (s->non_ecm_tx.out_bytes) - { - /* Make room for new data in existing data buffer. */ - s->non_ecm_tx.in_bytes -= s->non_ecm_tx.out_bytes; - memmove(&s->non_ecm_tx.buf[0], &s->non_ecm_tx.buf[s->non_ecm_tx.out_bytes], s->non_ecm_tx.in_bytes); - s->non_ecm_tx.out_bytes = 0; - } - /*endif*/ - if (s->t38_fe.ecm_mode == 2) - dle_unstuff_fake_hdlc(s, t, len); - else - dle_unstuff(s, t, len); - /*endif*/ - break; - case AT_MODE_CONNECTED: - /* TODO: Implement for data modem operation */ - break; - } - /*endswitch*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int silence_rx(void *user_data, const int16_t amp[], int len) -{ - t31_state_t *s; - - /* Searching for a specified minimum period of silence. */ - s = (t31_state_t *) user_data; - if (s->silence_awaited && s->audio.silence_heard >= s->silence_awaited) - { - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - s->audio.silence_heard = 0; - s->silence_awaited = 0; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int initial_timed_rx(void *user_data, const int16_t amp[], int len) -{ - t31_state_t *s; - - s = (t31_state_t *) user_data; - if (s->call_samples > ms_to_samples(s->at_state.p.s_regs[7]*1000)) - { - /* After calling, S7 has elapsed... no carrier found. */ - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_NO_CARRIER); - restart_modem(s, FAX_MODEM_SILENCE_TX); - at_modem_control(&s->at_state, AT_MODEM_CONTROL_HANGUP, NULL); - t31_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - return 0; - } - fsk_rx(&s->audio.modems.v21_rx, amp, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_rx(t31_state_t *s, int16_t amp[], int len) -{ - int i; - int32_t power; - - /* Monitor for received silence. Maximum needed detection is AT+FRS=255 (255*10ms). */ - /* We could probably only run this loop if (s->modem == FAX_MODEM_SILENCE_RX), however, - the spec says "when silence has been present on the line for the amount of - time specified". That means some of the silence may have occurred before - the AT+FRS=n command. This condition, however, is not likely to ever be the - case. (AT+FRS=n will usually be issued before the remote goes silent.) */ - for (i = 0; i < len; i++) - { - /* Clean up any DC influence. */ - power = power_meter_update(&s->audio.rx_power, amp[i] - s->audio.last_sample); - s->audio.last_sample = amp[i]; - if (power > s->audio.silence_threshold_power) - { - s->audio.silence_heard = 0; - } - else - { - if (s->audio.silence_heard <= ms_to_samples(255*10)) - s->audio.silence_heard++; - /*endif*/ - } - /*endif*/ - } - /*endfor*/ - - /* Time is determined by counting the samples in audio packets coming in. */ - s->call_samples += len; - - /* In HDLC transmit mode, if 5 seconds elapse without data from the DTE - we must treat this as an error. We return the result ERROR, and change - to command-mode. */ - if (s->dte_data_timeout && s->call_samples > s->dte_data_timeout) - { - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_ERROR); - restart_modem(s, FAX_MODEM_SILENCE_TX); - } - /*endif*/ - - if (s->audio.modems.rx_handler) - s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_rx_fillin(t31_state_t *s, int len) -{ - /* To mitigate the effect of lost packets on a packet network we should - try to sustain the status quo. If there is no receive modem running, keep - things that way. If there is a receive modem running, try to sustain its - operation, without causing a phase hop, or letting its adaptive functions - diverge. */ - /* Time is determined by counting the samples in audio packets coming in. */ - s->call_samples += len; - - /* In HDLC transmit mode, if 5 seconds elapse without data from the DTE - we must treat this as an error. We return the result ERROR, and change - to command-mode. */ - if (s->dte_data_timeout && s->call_samples > s->dte_data_timeout) - { - t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - at_put_response_code(&s->at_state, AT_RESPONSE_CODE_ERROR); - restart_modem(s, FAX_MODEM_SILENCE_TX); - } - /*endif*/ - - s->audio.modems.rx_fillin_handler(s->audio.modems.rx_fillin_user_data, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) -{ - int len; - - len = 0; - if (s->at_state.transmit) - { - 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 */ - 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*/ - } - /*endif*/ - } - /*endif*/ - if (s->audio.modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - vec_zeroi16(&[len], max_len - len); - len = max_len; - } - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -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, bool use_tep) -{ - s->audio.modems.use_tep = use_tep; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t31_set_t38_config(t31_state_t *s, bool without_pacing) -{ - if (without_pacing) - { - /* Continuous streaming mode, as used for TPKT over TCP transport */ - /* Inhibit indicator packets */ - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_INDICATOR, 0); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA, 1); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA_END, 1); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA, 1); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA_END, 1); - s->t38_fe.us_per_tx_chunk = 0; - } - else - { - /* Paced streaming mode, as used for UDP transports */ - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_INDICATOR, INDICATOR_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA, DATA_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA_END, DATA_END_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA, DATA_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA_END, DATA_END_TX_COUNT); - s->t38_fe.us_per_tx_chunk = US_PER_TX_CHUNK; - } - /*endif*/ - set_octets_per_data_packet(s, 300); -} -/*- End of function --------------------------------------------------------*/ - -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); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t31_get_logging_state(t31_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(at_state_t *) t31_get_at_state(t31_state_t *s) -{ - return &s->at_state; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t38_core_state_t *) t31_get_t38_core_state(t31_state_t *s) -{ - return &s->t38_fe.t38; -} -/*- End of function --------------------------------------------------------*/ - -static int t31_t38_fe_init(t31_state_t *t, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data) -{ - t31_t38_front_end_state_t *s; - - s = &t->t38_fe; - - t38_core_init(&s->t38, - process_rx_indicator, - process_rx_data, - process_rx_missing, - (void *) t, - tx_packet_handler, - tx_packet_user_data); - s->t38.fastest_image_data_rate = 14400; - - s->timed_step = T38_TIMED_STEP_NONE; - //s->iaf = T30_IAF_MODE_T37 | T30_IAF_MODE_T38; - s->iaf = T30_IAF_MODE_T38; - - s->current_tx_data_type = T38_DATA_NONE; - s->next_tx_samples = 0; - s->chunking_modes = T38_CHUNKING_ALLOW_TEP_TIME; - - t->hdlc_tx.ptr = 0; - - /* Prepare the non-ecm HDLC bit stream -> T.38 HDLC -> non-ecm HDLC bit stream path */ - 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 --------------------------------------------------------*/ - -SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, - at_tx_handler_t at_tx_handler, - void *at_tx_user_data, - t31_modem_control_handler_t modem_control_handler, - void *modem_control_user_data, - t38_tx_packet_handler_t tx_t38_packet_handler, - void *tx_t38_packet_user_data) -{ - v8_parms_t v8_parms; - int alloced; - - if (at_tx_handler == NULL || modem_control_handler == NULL) - return NULL; - /*endif*/ - - alloced = false; - if (s == NULL) - { - if ((s = (t31_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - alloced = true; - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "T.31"); - - s->modem_control_handler = modem_control_handler; - s->modem_control_user_data = modem_control_user_data; - fax_modems_init(&s->audio.modems, - false, - hdlc_accept_frame, - hdlc_tx_underflow, - non_ecm_put_bit, - non_ecm_get_bit, - tone_detected, - (void *) s); - 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); - v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - v8_parms.call_function = V8_CALL_T30_RX; - v8_parms.modulations = V8_MOD_V21 -#if 0 - | V8_MOD_V34HALF -#endif - | V8_MOD_V17 - | V8_MOD_V29 - | V8_MOD_V27TER; - v8_parms.protocol = V8_PROTOCOL_NONE; - v8_parms.pcm_modem_availability = 0; - v8_parms.pstn_access = 0; - v8_parms.nsf = -1; - v8_parms.t66 = -1; - 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.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; - - if (s->rx_queue) - queue_free(s->rx_queue); - if ((s->rx_queue = queue_init(NULL, 4096, QUEUE_WRITE_ATOMIC | QUEUE_READ_ATOMIC)) == NULL) - { - if (alloced) - span_free(s); - /*endif*/ - return NULL; - } - /*endif*/ - at_init(&s->at_state, at_tx_handler, at_tx_user_data, t31_modem_control_handler, s); - at_set_class1_handler(&s->at_state, process_class1_cmd, s); - s->at_state.dte_inactivity_timeout = DEFAULT_DTE_TIMEOUT; - 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); - } - /*endif*/ - s->t38_mode = false; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_release(t31_state_t *s) -{ - at_reset_call_info(&s->at_state); - v8_release(&s->audio.v8); - fax_modems_release(&s->audio.modems); - queue_free(s->rx_queue); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t31_free(t31_state_t *s) -{ - t31_release(s); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t35.c b/libs/spandsp/src/t35.c deleted file mode 100644 index c6fbaf8b41..0000000000 --- a/libs/spandsp/src/t35.c +++ /dev/null @@ -1,944 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t35.c - ITU T.35 FAX non-standard facility processing. - * - * 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. - */ - -/* - * The NSF data tables are adapted from the NSF handling in HylaFAX, which - * carries the following copyright notice: - * - * Created by Dmitry Bely, April 2000 - * Copyright (c) 1994-1996 Sam Leffler - * Copyright (c) 1994-1996 Silicon Graphics, Inc. - * HylaFAX is a trademark of Silicon Graphics - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that (i) the above copyright notices and this permission notice appear in - * all copies of the software and related documentation, and (ii) the names of - * Sam Leffler and Silicon Graphics may not be used in any advertising or - * publicity relating to the software without the specific, prior written - * permission of Sam Leffler and Silicon Graphics. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR - * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, - * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF - * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#if defined(HAVE_STDBOOL_H) -#include -#else -#include "spandsp/stdbool.h" -#endif - -#include "spandsp/telephony.h" -#include "spandsp/bit_operations.h" -#include "spandsp/t35.h" - -/*! NSF pattern for FAX machine identification */ -typedef struct -{ - /*! The number of bytes of the NSF byte string to match */ - int model_id_size; - /*! The NSF byte string to expect */ - const char *model_id; - /*! The model name of the FAX terminal */ - const char *model_name; -} model_data_t; - -/*! NSF pattern for identifying the manufacturer of a FAX machine */ -typedef struct -{ - /*! The vendor ID byte string */ - const char *vendor_id; - /*! The length of the vendor ID byte string */ - int vendor_id_len; - /*! The vendor's name */ - const char *vendor_name; - /*! 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; -} nsf_data_t; - -/*! T.35 country codes */ -typedef struct -{ - /*! The country's name */ - const char *name; - /*! A pointer to a list of known vendors from this country */ - const nsf_data_t *vendors; -} country_code_t; - -static const model_data_t Canon[] = -{ - {5, "\x80\x00\x80\x48\x00", "Faxphone B640"}, - {5, "\x80\x00\x80\x49\x10", "Fax B100"}, - {5, "\x80\x00\x8A\x49\x10", "Laser Class 9000 Series"}, - {5, "\x80\x00\x8A\x48\x00", "Laser Class 2060"}, - {0, NULL, NULL} -}; - -static const model_data_t Brother[] = -{ - {9, "\x55\x55\x00\x88\x90\x80\x5F\x00\x15\x51", "Intellifax 770"}, - {9, "\x55\x55\x00\x80\xB0\x80\x00\x00\x59\xD4", "Personal fax 190"}, - {9, "\x55\x55\x00\x8C\x90\x80\xF0\x02\x20", "MFC-8600"}, - {0, NULL, NULL} -}; - -static const model_data_t Panasonic0E[] = -{ - {10, "\x00\x00\x00\x96\x0F\x01\x02\x00\x10\x05\x02\x95\xC8\x08\x01\x49\x02\x41\x53\x54\x47", "KX-F90"}, - {10, "\x00\x00\x00\x96\x0F\x01\x03\x00\x10\x05\x02\x95\xC8\x08\x01\x49\x02\x03", "KX-F230 or KX-FT21 or ..."}, - {10, "\x00\x00\x00\x16\x0F\x01\x03\x00\x10\x05\x02\x95\xC8\x08", "KX-F780"}, - {10, "\x00\x00\x00\x16\x0F\x01\x03\x00\x10\x00\x02\x95\x80\x08\x75\xB5", "KX-M260"}, - {10, "\x00\x00\x00\x16\x0F\x01\x02\x00\x10\x05\x02\x85\xC8\x08\xAD", "KX-F2050BS"}, - {0, NULL, NULL} -}; - -static const model_data_t Panasonic79[] = -{ - {10, "\x00\x00\x00\x02\x0F\x09\x12\x00\x10\x05\x02\x95\xC8\x88\x80\x80\x01", "UF-S10"}, - {10, "\x00\x00\x00\x16\x7F\x09\x13\x00\x10\x05\x16\x8D\xC0\xD0\xF8\x80\x01", "/Siemens Fax 940"}, - {10, "\x00\x00\x00\x16\x0F\x09\x13\x00\x10\x05\x06\x8D\xC0\x50\xCB", "Panafax UF-321"}, - {0, NULL, NULL} -}; - -static const model_data_t Ricoh[] = -{ - {10, "\x00\x00\x00\x12\x10\x0D\x02\x00\x50\x00\x2A\xB8\x2C", "/Nashuatec P394"}, - {0, NULL, NULL} -}; - -static const model_data_t Samsung16[] = -{ - {4, "\x00\x00\xA4\x01", "M545 6800"}, - {0, NULL, NULL} -}; - -static const model_data_t Samsung5A[] = -{ - {4, "\x00\x00\xC0\x00", "SF-5100"}, - {0, NULL, NULL} -}; - -static const model_data_t Samsung8C[] = -{ - {4, "\x00\x00\x01\x00", "SF-2010"}, - {0, NULL, NULL} -}; - -static const model_data_t SamsungA2[] = -{ - {4, "\x00\x00\x80\x00", "FX-4000"}, - {0, NULL, NULL} -}; - -static const model_data_t Sanyo[] = -{ - {10, "\x00\x00\x10\xB1\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x41\x26\xFF\xFF\x00\x00\x85\xA1", "SFX-107"}, - {10, "\x00\x00\x00\xB1\x12\xF2\x62\xB4\x82\x0A\xF2\x2A\x12\xD2\xA2\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x41\x4E\xFF\xFF\x00\x00", "MFP-510"}, - {0, NULL, NULL} -}; - -static const model_data_t HP[] = -{ - {5, "\x20\x00\x45\x00\x0C\x04\x70\xCD\x4F\x00\x7F\x49", "LaserJet 3150"}, - {5, "\x40\x80\x84\x01\xF0\x6A", "OfficeJet"}, - {5, "\xC0\x00\x00\x00\x00", "OfficeJet 500"}, - {5, "\xC0\x00\x00\x00\x00\x8B", "Fax-920"}, - {0, NULL, NULL} -}; - -static const model_data_t Sharp[] = -{ - {32, "\x00\xCE\xB8\x80\x80\x11\x85\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\x00\x00\x00\x00\x00\x00\x00\x00\xED\x22\xB0\x00\x00\x90\x00", "Sharp F0-10"}, - {33, "\x00\xCE\xB8\x80\x80\x11\x85\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\x00\x00\x00\x00\x00\x00\x00\x00\xED\x22\xB0\x00\x00\x90\x00\x8C", "Sharp UX-460"}, - {33, "\x00\x4E\xB8\x80\x80\x11\x84\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\x00\x00\x00\x00\x00\x00\x00\x00\xED\x22\xB0\x00\x00\x90\x00\xAD", "Sharp UX-177"}, - {33, "\x00\xCE\xB8\x00\x84\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\xDD\xDD\xDD\x02\x05\x28\x02\x22\x43\x29\xED\x23\x90\x00\x00\x90\x01\x00", "Sharp FO-4810"}, - {0, NULL, NULL} -}; - -static const model_data_t Xerox[] = -{ - {10, "\x00\x08\x2D\x43\x57\x50\x61\x75\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01\x1A\x02\x02\x10\x01\x82\x01\x30\x34", "635 Workcenter"}, - {0, NULL, NULL} -}; - -static const model_data_t XeroxDA[] = -{ - {4, "\x00\x00\xC0\x00", "Workcentre Pro 580"}, - {0, NULL, NULL} -}; - -static const model_data_t Lexmark[] = -{ - {4, "\x00\x80\xA0\x00", "X4270"}, - {0, NULL, NULL} -}; - -static const model_data_t JetFax[] = -{ - {6, "\x01\x00\x45\x00\x0D\x7F", "M910e"}, - {0, NULL, NULL} -}; - -static const model_data_t PitneyBowes[] = -{ - {6, "\x79\x91\xB1\xB8\x7A\xD8", "9550"}, - {0, NULL, NULL} -}; - -static const model_data_t Dialogic[] = -{ - {8, "\x56\x8B\x06\x55\x00\x15\x00\x00", "VFX/40ESC"}, - {0, NULL, NULL} -}; - -static const model_data_t Muratec45[] = -{ - {10, "\xF4\x91\xFF\xFF\xFF\x42\x2A\xBC\x01\x57", "M4700"}, - {0, NULL, NULL} -}; - -/* Muratec uses unregistered Japan code "00 00 48" */ -static const model_data_t Muratec48[] = -{ - {3, "\x53\x53\x61", "M620"}, - {0, NULL, NULL} -}; - -/* - * Country code first byte, then manufacturer is last two bytes. See T.35. - * Apparently Germany issued some manufacturer codes before the two-byte - * standard was accepted, and so some few German manufacturers are - * identified by a single manufacturer byte. - * - * T.30 5.3.6.2.7 (2003) states that the NSF FIF is transmitted - * in MSB2LSB order. Revisions of T.30 prior to 2003 did not - * contain explicit specification as to the transmit bit order. - * (Although it did otherwise state that all HDLC frame data should - * be in MSB order except as noted.) Because CSI, TSI, and other - * prologue frames were in LSB order by way of an exception to the - * general rule (T.30 5.3.6.2.4-11) many manufacturers assumed that - * NSF should also be in LSB order. Consequently there will be - * some country-code "masquerading" as a terminal may use the - * proper country-code, but with an inverted bit order. - * - * Thus, country code x61 (Korea) turns into x86 (Papua New Guinea), - * code xB5 (USA) turns into xAD (Tunisia), code x26 (China) turns - * into x64 (Lebanon), code x04 (Germany) turns into x20 (Canada), - * and code x3D (France) turns into xBC (Vietnam). - * - * For the most part it should be safe to identify a manufacturer - * both with the MSB and LSB ordered bits, as the "masqueraded" country - * is likely to not be actively assigning T.38 manufacturer codes. - * However, some manufacturers (e.g. Microsoft) may use MSB for the - * country code and LSB for the rest of the NSF, and so basically this - * table must be verified and corrected against actual real-world - * results. - */ -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} -}; - -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} -}; - -static const nsf_data_t vendor_61[] = -{ - /* Korea */ - {"\x00\x7A", 2, "Xerox", 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} -}; - -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} -}; - -static const nsf_data_t vendor_ad[] = -{ - /* United States (not Tunisia) */ - {"\x00\x00", 2, "Pitney Bowes", false, PitneyBowes}, - {"\x00\x0C", 2, "Dialogic", false, Dialogic}, - {"\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} -}; - -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, Dialogic}, - {"\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 nsf_data_t vendor_bc[] = -{ - /* France (not Vietnam) */ - {"\x53\x01", 2, "Minolta", false, NULL}, - {NULL, 0, NULL, false, NULL} -}; - -static const country_code_t t35_country_codes[255] = -{ - {"Japan", vendor_00}, /* 0x00 */ - {"Albania", NULL}, - {"Algeria", NULL}, - {"American Samoa", NULL}, - {"Germany", NULL}, - {"Anguilla", NULL}, - {"Antigua and Barbuda", NULL}, - {"Argentina", NULL}, - {"Ascension (see S. Helena)", NULL}, - {"Australia", NULL}, - {"Austria", NULL}, - {"Bahamas", NULL}, - {"Bahrain", NULL}, - {"Bangladesh", NULL}, - {"Barbados", NULL}, - {"Belgium", NULL}, - {"Belize", NULL}, /* 0x10 */ - {"Benin (Republic of)", NULL}, - {"Bermudas", NULL}, - {"Bhutan (Kingdom of)", NULL}, - {"Bolivia", NULL}, - {"Botswana", NULL}, - {"Brazil", NULL}, - {"British Antarctic Territory", NULL}, - {"British Indian Ocean Territory", NULL}, - {"British Virgin Islands", NULL}, - {"Brunei Darussalam", NULL}, - {"Bulgaria", NULL}, - {"Myanmar (Union of)", NULL}, - {"Burundi", NULL}, - {"Byelorussia", NULL}, - {"Cameroon", NULL}, - {"Canada", vendor_20}, /* 0x20 */ - {"Cape Verde", NULL}, - {"Cayman Islands", NULL}, - {"Central African Republic", NULL}, - {"Chad", NULL}, - {"Chile", NULL}, - {"China", NULL}, - {"Colombia", NULL}, - {"Comoros", NULL}, - {"Congo", NULL}, - {"Cook Islands", NULL}, - {"Costa Rica", NULL}, - {"Cuba", NULL}, - {"Cyprus", NULL}, - {"Czech and Slovak Federal Republic", NULL}, /* 0x30 */ - {"Cambodia", NULL}, - {"Democratic People's Republic of Korea", NULL}, - {"Denmark", NULL}, - {"Djibouti", NULL}, - {"Dominican Republic", NULL}, - {"Dominica", NULL}, - {"Ecuador", NULL}, - {"Egypt", NULL}, - {"El Salvador", NULL}, - {"Equatorial Guinea", NULL}, - {"Ethiopia", NULL}, - {"Falkland Islands", NULL}, - {"Fiji", NULL}, - {"Finland", NULL}, - {"France", NULL}, - {"French Polynesia", NULL}, - {"French Southern and Antarctic Lands", NULL}, - {"Gabon", NULL}, /* 0x40 */ - {"Gambia", NULL}, - {"Germany (Federal Republic of)", NULL}, - {"Angola", NULL}, - {"Ghana", NULL}, - {"Gibraltar", NULL}, - {"Greece", NULL}, - {"Grenada", NULL}, - {"Guam", NULL}, - {"Guatemala", NULL}, - {"Guernsey", NULL}, - {"Guinea", NULL}, - {"Guinea-Bissau", NULL}, - {"Guayana", NULL}, - {"Haiti", NULL}, - {"Honduras", NULL}, - {"Hong Kong", NULL}, /* 0x50 */ - {"Hungary (Republic of)", NULL}, - {"Iceland", NULL}, - {"India", NULL}, - {"Indonesia", NULL}, - {"Iran (Islamic Republic of)", NULL}, - {"Iraq", NULL}, - {"Ireland", NULL}, - {"Israel", NULL}, - {"Italy", NULL}, - {"Cote d'Ivoire", NULL}, - {"Jamaica", NULL}, - {"Afghanistan", NULL}, - {"Jersey", NULL}, - {"Jordan", NULL}, - {"Kenya", NULL}, - {"Kiribati", NULL}, /* 0x60 */ - {"Korea (Republic of)", vendor_61}, - {"Kuwait", NULL}, - {"Lao (People's Democratic Republic)", NULL}, - {"Lebanon", vendor_64}, - {"Lesotho", NULL}, - {"Liberia", NULL}, - {"Libya", NULL}, - {"Liechtenstein", NULL}, - {"Luxembourg", NULL}, - {"Macau", NULL}, - {"Madagascar", NULL}, - {"Malaysia", NULL}, - {"Malawi", NULL}, - {"Maldives", NULL}, - {"Mali", NULL}, - {"Malta", NULL}, /* 0x70 */ - {"Mauritania", NULL}, - {"Mauritius", NULL}, - {"Mexico", NULL}, - {"Monaco", NULL}, - {"Mongolia", NULL}, - {"Montserrat", NULL}, - {"Morocco", NULL}, - {"Mozambique", NULL}, - {"Nauru", NULL}, - {"Nepal", NULL}, - {"Netherlands", NULL}, - {"Netherlands Antilles", NULL}, - {"New Caledonia", NULL}, - {"New Zealand", NULL}, - {"Nicaragua", NULL}, - {"Niger", NULL}, /* 0x80 */ - {"Nigeria", NULL}, - {"Norway", NULL}, - {"Oman", NULL}, - {"Pakistan", NULL}, - {"Panama", NULL}, - {"Papua New Guinea", vendor_86}, - {"Paraguay", NULL}, - {"Peru", NULL}, - {"Philippines", NULL}, - {"Poland (Republic of)", NULL}, - {"Portugal", NULL}, - {"Puerto Rico", NULL}, - {"Qatar", NULL}, - {"Romania", NULL}, - {"Rwanda", NULL}, - {"Saint Kitts and Nevis", NULL}, /* 0x90 */ - {"Saint Croix", NULL}, - {"Saint Helena and Ascension", NULL}, - {"Saint Lucia", NULL}, - {"San Marino", NULL}, - {"Saint Thomas", NULL}, - {"Sao Tome and Principe", NULL}, - {"Saint Vincent and the Grenadines", NULL}, - {"Saudi Arabia", NULL}, - {"Senegal", NULL}, - {"Seychelles", NULL}, - {"Sierra Leone", NULL}, - {"Singapore", NULL}, - {"Solomon Islands", NULL}, - {"Somalia", NULL}, - {"South Africa", NULL}, - {"Spain", NULL}, /* 0xA0 */ - {"Sri Lanka", NULL}, - {"Sudan", NULL}, - {"Suriname", NULL}, - {"Swaziland", NULL}, - {"Sweden", NULL}, - {"Switzerland", NULL}, - {"Syria", NULL}, - {"Tanzania", NULL}, - {"Thailand", NULL}, - {"Togo", NULL}, - {"Tonga", NULL}, - {"Trinidad and Tobago", NULL}, - {"Tunisia", vendor_ad}, - {"Turkey", NULL}, - {"Turks and Caicos Islands", NULL}, - {"Tuvalu", NULL}, /* 0xB0 */ - {"Uganda", NULL}, - {"Ukraine", NULL}, - {"United Arab Emirates", NULL}, - {"United Kingdom", vendor_b4}, - {"United States", vendor_b5}, - {"Burkina Faso", NULL}, - {"Uruguay", NULL}, - {"U.S.S.R.", NULL}, - {"Vanuatu", NULL}, - {"Vatican City State", NULL}, - {"Venezuela", NULL}, - {"Vietnam", vendor_bc}, - {"Wallis and Futuna", NULL}, - {"Western Samoa", NULL}, - {"Yemen (Republic of)", NULL}, - {"Yemen (Republic of)", NULL}, /* 0xC0 */ - {"Yugoslavia", NULL}, - {"Zaire", NULL}, - {"Zambia", NULL}, - {"Zimbabwe", NULL}, - {"Slovakia", NULL}, - {"Slovenia", NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, /* 0xD0 */ - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, /* 0xE0 */ - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, /* 0xF0 */ - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {NULL, NULL}, - {"Lithuania", NULL}, - {"Latvia", NULL}, - {"Estonia", NULL}, - {"US Virgin Islands", NULL}, - {NULL, NULL}, - {NULL, NULL}, - {"(Universal)", NULL}, - {"Taiwan", NULL} -}; - -SPAN_DECLARE(int) t35_real_country_code(int country_code, int country_code_extension) -{ - if (country_code < 0 || country_code > 0xFF) - return -1; - if (country_code == 0xFF) - { - /* The extension code gives us the country. */ - /* Right now there are no extension codes defined by the ITU */ - return -1; - } - /* We need to apply realism over accuracy, though it blocks out some countries. - It is very rare to find a machine from any country but the following: - - Japan 0x00 (no confusion) - Germany 0x04 (0x20) (Canada/Germany confusion) - China 0x26 (0x64) (China/Lebanon confusion) - Korea 0x61 (0x86) (Korea/Papua New Guinea confusion) - UK 0xB4 (0x2D) (UK/Cyprus confusion) - USA 0xB5 (0xAD) (USA/Tunisia confusion) - France 0x3D (0xBC) (France/Vietnam confusion) - - If we force the most likely of the two possible countries (forward or bit reversed), - the only mixup with any realistic probability is the Canada/Germany confusion. We - will just live with this, and force the more likely countries. */ - switch (country_code) - { - case 0x20: - /* Force Germany */ - case 0x2D: - /* Force UK */ - case 0x64: - /* Force China */ - case 0x86: - /* Force Korea */ - case 0xAD: - /* Force USA */ - case 0xBC: - /* Force France */ - country_code = bit_reverse8(country_code); - break; - } - /* Try the country code at face value, then bit reversed */ - if (t35_country_codes[country_code].name) - return country_code; - /* If the country code is missing, its most likely the country code is reversed. */ - country_code = bit_reverse8(country_code); - if (t35_country_codes[country_code].name) - return country_code; - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t35_real_country_code_to_str(int country_code, int country_code_extension) -{ - int real_code; - - if ((real_code = t35_real_country_code(country_code, country_code_extension)) >= 0) - return t35_country_codes[real_code].name; - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t35_country_code_to_str(int country_code, int country_code_extension) -{ - if (country_code < 0 || country_code > 0xFF) - return NULL; - if (country_code == 0xFF) - { - /* The extension code gives us the country. */ - /* Right now there are no extension codes defined by the ITU */ - return NULL; - } - - return t35_country_codes[country_code].name; -} -/*- End of function --------------------------------------------------------*/ - -static const nsf_data_t *find_vendor(const uint8_t *msg, int len) -{ - const nsf_data_t *vendors; - const nsf_data_t *p; - int real_country_code; - - if (msg[0] == 0xFF) - { - /* The extension code gives us the country. */ - /* Right now there are no extension codes defined by the ITU */ - return NULL; - } - if ((real_country_code = t35_real_country_code(msg[0], msg[1])) < 0) - return NULL; - if ((vendors = t35_country_codes[msg[0]].vendors) == NULL) - return NULL; - for (p = vendors; p->vendor_id; p++) - { - if (len >= p->vendor_id_len - && - memcmp(p->vendor_id, &msg[1], p->vendor_id_len) == 0) - { - return p; - } - } - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t35_vendor_to_str(const uint8_t *msg, int len) -{ - const nsf_data_t *p; - - if ((p = find_vendor(msg, len)) == NULL) - return NULL; - return p->vendor_name; -} -/*- End of function --------------------------------------------------------*/ - -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; - - if (country) - *country = t35_real_country_code_to_str(msg[0], msg[1]); - if (vendor) - *vendor = NULL; - if (model) - *model = NULL; - - if ((p = find_vendor(msg, len)) == NULL) - return false; - if (vendor) - *vendor = p->vendor_name; - if (model && p->known_models) - { - for (pp = p->known_models; pp->model_id; pp++) - { - if (len == 1 + p->vendor_id_len + pp->model_id_size - && - memcmp(&msg[1 + p->vendor_id_len], pp->model_id, pp->model_id_size) == 0) - { - *model = pp->model_name; - break; - } - } - } - return true; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c deleted file mode 100644 index 347549549f..0000000000 --- a/libs/spandsp/src/t38_core.c +++ /dev/null @@ -1,1256 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_core.c - Encode and decode the ASN.1 of a T.38 IFP message - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006 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 -#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/bit_operations.h" -#include "spandsp/t38_core.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/t38_core.h" - -#define ACCEPTABLE_SEQ_NO_OFFSET 2000 - -/* The times for training, the optional TEP, and the HDLC preamble, for all the modem options, in ms. - Note that the preamble for V.21 is 1s+-15%, and for the other modems is 200ms+100ms. */ -static const struct -{ - int tep; - int training; - int flags; -} modem_startup_time[] = -{ - { 0, 75000, 0}, /* T38_IND_NO_SIGNAL */ - { 0, 0, 0}, /* T38_IND_CNG */ - { 0, 3000000, 0}, /* T38_IND_CED */ - { 0, 0, 1000000}, /* T38_IND_V21_PREAMBLE */ /* TODO: 850ms should be OK for this, but it causes trouble with some ATAs. Why? */ - { 215000, 943000, 200000}, /* T38_IND_V27TER_2400_TRAINING */ - { 215000, 708000, 200000}, /* T38_IND_V27TER_4800_TRAINING */ - { 215000, 234000, 200000}, /* T38_IND_V29_7200_TRAINING */ - { 215000, 234000, 200000}, /* T38_IND_V29_9600_TRAINING */ - { 215000, 142000, 200000}, /* T38_IND_V17_7200_SHORT_TRAINING */ - { 215000, 1393000, 200000}, /* T38_IND_V17_7200_LONG_TRAINING */ - { 215000, 142000, 200000}, /* T38_IND_V17_9600_SHORT_TRAINING */ - { 215000, 1393000, 200000}, /* T38_IND_V17_9600_LONG_TRAINING */ - { 215000, 142000, 200000}, /* T38_IND_V17_12000_SHORT_TRAINING */ - { 215000, 1393000, 200000}, /* T38_IND_V17_12000_LONG_TRAINING */ - { 215000, 142000, 200000}, /* T38_IND_V17_14400_SHORT_TRAINING */ - { 215000, 1393000, 200000}, /* T38_IND_V17_14400_LONG_TRAINING */ - { 0, 0, 0}, /* T38_IND_V8_ANSAM */ - { 0, 0, 0}, /* T38_IND_V8_SIGNAL */ - { 0, 0, 200000}, /* T38_IND_V34_CNTL_CHANNEL_1200 */ - { 0, 0, 200000}, /* T38_IND_V34_PRI_CHANNEL */ - { 0, 0, 0}, /* T38_IND_V34_CC_RETRAIN */ - { 215000, 0, 200000}, /* T38_IND_V33_12000_TRAINING */ - { 215000, 0, 200000} /* T38_IND_V33_14400_TRAINING */ -}; - -SPAN_DECLARE(const char *) t38_indicator_to_str(int indicator) -{ - switch (indicator) - { - case T38_IND_NO_SIGNAL: - return "no-signal"; - case T38_IND_CNG: - return "cng"; - case T38_IND_CED: - return "ced"; - case T38_IND_V21_PREAMBLE: - return "v21-preamble"; - case T38_IND_V27TER_2400_TRAINING: - return "v27-2400-training"; - case T38_IND_V27TER_4800_TRAINING: - return "v27-4800-training"; - case T38_IND_V29_7200_TRAINING: - return "v29-7200-training"; - case T38_IND_V29_9600_TRAINING: - return "v29-9600-training"; - case T38_IND_V17_7200_SHORT_TRAINING: - return "v17-7200-short-training"; - case T38_IND_V17_7200_LONG_TRAINING: - return "v17-7200-long-training"; - case T38_IND_V17_9600_SHORT_TRAINING: - return "v17-9600-short-training"; - case T38_IND_V17_9600_LONG_TRAINING: - return "v17-9600-long-training"; - case T38_IND_V17_12000_SHORT_TRAINING: - return "v17-12000-short-training"; - case T38_IND_V17_12000_LONG_TRAINING: - return "v17-12000-long-training"; - case T38_IND_V17_14400_SHORT_TRAINING: - return "v17-14400-short-training"; - case T38_IND_V17_14400_LONG_TRAINING: - return "v17-14400-long-training"; - case T38_IND_V8_ANSAM: - return "v8-ansam"; - case T38_IND_V8_SIGNAL: - return "v8-signal"; - case T38_IND_V34_CNTL_CHANNEL_1200: - return "v34-cntl-channel-1200"; - case T38_IND_V34_PRI_CHANNEL: - return "v34-pri-channel"; - case T38_IND_V34_CC_RETRAIN: - return "v34-CC-retrain"; - case T38_IND_V33_12000_TRAINING: - return "v33-12000-training"; - case T38_IND_V33_14400_TRAINING: - return "v33-14400-training"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t38_data_type_to_str(int data_type) -{ - switch (data_type) - { - case T38_DATA_V21: - return "v21"; - case T38_DATA_V27TER_2400: - return "v27-2400"; - case T38_DATA_V27TER_4800: - return "v27-4800"; - case T38_DATA_V29_7200: - return "v29-7200"; - case T38_DATA_V29_9600: - return "v29-9600"; - case T38_DATA_V17_7200: - return "v17-7200"; - case T38_DATA_V17_9600: - return "v17-9600"; - case T38_DATA_V17_12000: - return "v17-12000"; - case T38_DATA_V17_14400: - return "v17-14400"; - case T38_DATA_V8: - return "v8"; - case T38_DATA_V34_PRI_RATE: - return "v34-pri-rate"; - case T38_DATA_V34_CC_1200: - return "v34-CC-1200"; - case T38_DATA_V34_PRI_CH: - return "v34-pri-ch"; - case T38_DATA_V33_12000: - return "v33-12000"; - case T38_DATA_V33_14400: - return "v33-14400"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t38_field_type_to_str(int field_type) -{ - switch (field_type) - { - case T38_FIELD_HDLC_DATA: - return "hdlc-data"; - case T38_FIELD_HDLC_SIG_END: - return "hdlc-sig-end"; - case T38_FIELD_HDLC_FCS_OK: - return "hdlc-fcs-OK"; - case T38_FIELD_HDLC_FCS_BAD: - return "hdlc-fcs-BAD"; - case T38_FIELD_HDLC_FCS_OK_SIG_END: - return "hdlc-fcs-OK-sig-end"; - case T38_FIELD_HDLC_FCS_BAD_SIG_END: - return "hdlc-fcs-BAD-sig-end"; - case T38_FIELD_T4_NON_ECM_DATA: - return "t4-non-ecm-data"; - case T38_FIELD_T4_NON_ECM_SIG_END: - return "t4-non-ecm-sig-end"; - case T38_FIELD_CM_MESSAGE: - return "cm-message"; - case T38_FIELD_JM_MESSAGE: - return "jm-message"; - case T38_FIELD_CI_MESSAGE: - return "ci-message"; - case T38_FIELD_V34RATE: - return "v34rate"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t38_cm_profile_to_str(int profile) -{ - switch (profile) - { - case '1': - return "G3 FAX sending terminal"; - case '2': - return "G3 FAX receiving terminal"; - case '3': - return "V.34 HDX and G3 FAX sending terminal"; - case '4': - return "V.34 HDX and G3 FAX receiving terminal"; - case '5': - return "V.34 HDX-only FAX sending terminal"; - case '6': - return "V.34 HDX-only FAX receiving terminal"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t38_jm_to_str(const uint8_t *data, int len) -{ - if (len < 2) - return "???"; - /*endif*/ - switch (data[0]) - { - case 'A': - switch (data[1]) - { - case '0': - return "ACK"; - } - /*endswitch*/ - break; - case 'N': - switch (data[1]) - { - case '0': - return "NACK: No compatible mode available"; - case '1': - /* Response for profiles 1 and 2 */ - return "NACK: No V.34 FAX, use G3 FAX"; - case '2': - /* Response for profiles 5 and 6 */ - return "NACK: V.34 only FAX."; - } - /*endswitch*/ - break; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_v34rate_to_bps(const uint8_t *data, int len) -{ - int i; - int rate; - - if (len < 3) - return -1; - /*endif*/ - for (i = 0, rate = 0; i < 3; i++) - { - if (data[i] < '0' || data[i] > '9') - return -1; - /*endif*/ - rate = rate*10 + data[i] - '0'; - } - /*endfor*/ - return rate*100; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int classify_seq_no_offset(int expected, int actual) -{ - /* Classify the mismatch between expected and actual sequence numbers - according to whether the actual is a little in the past (late), a - little in the future (some packets have been lost), or a large jump - that represents the sequence being lost (possibly when some RTP - gets dumped to a UDPTL port). */ - /* This assumes they are not equal */ - if (expected > actual) - { - if (expected > actual + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET) - { - /* In the near future */ - return 1; - } - /*endif*/ - if (expected < actual + ACCEPTABLE_SEQ_NO_OFFSET) - { - /* In the recent past */ - return -1; - } - /*endif*/ - } - else - { - if (expected + ACCEPTABLE_SEQ_NO_OFFSET > actual) - { - /* In the near future */ - return 1; - } - /*endif*/ - if (expected + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET < actual) - { - /* In the recent past */ - return -1; - } - /*endif*/ - } - /*endif*/ - /* There has been a huge step in the sequence */ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no) -{ - int i; - int t30_indicator; - int t30_data; - int prev_ptr; - int ptr; - int other_half; - int numocts; - int pkt_len; - int ret; - const uint8_t *msg; - unsigned int count; - unsigned int t30_field_type; - uint8_t type; - uint8_t data_field_present; - uint8_t field_data_present; - char tag[20]; - - if (span_log_test(&s->logging, SPAN_LOG_FLOW)) - { - sprintf(tag, "Rx %5d: IFP", log_seq_no); - span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len); - } - /*endif*/ - ptr = 0; - pkt_len = len; - switch (s->data_transport_protocol) - { - case T38_TRANSPORT_TCP: - /* We don't know the actual packet length, so treat everythign we have as the packet */ - ret = 0; - break; - case T38_TRANSPORT_TCP_TPKT: - if (len >= 4) - { - /* Version */ - if (buf[0] != 3) - return -1; - /*endif*/ - /* Reserved */ - if (buf[1] != 0) - return -1; - /*endif*/ - /* Packet length - this includes the length of the header itself */ - pkt_len = (buf[2] << 8) | buf[3]; - if (len < pkt_len) - return 0; - /*endif*/ - ptr = 4; - } - /*endif*/ - ret = -1; - break; - default: - /* We know the actual packet length, and its the exact length of what we were passed. */ - ret = -1; - break; - } - /*endswitch*/ - if ((ptr + 1) > pkt_len) - return ret; - /*endif*/ - data_field_present = buf[ptr] & 0x80; - type = (buf[ptr] >> 6) & 1; - switch (type) - { - case T38_TYPE_OF_MSG_T30_INDICATOR: - /* Indicators should never have a data field */ - if (data_field_present) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Data field with indicator\n", log_seq_no); - return -1; - } - /*endif*/ - /* Any received indicator should mean we no longer have a valid concept of "last received data/field type". */ - s->current_rx_data_type = -1; - s->current_rx_field_type = -1; - if ((buf[ptr] & 0x20)) - { - /* Extension */ - if ((ptr + 2) > pkt_len) - return ret; - /*endif*/ - t30_indicator = T38_IND_V8_ANSAM + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3)); - if (t30_indicator > T38_IND_V33_14400_TRAINING) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown indicator - %d\n", log_seq_no, t30_indicator); - return -1; - } - /*endif*/ - ptr += 2; - } - else - { - t30_indicator = (buf[ptr] >> 1) & 0xF; - ptr += 1; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: indicator %s\n", log_seq_no, t38_indicator_to_str(t30_indicator)); - s->rx_indicator_handler(s, s->rx_user_data, t30_indicator); - /* This must come after the indicator handler, so the handler routine sees the existing state of the - indicator. */ - s->current_rx_indicator = t30_indicator; - break; - case T38_TYPE_OF_MSG_T30_DATA: - if ((buf[ptr] & 0x20)) - { - /* Extension */ - if ((ptr + 2) > pkt_len) - return ret; - /*endif*/ - t30_data = T38_DATA_V8 + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3)); - if (t30_data > T38_DATA_V33_14400) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown data type - %d\n", log_seq_no, t30_data); - return -1; - } - /*endif*/ - ptr += 2; - } - else - { - t30_data = (buf[ptr] >> 1) & 0xF; - if (t30_data > T38_DATA_V17_14400) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown data type - %d\n", log_seq_no, t30_data); - return -1; - } - /*endif*/ - ptr += 1; - } - /*endif*/ - if (!data_field_present) - { - /* This is kinda weird, but I guess if the length checks out we accept it. */ - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Data type with no data field\n", log_seq_no); - break; - } - /*endif*/ - if (ptr >= pkt_len) - return ret; - /*endif*/ - count = buf[ptr++]; - //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; - for (i = 0; i < (int) count; i++) - { - if (ptr >= pkt_len) - return ret; - /*endif*/ - if (s->t38_version == 0) - { - /* The original version of T.38 with a typo in the ASN.1 spec. */ - if (other_half) - { - /* The lack of a data field in the previous message means - we are currently in the middle of an octet. */ - field_data_present = (buf[ptr] >> 3) & 1; - /* Decode field_type */ - t30_field_type = buf[ptr] & 0x7; - ptr++; - other_half = false; - } - else - { - field_data_present = (buf[ptr] >> 7) & 1; - /* Decode field_type */ - t30_field_type = (buf[ptr] >> 4) & 0x7; - if (field_data_present) - ptr++; - else - other_half = true; - /*endif*/ - } - /*endif*/ - if (t30_field_type > T38_FIELD_T4_NON_ECM_SIG_END) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown field type - %d\n", log_seq_no, t30_field_type); - return -1; - } - /*endif*/ - } - else - { - field_data_present = (buf[ptr] >> 7) & 1; - /* Decode field_type */ - if ((buf[ptr] & 0x40)) - { - if ((ptr + 2) > pkt_len) - return ret; - /*endif*/ - t30_field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3)); - if (t30_field_type > T38_FIELD_V34RATE) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown field type - %d\n", log_seq_no, t30_field_type); - return -1; - } - /*endif*/ - ptr += 2; - } - else - { - ptr++; - } - /*endif*/ - } - /*endif*/ - /* Decode field_data */ - if (field_data_present) - { - if ((ptr + 2) > pkt_len) - return ret; - /*endif*/ - numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1; - ptr += numocts + 2; - } - /*endif*/ - if (ptr > pkt_len) - return ret; - /*endif*/ - } - /*endfor*/ - /* Check if we finished mid byte in a version 0 packet. */ - if (other_half) - ptr++; - /*endif*/ - if (ptr > pkt_len) - return ret; - /*endif*/ - - /* 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; - for (i = 0; i < (int) count; i++) - { - if (s->t38_version == 0) - { - /* The original version of T.38 with a typo in the ASN.1 spec. */ - if (other_half) - { - /* The lack of a data field in the previous message means - we are currently in the middle of an octet. */ - field_data_present = (buf[ptr] >> 3) & 1; - /* Decode field_type */ - t30_field_type = buf[ptr] & 0x7; - ptr++; - other_half = false; - } - else - { - field_data_present = (buf[ptr] >> 7) & 1; - /* Decode field_type */ - t30_field_type = (buf[ptr] >> 4) & 0x7; - if (field_data_present) - ptr++; - else - other_half = true; - /*endif*/ - } - /*endif*/ - } - else - { - field_data_present = (buf[ptr] >> 7) & 1; - /* Decode field_type */ - if ((buf[ptr] & 0x40)) - { - t30_field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3)); - ptr += 2; - } - else - { - t30_field_type = (buf[ptr++] >> 3) & 0x7; - } - /*endif*/ - } - /*endif*/ - /* Decode field_data */ - if (field_data_present) - { - numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1; - msg = buf + ptr + 2; - ptr += numocts + 2; - } - else - { - numocts = 0; - msg = NULL; - } - /*endif*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "Rx %5d: (%d) data %s/%s + %d byte(s)\n", - log_seq_no, - i, - t38_data_type_to_str(t30_data), - t38_field_type_to_str(t30_field_type), - numocts); - s->rx_data_handler(s, s->rx_user_data, t30_data, t30_field_type, msg, numocts); - s->current_rx_data_type = t30_data; - s->current_rx_field_type = t30_field_type; - } - /*endfor*/ - /* Check if we finished mid byte in a version 0 packet. */ - if (other_half) - ptr++; - /*endif*/ - break; - } - /*endswitch*/ - if (ptr > pkt_len) - return ret; - /*endif*/ - return ptr; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no) -{ - int log_seq_no; - int ptr; - - log_seq_no = (s->check_sequence_numbers) ? seq_no : s->rx_expected_seq_no; - - if (s->check_sequence_numbers) - { - seq_no &= 0xFFFF; - if (seq_no != s->rx_expected_seq_no) - { - /* An expected value of -1 indicates this is the first received packet, and will accept - anything for that. We can't assume they will start from zero, even though they should. */ - if (s->rx_expected_seq_no != -1) - { - /* We have a packet with a serial number that is not in sequence. The cause could be: - - 1. a repeat copy of a recent packet. Many T.38 implementations can preduce quite a lot of these. - - 2. a late packet, whose point in the sequence we have already passed. - - 3. the result of a hop in the sequence numbers cause by something weird from the other - end. Stream switching might cause this - - 4. missing packets. - - In cases 1 and 2 we need to drop this packet. In case 2 it might make sense to try to do - something with it in the terminal case. Currently we don't. For gateway operation it will be - too late to do anything useful. - */ - if (((seq_no + 1) & 0xFFFF) == s->rx_expected_seq_no) - { - /* Assume this is truly a repeat packet, and don't bother checking its contents. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Repeat packet number\n", log_seq_no); - return 0; - } - /*endif*/ - /* Distinguish between a little bit out of sequence, and a huge hop. */ - switch (classify_seq_no_offset(s->rx_expected_seq_no, seq_no)) - { - case -1: - /* This packet is in the near past, so its late. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Late packet - expected %d\n", log_seq_no, s->rx_expected_seq_no); - return 0; - case 1: - /* This packet is in the near future, so some packets have been lost */ - span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Missing from %d\n", log_seq_no, s->rx_expected_seq_no); - s->rx_missing_handler(s, s->rx_user_data, s->rx_expected_seq_no, seq_no); - s->missing_packets += (seq_no - s->rx_expected_seq_no); - break; - default: - /* The sequence has jumped wildly */ - span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Sequence restart\n", log_seq_no); - s->rx_missing_handler(s, s->rx_user_data, -1, -1); - s->missing_packets++; - break; - } - /*endswitch*/ - } - /*endif*/ - s->rx_expected_seq_no = seq_no; - } - /*endif*/ - } - /*endif*/ - if (len < 1) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Bad packet length - %d\n", log_seq_no, len); - return -1; - } - /*endif*/ - /* The sequence numbering is defined as rolling from 0xFFFF to 0x0000. Some implementations - of T.38 roll from 0xFFFF to 0x0001. Isn't standardisation a wonderful thing? The T.38 - document specifies only a small fraction of what it should, yet then they actually nail - something properly, people ignore it. Developers in this industry truly deserves the **** - **** **** **** **** **** documents they have to live with. Anyway, when the far end has a - broken rollover behaviour we will get a hiccup at the rollover point. Don't worry too - much. We will just treat the message in progress as one with some missing data. With any - luck a retry will ride over the problem. Rollovers don't occur that often. It takes quite - a few FAX pages to reach rollover. */ - s->rx_expected_seq_no = (s->rx_expected_seq_no + 1) & 0xFFFF; - - ptr = t38_core_rx_ifp_stream(s, buf, len, seq_no); - if (ptr != len) - { - if (ptr >= 0) - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for packet - %d %d\n", log_seq_no, ptr, len); - /*endif*/ - return -1; - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_encode_indicator(t38_core_state_t *s, uint8_t buf[], int indicator) -{ - int len; - - /* Build the IFP packet */ - len = 0; - if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT) - len = 4; - /*endif*/ - - /* Data field not present */ - /* Indicator packet */ - /* Type of indicator */ - if (indicator <= T38_IND_V17_14400_LONG_TRAINING) - { - buf[len++] = (uint8_t) (indicator << 1); - } - else if (s->t38_version != 0 && indicator <= T38_IND_V33_14400_TRAINING) - { - buf[len++] = (uint8_t) (0x20 | (((indicator - T38_IND_V8_ANSAM) & 0xF) >> 2)); - buf[len++] = (uint8_t) (((indicator - T38_IND_V8_ANSAM) << 6) & 0xFF); - } - else - { - len = -1; - } - /*endif*/ - if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT) - { - /* Fill in the TPKT header (see RFC1006) */ - /* Version */ - buf[0] = 3; - /* Reserved */ - buf[1] = 0; - /* Packet length - this includes the length of the header itself */ - buf[2] = (len >> 8) & 0xFF; - buf[3] = len & 0xFF; - } - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, const t38_data_field_t field[], int fields) -{ - int len; - int i; - int enclen; - int multiplier; - int data_field_no; - const t38_data_field_t *q; - unsigned int encoded_len; - unsigned int fragment_len; - unsigned int value; - uint8_t data_field_present; - uint8_t field_data_present; - char tag[20]; - - /* Build the IFP packet */ - len = 0; - if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT) - len = 4; - /*endif*/ - - /* There seems no valid reason why a packet would ever be generated without a data field present */ - data_field_present = (fields > 0) ? 0x80 : 0x00; - - /* Data field present */ - /* Data packet */ - /* Type of data */ - if (data_type <= T38_DATA_V17_14400) - { - buf[len++] = (uint8_t) (data_field_present | 0x40 | (data_type << 1)); - } - else if (s->t38_version != 0 && data_type <= T38_DATA_V33_14400) - { - buf[len++] = (uint8_t) (data_field_present | 0x60 | (((data_type - T38_DATA_V8) & 0xF) >> 2)); - buf[len++] = (uint8_t) (((data_type - T38_DATA_V8) << 6) & 0xFF); - } - else - { - return -1; - } - /*endif*/ - - if (data_field_present) - { - encoded_len = 0; - data_field_no = 0; - do - { - value = fields - encoded_len; - if (value < 0x80) - { - /* 1 octet case */ - buf[len++] = (uint8_t) value; - enclen = value; - } - else if (value < 0x4000) - { - /* 2 octet case */ - buf[len++] = (uint8_t) (0x80 | ((value >> 8) & 0xFF)); - buf[len++] = (uint8_t) (value & 0xFF); - enclen = value; - } - else - { - /* Fragmentation case */ - multiplier = (value/0x4000 < 4) ? value/0x4000 : 4; - buf[len++] = (uint8_t) (0xC0 | multiplier); - enclen = 0x4000*multiplier; - } - /*endif*/ - - fragment_len = enclen; - encoded_len += fragment_len; - /* Encode the elements */ - for (i = 0; i < (int) encoded_len; i++) - { - q = &field[data_field_no]; - field_data_present = (uint8_t) (q->field_len > 0); - /* Encode field_type */ - if (s->t38_version == 0) - { - /* Original version of T.38 with a typo */ - if (q->field_type > T38_FIELD_T4_NON_ECM_SIG_END) - return -1; - /*endif*/ - buf[len++] = (uint8_t) ((field_data_present << 7) | (q->field_type << 4)); - } - else - { - if (q->field_type <= T38_FIELD_T4_NON_ECM_SIG_END) - { - buf[len++] = (uint8_t) ((field_data_present << 7) | (q->field_type << 3)); - } - else if (q->field_type <= T38_FIELD_V34RATE) - { - buf[len++] = (uint8_t) ((field_data_present << 7) | 0x40 | ((q->field_type - T38_FIELD_CM_MESSAGE) >> 2)); - buf[len++] = (uint8_t) (((q->field_type - T38_FIELD_CM_MESSAGE) << 6) & 0xC0); - } - else - { - return -1; - } - /*endif*/ - } - /*endif*/ - /* Encode field_data */ - if (field_data_present) - { - if (q->field_len < 1 || q->field_len > 65535) - return -1; - /*endif*/ - buf[len++] = (uint8_t) (((q->field_len - 1) >> 8) & 0xFF); - buf[len++] = (uint8_t) ((q->field_len - 1) & 0xFF); - memcpy(&buf[len], q->field, q->field_len); - len += q->field_len; - } - /*endif*/ - data_field_no++; - } - /*endfor*/ - } - while ((int) encoded_len != fields || fragment_len >= 16384); - } - /*endif*/ - - for (data_field_no = 0; data_field_no < fields; data_field_no++) - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "Tx %5d: (%d) data %s/%s + %d byte(s)\n", - s->tx_seq_no, - data_field_no, - t38_data_type_to_str(data_type), - t38_field_type_to_str(field[data_field_no].field_type), - field[data_field_no].field_len); - } - /*endfor*/ - - if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT) - { - /* Fill in the TPKT header (see RFC1006) */ - /* Version */ - buf[0] = 3; - /* Reserved */ - buf[1] = 0; - /* Packet length - this includes the length of the header itself */ - buf[2] = (len >> 8) & 0xFF; - buf[3] = len & 0xFF; - } - /*endif*/ - - if (span_log_test(&s->logging, SPAN_LOG_FLOW)) - { - sprintf(tag, "Tx %5d: IFP", s->tx_seq_no); - span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len); - } - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_send_indicator(t38_core_state_t *s, int indicator) -{ - uint8_t buf[100]; - int len; - int delay; - int transmissions; - - delay = 0; - /* Only send an indicator if it represents a change of state. */ - /* If the 0x100 bit is set in indicator it will bypass this test, and force transmission */ - if (s->current_tx_indicator != indicator) - { - /* Zero is a valid count, to suppress the transmission of indicators when the - transport means they are not needed - e.g. TPKT/TCP. */ - transmissions = (indicator & 0x100) ? 1 : s->category_control[T38_PACKET_CATEGORY_INDICATOR]; - indicator &= 0xFF; - if (s->category_control[T38_PACKET_CATEGORY_INDICATOR]) - { - if ((len = t38_encode_indicator(s, buf, indicator)) < 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "T.38 indicator len is %d\n", len); - return len; - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: indicator %s\n", s->tx_seq_no, t38_indicator_to_str(indicator)); - if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, transmissions) < 0) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx packet handler failure\n"); - return -1; - } - /*endif*/ - s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; - if (s->pace_transmission) - { - delay = modem_startup_time[indicator].training; - if (s->allow_for_tep) - delay += modem_startup_time[indicator].tep; - /*endif*/ - } - /*endif*/ - } - /*endif*/ - s->current_tx_indicator = indicator; - } - /*endif*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_send_flags_delay(t38_core_state_t *s, int indicator) -{ - if (s->pace_transmission) - return modem_startup_time[indicator].flags; - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_send_training_delay(t38_core_state_t *s, int indicator) -{ - if (s->pace_transmission) - return modem_startup_time[indicator].training; - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_send_data(t38_core_state_t *s, int data_type, int field_type, const uint8_t field[], int field_len, int category) -{ - t38_data_field_t field0; - uint8_t buf[1000]; - int len; - - field0.field_type = field_type; - field0.field = field; - field0.field_len = field_len; - if ((len = t38_encode_data(s, buf, data_type, &field0, 1)) < 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len); - return len; - } - /*endif*/ - if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]) < 0) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx packet handler failure\n"); - return -1; - } - /*endif*/ - s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_type, const t38_data_field_t field[], int fields, int category) -{ - uint8_t buf[1000]; - int len; - - if ((len = t38_encode_data(s, buf, data_type, field, fields)) < 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len); - return len; - } - /*endif*/ - if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]) < 0) - { - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx packet handler failure\n"); - return -1; - } - /*endif*/ - s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_data_rate_management_method(t38_core_state_t *s, int method) -{ - s->data_rate_management_method = method; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_data_transport_protocol(t38_core_state_t *s, int data_transport_protocol) -{ - s->data_transport_protocol = data_transport_protocol; -} -/*- End of function --------------------------------------------------------*/ - -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, bool mmr_transcoding) -{ - s->mmr_transcoding = mmr_transcoding; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, bool jbig_transcoding) -{ - s->jbig_transcoding = jbig_transcoding; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_max_buffer_size(t38_core_state_t *s, int max_buffer_size) -{ - s->max_buffer_size = max_buffer_size; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_max_datagram_size(t38_core_state_t *s, int max_datagram_size) -{ - s->max_datagram_size = max_datagram_size; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_t38_version(t38_core_state_t *s, int t38_version) -{ - s->t38_version = t38_version; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, bool check) -{ - s->check_sequence_numbers = check; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_pace_transmission(t38_core_state_t *s, int pace_transmission) -{ - s->pace_transmission = pace_transmission; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, bool allow_for_tep) -{ - s->allow_for_tep = allow_for_tep; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_redundancy_control(t38_core_state_t *s, int category, int setting) -{ - s->category_control[category] = setting; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_set_fastest_image_data_rate(t38_core_state_t *s, int max_rate) -{ - s->fastest_image_data_rate = max_rate; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_get_fastest_image_data_rate(t38_core_state_t *s) -{ - return s->fastest_image_data_rate; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t38_core_get_logging_state(t38_core_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_restart(t38_core_state_t *s) -{ - /* Set the initial current receive states to something invalid, so the - first data received is seen as a change of state. */ - s->current_rx_indicator = -1; - s->current_rx_data_type = -1; - s->current_rx_field_type = -1; - - /* Set the initial current indicator state to something invalid, so the - first attempt to send an indicator will work. */ - s->current_tx_indicator = -1; - - /* We have no initial expectation of the received packet sequence number. - They most often start at 0 or 1 for a UDPTL transport, but random - starting numbers are possible. */ - s->rx_expected_seq_no = -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t38_core_state_t *) t38_core_init(t38_core_state_t *s, - t38_rx_indicator_handler_t rx_indicator_handler, - t38_rx_data_handler_t rx_data_handler, - t38_rx_missing_handler_t rx_missing_handler, - void *rx_user_data, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data) -{ - if (s == NULL) - { - if ((s = (t38_core_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "T.38"); - - /* Set some defaults for the parameters configurable from outside the - 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->max_buffer_size = 400; - s->max_datagram_size = 100; - s->t38_version = 0; - s->check_sequence_numbers = true; - s->pace_transmission = true; - - /* Set some defaults */ - s->category_control[T38_PACKET_CATEGORY_INDICATOR] = 1; - s->category_control[T38_PACKET_CATEGORY_CONTROL_DATA] = 1; - s->category_control[T38_PACKET_CATEGORY_CONTROL_DATA_END] = 1; - s->category_control[T38_PACKET_CATEGORY_IMAGE_DATA] = 1; - s->category_control[T38_PACKET_CATEGORY_IMAGE_DATA_END] = 1; - - s->rx_indicator_handler = rx_indicator_handler; - s->rx_data_handler = rx_data_handler; - s->rx_missing_handler = rx_missing_handler; - s->rx_user_data = rx_user_data; - s->tx_packet_handler = tx_packet_handler; - s->tx_packet_user_data = tx_packet_user_data; - - t38_core_restart(s); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_release(t38_core_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_core_free(t38_core_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c deleted file mode 100644 index 53c877e591..0000000000 --- a/libs/spandsp/src/t38_gateway.c +++ /dev/null @@ -1,2435 +0,0 @@ -//#define LOG_FAX_AUDIO -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_gateway.c - A T.38 gateway, less the packet exchange part - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2007, 2008 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 -#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 -#if defined(LOG_FAX_AUDIO) -#include -#endif -#include - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/queue.h" -#include "spandsp/vector_int.h" -#include "spandsp/dc_restore.h" -#include "spandsp/bit_operations.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/crc.h" -#include "spandsp/hdlc.h" -#include "spandsp/silence_gen.h" -#include "spandsp/fsk.h" -#include "spandsp/v29tx.h" -#include "spandsp/v29rx.h" -#include "spandsp/v27ter_tx.h" -#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" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/t30_fcf.h" -#include "spandsp/t35.h" -#include "spandsp/t30.h" -#include "spandsp/t30_logging.h" -#include "spandsp/fax_modems.h" -#include "spandsp/t38_core.h" -#include "spandsp/t38_non_ecm_buffer.h" -#include "spandsp/t38_gateway.h" - -#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" -#include "spandsp/private/v27ter_rx.h" -#include "spandsp/private/v29tx.h" -#include "spandsp/private/v29rx.h" -#include "spandsp/private/modem_connect_tones.h" -#include "spandsp/private/hdlc.h" -#include "spandsp/private/fax_modems.h" -#include "spandsp/private/timezone.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" -#include "spandsp/private/t30.h" -#include "spandsp/private/t38_core.h" -#include "spandsp/private/t38_non_ecm_buffer.h" -#include "spandsp/private/t38_gateway.h" - -/* This is the target time per transmission chunk. The actual - packet timing will sync to the data octets. */ -/*! The default number of milliseconds per transmitted IFP when sending bulk T.38 data */ -#define DEFAULT_MS_PER_TX_CHUNK 30 - -/*! The number of bytes which must be in the audio to T.38 HDLC buffer before we start - outputting them as IFP messages. */ -#define HDLC_START_BUFFER_LEVEL 8 - -/*! The number of transmissions of indicator IFP packets */ -#define INDICATOR_TX_COUNT 3 -/*! The number of transmissions of data IFP packets */ -#define DATA_TX_COUNT 1 -/*! The number of transmissions of terminating data IFP packets */ -#define DATA_END_TX_COUNT 3 - -/*! The number of consecutive flags to declare HDLC framing is OK. */ -#define HDLC_FRAMING_OK_THRESHOLD 5 - -#define HDLC_TRAMISSION_LAG_OCTETS 2 - -enum -{ - DISBIT1 = 0x01, - DISBIT2 = 0x02, - DISBIT3 = 0x04, - DISBIT4 = 0x08, - DISBIT5 = 0x10, - DISBIT6 = 0x20, - DISBIT7 = 0x40, - DISBIT8 = 0x80 -}; - -enum -{ - HDLC_FLAG_FINISHED = 0x01, - HDLC_FLAG_CORRUPT_CRC = 0x02, - HDLC_FLAG_PROCEED_WITH_OUTPUT = 0x04, - HDLC_FLAG_MISSING_DATA = 0x08 -}; - -enum -{ - FLAG_INDICATOR = 0x100, - FLAG_DATA = 0x200 -}; - -enum -{ - TIMED_MODE_STARTUP = 0, - TIMED_MODE_IDLE, - TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_ANNOUNCED, - TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_SEEN, - TIMED_MODE_TCF_PREDICTABLE_MODEM_START_PAST_V21_MODEM, - TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN, -}; - -static int restart_rx_modem(t38_gateway_state_t *s); -static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator); -static void hdlc_underflow_handler(void *user_data); -static void to_t38_buffer_init(t38_gateway_to_t38_state_t *s); -static void t38_hdlc_rx_put_bit(hdlc_rx_state_t *t, int new_bit); -static void non_ecm_put_bit(void *user_data, int bit); -static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit); -static void non_ecm_push_residue(t38_gateway_state_t *s); -static void tone_detected(void *user_data, int tone, int level, int delay); - -static void tone_detected(void *user_data, int tone, int level, int delay) -{ - t38_gateway_state_t *s; - - s = (t38_gateway_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level); -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_underflow_handler(void *user_data) -{ - t38_gateway_state_t *s; - t38_gateway_hdlc_state_t *t; - - s = (t38_gateway_state_t *) user_data; - t = &s->core.hdlc_to_modem; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC underflow at %d\n", t->out); - /* If the current HDLC buffer is not at the HDLC_FLAG_PROCEED_WITH_OUTPUT stage, this - underflow must be an end of preamble condition. */ - if ((t->buf[t->out].flags & HDLC_FLAG_PROCEED_WITH_OUTPUT)) - { - t->buf[t->out].len = 0; - t->buf[t->out].flags = 0; - t->buf[t->out].contents = 0; - if (++t->out >= T38_TX_HDLC_BUFS) - t->out = 0; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC next is 0x%X\n", t->buf[t->out].contents); - if ((t->buf[t->out].contents & FLAG_INDICATOR)) - { - /* The next thing in the queue is an indicator, so we need to stop this modem. */ - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC shutdown\n"); - hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0); - } - else if ((t->buf[t->out].contents & FLAG_DATA)) - { - /* Check if we should start sending the next frame */ - if ((t->buf[t->out].flags & HDLC_FLAG_PROCEED_WITH_OUTPUT)) - { - /* This frame is ready to go, and uses the same modem we are running now. So, send - whatever we have. This might or might not be an entire frame. */ - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC start next frame\n"); - hdlc_tx_frame(&s->audio.modems.hdlc_tx, t->buf[t->out].buf, t->buf[t->out].len); - if ((t->buf[t->out].flags & HDLC_FLAG_CORRUPT_CRC)) - hdlc_tx_corrupt_frame(&s->audio.modems.hdlc_tx); - /*endif*/ - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -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 short_train; - int use_hdlc; - - t = &s->audio.modems; - t38_non_ecm_buffer_report_output_status(&s->core.non_ecm_to_modem, &s->logging); - if (t->next_tx_handler) - { - /* There is a handler queued, so that is the next one. */ - fax_modems_set_tx_handler(t, t->next_tx_handler, t->next_tx_user_data); - fax_modems_set_next_tx_handler(t, NULL, NULL); - if (t->tx_handler == (span_tx_handler_t) &silence_gen - || - t->tx_handler == (span_tx_handler_t) &tone_gen) - { - fax_modems_set_rx_active(t, true); - } - else - { - fax_modems_set_rx_active(t, false); - } - /*endif*/ - return true; - } - /*endif*/ - u = &s->core.hdlc_to_modem; - if (u->in == u->out) - return false; - /*endif*/ - if ((u->buf[u->out].contents & FLAG_INDICATOR) == 0) - return false; - /*endif*/ - indicator = (u->buf[u->out].contents & 0xFF); - u->buf[u->out].len = 0; - u->buf[u->out].flags = 0; - u->buf[u->out].contents = 0; - if (++u->out >= T38_TX_HDLC_BUFS) - u->out = 0; - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Changing to %s\n", t38_indicator_to_str(indicator)); - 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); - fax_modems_set_get_bit(t, (get_bit_func_t) hdlc_tx_get_bit, &t->hdlc_tx); - 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; - } - /*endif*/ - switch (indicator) - { - case T38_IND_NO_SIGNAL: - t->tx_bit_rate = 0; - /* Impose 75ms minimum on transmitted silence */ - //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); - 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); - 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); - 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_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); - break; - case T38_IND_V27TER_2400_TRAINING: - case T38_IND_V27TER_4800_TRAINING: - 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, 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); - break; - case T38_IND_V29_7200_TRAINING: - case T38_IND_V29_9600_TRAINING: - 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, 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); - break; - case T38_IND_V17_7200_SHORT_TRAINING: - case T38_IND_V17_7200_LONG_TRAINING: - case T38_IND_V17_9600_SHORT_TRAINING: - case T38_IND_V17_9600_LONG_TRAINING: - case T38_IND_V17_12000_SHORT_TRAINING: - case T38_IND_V17_12000_LONG_TRAINING: - case T38_IND_V17_14400_SHORT_TRAINING: - case T38_IND_V17_14400_LONG_TRAINING: - short_train = false; - switch (indicator) - { - case T38_IND_V17_7200_SHORT_TRAINING: - short_train = true; - t->tx_bit_rate = 7200; - break; - case T38_IND_V17_7200_LONG_TRAINING: - t->tx_bit_rate = 7200; - break; - case T38_IND_V17_9600_SHORT_TRAINING: - short_train = true; - t->tx_bit_rate = 9600; - break; - case T38_IND_V17_9600_LONG_TRAINING: - t->tx_bit_rate = 9600; - break; - case T38_IND_V17_12000_SHORT_TRAINING: - short_train = true; - t->tx_bit_rate = 12000; - break; - case T38_IND_V17_12000_LONG_TRAINING: - t->tx_bit_rate = 12000; - break; - case T38_IND_V17_14400_SHORT_TRAINING: - short_train = true; - t->tx_bit_rate = 14400; - break; - case T38_IND_V17_14400_LONG_TRAINING: - t->tx_bit_rate = 14400; - break; - } - /*endswitch*/ - silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - 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); - break; - case T38_IND_V8_ANSAM: - t->tx_bit_rate = 300; - break; - case T38_IND_V8_SIGNAL: - t->tx_bit_rate = 300; - break; - case T38_IND_V34_CNTL_CHANNEL_1200: - t->tx_bit_rate = 1200; - break; - case T38_IND_V34_PRI_CHANNEL: - t->tx_bit_rate = 33600; - break; - case T38_IND_V34_CC_RETRAIN: - t->tx_bit_rate = 0; - break; - case T38_IND_V33_12000_TRAINING: - t->tx_bit_rate = 12000; - break; - case T38_IND_V33_14400_TRAINING: - t->tx_bit_rate = 14400; - break; - default: - break; - } - /*endswitch*/ - /* For any fast modem, set 200ms of preamble flags */ - if (t->tx_bit_rate > 300) - hdlc_tx_flags(&t->hdlc_tx, t->tx_bit_rate/(8*5)); - /*endif*/ - s->t38x.in_progress_rx_indicator = indicator; - return true; -} -/*- End of function --------------------------------------------------------*/ - -static void finalise_hdlc_frame(t38_gateway_state_t *s, int good_fcs) -{ - t38_gateway_hdlc_buf_t *hdlc_buf; - - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (!good_fcs || (hdlc_buf->flags & HDLC_FLAG_MISSING_DATA)) - hdlc_buf->flags |= HDLC_FLAG_CORRUPT_CRC; - /*endif*/ - if (s->core.hdlc_to_modem.in == s->core.hdlc_to_modem.out) - { - /* This is the frame in progress at the output. */ - if ((hdlc_buf->flags & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0) - { - /* Output of this frame has not yet begun. Throw it all out now. */ - hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf, hdlc_buf->len); - } - /*endif*/ - if ((hdlc_buf->flags & HDLC_FLAG_CORRUPT_CRC)) - hdlc_tx_corrupt_frame(&s->audio.modems.hdlc_tx); - /*endif*/ - } - /*endif*/ - hdlc_buf->flags |= (HDLC_FLAG_PROCEED_WITH_OUTPUT | HDLC_FLAG_FINISHED); - if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS) - s->core.hdlc_to_modem.in = 0; - /*endif*/ - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - hdlc_buf->len = 0; - hdlc_buf->flags = 0; - hdlc_buf->contents = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void edit_control_messages(t38_gateway_state_t *s, bool from_modem, uint8_t *buf, int len) -{ - /* Frames need to be fed to this routine byte by byte as they arrive. It basically just - edits the last byte received, based on the frame up to that point. */ - if (s->t38x.corrupt_current_frame[(from_modem) ? 1 : 0]) - { - /* We simply need to overwrite a section of the message, so it is not recognisable at - the receiver. This is used for the NSF, NSC, and NSS messages. Several strategies are - possible for the replacement data. If you have a manufacturer code of your own, the - sane thing is to overwrite the original data with that. */ - if (len <= s->t38x.suppress_nsx_len[(from_modem) ? 1 : 0]) - buf[len - 1] = s->t38x.suppress_nsx_string[(from_modem) ? 1 : 0][len - 1 - 3]; - /*endif*/ - return; - } - /*endif*/ - /* Edit the message, if we need to control the communication between the end points. */ - switch (len) - { - case 3: - switch (buf[2]) - { - case T30_NSF: - case T30_NSC: - case T30_NSS: - if (s->t38x.suppress_nsx_len[(from_modem) ? 1 : 0]) - { - /* Corrupt the message, so it will be ignored by the far end. If it were - 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) ? 1 : 0] = true; - } - /*endif*/ - break; - } - /*endswitch*/ - break; - case 4: - switch (buf[2]) - { - case T30_DIS: - /* Make sure the V.8 capability doesn't pass through. If it - did, two V.34 capable FAX machines might start some - V.8 re-negotiation. */ - buf[3] &= ~DISBIT6; - break; - } - /*endswitch*/ - break; - case 5: - switch (buf[2]) - { - case T30_DIS: - /* We may need to adjust the capabilities, so they do not exceed our own */ - span_log(&s->logging, SPAN_LOG_FLOW, "Applying fast modem type constraints.\n"); - switch (buf[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) - { - case 0: - case DISBIT4: - /* V.27ter only */ - break; - case DISBIT3: - case (DISBIT4 | DISBIT3): - /* V.27ter and V.29 */ - if (!(s->core.supported_modems & T30_SUPPORT_V29)) - buf[4] &= ~DISBIT3; - /*endif*/ - break; - case (DISBIT6 | DISBIT4 | DISBIT3): - /* V.27ter, V.29 and V.17 */ - if (!(s->core.supported_modems & T30_SUPPORT_V17)) - buf[4] &= ~DISBIT6; - /*endif*/ - if (!(s->core.supported_modems & T30_SUPPORT_V29)) - buf[4] &= ~DISBIT3; - /*endif*/ - break; - case (DISBIT5 | DISBIT4): - case (DISBIT6 | DISBIT4): - case (DISBIT6 | DISBIT5 | DISBIT4): - case (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3): - /* Reserved */ - buf[4] &= ~(DISBIT6 | DISBIT5); - buf[4] |= (DISBIT4 | DISBIT3); - break; - default: - /* Not used */ - buf[4] &= ~(DISBIT6 | DISBIT5); - buf[4] |= (DISBIT4 | DISBIT3); - break; - } - /*endswitch*/ - break; - } - /*endswitch*/ - break; - case 7: - switch (buf[2]) - { - case T30_DIS: - if (!s->core.ecm_allowed) - { - /* Do not allow ECM or T.6 coding */ - span_log(&s->logging, SPAN_LOG_FLOW, "Inhibiting ECM\n"); - buf[6] &= ~(DISBIT3 | DISBIT7); - } - /*endif*/ - break; - } - /*endswitch*/ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void monitor_control_messages(t38_gateway_state_t *s, - bool from_modem, - const uint8_t *buf, - int len) -{ - static const struct - { - int bit_rate; - int modem_type; - uint8_t dcs_code; - } modem_codes[] = - { - {14400, FAX_MODEM_V17_RX, (DISBIT6 )}, - {12000, FAX_MODEM_V17_RX, (DISBIT6 | DISBIT4 )}, - { 9600, FAX_MODEM_V17_RX, (DISBIT6 | DISBIT3)}, - { 9600, FAX_MODEM_V29_RX, ( DISBIT3)}, - { 7200, FAX_MODEM_V17_RX, (DISBIT6 | DISBIT4 | DISBIT3)}, - { 7200, FAX_MODEM_V29_RX, ( DISBIT4 | DISBIT3)}, - { 4800, FAX_MODEM_V27TER_RX, ( DISBIT4 )}, - { 2400, FAX_MODEM_V27TER_RX, (0 )}, - { 0, FAX_MODEM_NONE, (0 )} - }; - static const int minimum_scan_line_times[8] = - { - 20, 5, 10, 0, 40, 0, 0, 0 - }; - int dcs_code; - int i; - int j; - - /* Monitor the control messages, at the point where we have the whole message, so we can - see what is happening to things like training success/failure. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Monitoring %s\n", t30_frametype(buf[2])); - if (len < 3) - return; - /*endif*/ - s->core.timed_mode = TIMED_MODE_IDLE; - switch (buf[2]) - { - 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; - 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); - /*endif*/ - break; - 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; - break; - case T30_CTC: - if (len >= 5) - { - /* The table is short, and not searched often, so a brain-dead linear scan seems OK */ - dcs_code = buf[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3); - for (i = 0; modem_codes[i].bit_rate; i++) - { - if (modem_codes[i].dcs_code == dcs_code) - break; - /*endif*/ - } - /*endfor*/ - /* If we are processing a message from the modem side, the contents determine the fast - receive modem we are to use. If it comes from the T.38 side the contents do not. */ - s->core.fast_bit_rate = modem_codes[i].bit_rate; - if (from_modem) - s->core.fast_rx_modem = modem_codes[i].modem_type; - /*endif*/ - } - /*endif*/ - 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; - break; - case T30_DTC: - case T30_DCS: - case T30_DCS | 1: - /* We need to check which modem type is about to be used, so we can start the - 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; - if (from_modem) - s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN; - /*endif*/ - if (len >= 5) - { - /* The table is short, and not searched often, so a brain-dead linear scan seems OK */ - dcs_code = buf[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3); - for (i = 0; modem_codes[i].bit_rate; i++) - { - if (modem_codes[i].dcs_code == dcs_code) - break; - /*endif*/ - } - /*endfor*/ - /* If we are processing a DCS message from the modem side, the contents determine the fast - receive modem we are to use. If it comes from the T.38 side the contents do not. For a - DTC message this is reversed. */ - s->core.fast_bit_rate = modem_codes[i].bit_rate; - if ((buf[2] == T30_DTC && !from_modem) || (buf[2] != T30_DTC && from_modem)) - s->core.fast_rx_modem = modem_codes[i].modem_type; - /*endif*/ - } - /*endif*/ - if (len >= 6) - { - j = (buf[5] & (DISBIT7 | DISBIT6 | DISBIT5)) >> 4; - s->core.min_row_bits = (s->core.fast_bit_rate*minimum_scan_line_times[j])/1000; - } - else - { - s->core.min_row_bits = 0; - } - /*endif*/ - s->core.ecm_mode = (len >= 7) && (buf[6] & DISBIT3); - span_log(&s->logging, SPAN_LOG_FLOW, "Fast rx modem = %d/%d, ECM = %d, Min bits per row = %d\n", s->core.fast_rx_modem, s->core.fast_bit_rate, s->core.ecm_mode, s->core.min_row_bits); - break; - case T30_PPS: - case T30_PPS | 1: - switch (buf[3] & 0xFE) - { - case T30_EOP: - case T30_PRI_EOP: - case T30_EOM: - case T30_PRI_EOM: - case T30_EOS: -#if 0 - /* If we are hitting one of these conditions, it will take another DCS/DTC to select - 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; -#endif - /* Fall through */ - case T30_MPS: - case T30_PRI_MPS: - s->core.count_page_on_mcf = true; - break; - } - /*endswitch*/ - break; - case T30_EOP: - case T30_EOP | 1: - case T30_PRI_EOP: - case T30_PRI_EOP | 1: - case T30_EOM: - case T30_EOM | 1: - case T30_PRI_EOM: - case T30_PRI_EOM | 1: - case T30_EOS: - case T30_EOS | 1: -#if 0 - /* If we are hitting one of these conditions, it will take another DCS/DTC to select - 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; -#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; - break; - case T30_MCF: - case T30_MCF | 1: - if (s->core.count_page_on_mcf) - { - 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; - } - /*endif*/ - break; - default: - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void queue_missing_indicator(t38_gateway_state_t *s, int data_type) -{ - t38_core_state_t *t; - int expected; - int expected_alt; - - t = &s->t38x.t38; - expected = -1; - expected_alt = -1; - /* Missing packets might have lost us the indicator that should have put us in - the required mode of operation. It might be a bit late to fill in such a gap - now, but we should try. We may also want to force indicators into the queue, - such as when the data says 'end of signal'. */ - /* We have an expectation of whether long or short training should occur, but be - tolerant of either kind of indicator being present. */ - switch (data_type) - { - case T38_DATA_NONE: - expected = T38_IND_NO_SIGNAL; - break; - case T38_DATA_V21: - expected = T38_IND_V21_PREAMBLE; - break; - case T38_DATA_V27TER_2400: - expected = T38_IND_V27TER_2400_TRAINING; - break; - case T38_DATA_V27TER_4800: - expected = T38_IND_V27TER_4800_TRAINING; - break; - case T38_DATA_V29_7200: - expected = T38_IND_V29_7200_TRAINING; - break; - case T38_DATA_V29_9600: - expected = T38_IND_V29_9600_TRAINING; - break; - case T38_DATA_V17_7200: - expected = (s->core.short_train) ? T38_IND_V17_7200_SHORT_TRAINING : T38_IND_V17_7200_LONG_TRAINING; - expected_alt = (s->core.short_train) ? T38_IND_V17_7200_LONG_TRAINING : T38_IND_V17_7200_SHORT_TRAINING; - break; - case T38_DATA_V17_9600: - expected = (s->core.short_train) ? T38_IND_V17_9600_SHORT_TRAINING : T38_IND_V17_9600_LONG_TRAINING; - expected_alt = (s->core.short_train) ? T38_IND_V17_9600_LONG_TRAINING : T38_IND_V17_9600_SHORT_TRAINING; - break; - case T38_DATA_V17_12000: - expected = (s->core.short_train) ? T38_IND_V17_12000_SHORT_TRAINING : T38_IND_V17_12000_LONG_TRAINING; - expected_alt = (s->core.short_train) ? T38_IND_V17_12000_LONG_TRAINING : T38_IND_V17_12000_SHORT_TRAINING; - break; - case T38_DATA_V17_14400: - expected = (s->core.short_train) ? T38_IND_V17_14400_SHORT_TRAINING : T38_IND_V17_14400_LONG_TRAINING; - expected_alt = (s->core.short_train) ? T38_IND_V17_14400_LONG_TRAINING : T38_IND_V17_14400_SHORT_TRAINING; - break; - case T38_DATA_V8: - break; - case T38_DATA_V34_PRI_RATE: - break; - case T38_DATA_V34_CC_1200: - break; - case T38_DATA_V34_PRI_CH: - break; - case T38_DATA_V33_12000: - break; - case T38_DATA_V33_14400: - break; - } - /*endswitch*/ - if (expected < 0) - return; - /*endif*/ - if (t->current_rx_indicator == expected) - return; - /*endif*/ - if (expected_alt >= 0 && t->current_rx_indicator == expected_alt) - return; - /*endif*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "Queuing missing indicator - %s\n", - t38_indicator_to_str(expected)); - process_rx_indicator(t, (void *) s, expected); - /* Force the indicator setting here, as the core won't set in when its missing. */ - t->current_rx_indicator = expected; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_no, int expected_seq_no) -{ - t38_gateway_state_t *s; - - s = (t38_gateway_state_t *) user_data; - s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].flags |= HDLC_FLAG_MISSING_DATA; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator) -{ - t38_gateway_state_t *s; - t38_gateway_hdlc_state_t *u; - int immediate; - - s = (t38_gateway_state_t *) user_data; - - t38_non_ecm_buffer_report_input_status(&s->core.non_ecm_to_modem, &s->logging); - if (t->current_rx_indicator == indicator) - { - /* This is probably due to the far end repeating itself. Ignore it. Its harmless */ - return 0; - } - /*endif*/ - - u = &s->core.hdlc_to_modem; - immediate = (u->in == u->out); - if (u->buf[u->in].contents) - { - if (++u->in >= T38_TX_HDLC_BUFS) - u->in = 0; - /*endif*/ - } - /*endif*/ - u->buf[u->in].contents = (indicator | FLAG_INDICATOR); - if (++u->in >= T38_TX_HDLC_BUFS) - u->in = 0; - /*endif*/ - - if (immediate) - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "Changing - (%d) %s -> %s\n", - silence_gen_remainder(&s->audio.modems.silence_gen), - t38_indicator_to_str(t->current_rx_indicator), - t38_indicator_to_str(indicator)); - switch (s->t38x.current_rx_field_class) - { - case T38_FIELD_CLASS_NONE: - break; - case T38_FIELD_CLASS_HDLC: - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC shutdown\n"); - hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0); - break; - case T38_FIELD_CLASS_NON_ECM: - break; - } - } - else - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "Queued change - (%d) %s -> %s\n", - silence_gen_remainder(&s->audio.modems.silence_gen), - t38_indicator_to_str(t->current_rx_indicator), - t38_indicator_to_str(indicator)); - } - s->t38x.current_rx_field_class = T38_FIELD_CLASS_NONE; - /* We need to set this here, since we might have been called as a fake - indication when the real one was missing */ - t->current_rx_indicator = indicator; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void process_hdlc_data(t38_gateway_state_t *s, int data_type, const uint8_t *buf, int len) -{ - t38_gateway_hdlc_buf_t *hdlc_buf; - int i; - - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - /* Check if this data would overflow the buffer. */ - if (hdlc_buf->len + len > T38_MAX_HDLC_LEN) - { - s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].flags |= HDLC_FLAG_MISSING_DATA; - return; - } - /*endif*/ - hdlc_buf->contents = (data_type | FLAG_DATA); - bit_reverse(&hdlc_buf->buf[hdlc_buf->len], buf, len); - /* We need to send out the control messages as they are arriving. They are - too slow to capture a whole frame before starting to pass it on. - For the faster frames, take in the whole frame before sending it out. Also, there - is no need to monitor, or modify, the contents of the faster frames. */ - if (data_type == T38_DATA_V21) - { - for (i = 1; i <= len; i++) - edit_control_messages(s, 0, hdlc_buf->buf, hdlc_buf->len + i); - /*endfor*/ - /* Don't start pumping data into the actual output stream until there is - enough backlog to create some elasticity for jitter tolerance. */ - if (hdlc_buf->len + len >= HDLC_START_BUFFER_LEVEL) - { - if (s->core.hdlc_to_modem.in == s->core.hdlc_to_modem.out) - { - /* Output is not running, so kick it into life. */ - if ((hdlc_buf->flags & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0) - hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf, hdlc_buf->len + len); - else - hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf + hdlc_buf->len, len); - /*endif*/ - } - /*endif*/ - hdlc_buf->flags |= HDLC_FLAG_PROCEED_WITH_OUTPUT; - } - /*endif*/ - } - /*endif*/ - hdlc_buf->len += len; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len) -{ - t38_gateway_state_t *s; - t38_gateway_t38_state_t *xx; - t38_gateway_hdlc_buf_t *hdlc_buf; - - s = (t38_gateway_state_t *) user_data; - xx = &s->t38x; - /* There are a couple of special cases of data type that need their own treatment. */ - switch (data_type) - { - case T38_DATA_V8: - switch (field_type) - { - case T38_FIELD_CM_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_JM_MESSAGE: - if (len >= 2) - span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); - /*endif*/ - break; - case T38_FIELD_CI_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); - /*endif*/ - break; - default: - break; - } - /*endswitch*/ - return 0; - case T38_DATA_V34_PRI_RATE: - switch (field_type) - { - case T38_FIELD_V34RATE: - if (len >= 3) - { - xx->t38.v34_rate = t38_v34rate_to_bps(buf, len); - span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", xx->t38.v34_rate); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); - } - /*endif*/ - break; - default: - break; - } - /*endswitch*/ - return 0; - default: - break; - } - /*endswitch*/ - switch (field_type) - { - case T38_FIELD_HDLC_DATA: - xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - /* 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) - s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].flags |= HDLC_FLAG_MISSING_DATA; - /*endif*/ - } - /*endif*/ - if (len > 0) - process_hdlc_data(s, data_type, buf, len); - /*endif*/ - break; - case T38_FIELD_HDLC_FCS_OK: - xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(s, data_type, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (hdlc_buf->len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC OK\n", t30_frametype(hdlc_buf->buf[2])); - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - if (data_type == T38_DATA_V21) - { - if ((hdlc_buf->flags & HDLC_FLAG_MISSING_DATA) == 0) - { - monitor_control_messages(s, false, hdlc_buf->buf, hdlc_buf->len); - if (s->core.real_time_frame_handler) - s->core.real_time_frame_handler(s->core.real_time_frame_user_data, false, hdlc_buf->buf, hdlc_buf->len); - /*endif*/ - } - /*endif*/ - } - else - { - /* Make sure we go back to short training if CTC/CTR has kicked us into - long training. There has to be more than one value HDLC frame in a - chunk of image data, so just setting short training mode here should - be enough. */ - s->core.short_train = true; - } - /*endif*/ - hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, true); - } - else - { - /* Just restart using the current frame buffer */ - hdlc_buf->contents = 0; - } - /*endif*/ - xx->corrupt_current_frame[0] = false; - break; - case T38_FIELD_HDLC_FCS_BAD: - xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(s, data_type, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (hdlc_buf->len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad\n", t30_frametype(hdlc_buf->buf[2])); - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, false); - } - else - { - /* Just restart using the current frame buffer */ - hdlc_buf->contents = 0; - } - /*endif*/ - xx->corrupt_current_frame[0] = false; - break; - case T38_FIELD_HDLC_FCS_OK_SIG_END: - xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(s, data_type, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (hdlc_buf->len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC OK, sig end\n", t30_frametype(hdlc_buf->buf[2])); - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - if (data_type == T38_DATA_V21) - { - if ((hdlc_buf->flags & HDLC_FLAG_MISSING_DATA) == 0) - { - monitor_control_messages(s, false, hdlc_buf->buf, hdlc_buf->len); - if (s->core.real_time_frame_handler) - s->core.real_time_frame_handler(s->core.real_time_frame_user_data, false, hdlc_buf->buf, hdlc_buf->len); - /*endif*/ - } - /*endif*/ - } - else - { - /* Make sure we go back to short training if CTC/CTR has kicked us into - long training. There has to be more than one value HDLC frame in a - chunk of image data, so just setting short training mode here should - be enough. */ - s->core.short_train = true; - } - /*endif*/ - hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, true); - } - else - { - /* Just restart using the current frame buffer */ - hdlc_buf->contents = 0; - } - /*endif*/ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - queue_missing_indicator(s, T38_DATA_NONE); - xx->current_rx_field_class = T38_FIELD_CLASS_NONE; - } - /*endif*/ - xx->corrupt_current_frame[0] = false; - break; - case T38_FIELD_HDLC_FCS_BAD_SIG_END: - xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(s, data_type, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (hdlc_buf->len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad, sig end\n", t30_frametype(hdlc_buf->buf[2])); - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, false); - } - else - { - /* Just restart using the current frame buffer */ - hdlc_buf->contents = 0; - } - /*endif*/ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - queue_missing_indicator(s, T38_DATA_NONE); - xx->current_rx_field_class = T38_FIELD_CLASS_NONE; - } - /*endif*/ - xx->corrupt_current_frame[0] = false; - break; - case T38_FIELD_HDLC_SIG_END: - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_SIG_END!\n"); - /* The sender has incorrectly included data in this message, but there seems nothing meaningful - it could be. There could not be an FCS good/bad report beyond this. */ - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - /* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send this message at the - end of non-ECM data. We need to tolerate this. */ - if (xx->current_rx_field_class == T38_FIELD_CLASS_NON_ECM) - { - span_log(&s->logging, SPAN_LOG_WARNING, "T38_FIELD_HDLC_SIG_END received at the end of non-ECM data!\n"); - /* Don't flow control the data any more. Just pump out the remainder as fast as we can. */ - t38_non_ecm_buffer_push(&s->core.non_ecm_to_modem); - } - else - { - /* This message is expected under 2 circumstances. One is as an alternative to T38_FIELD_HDLC_FCS_OK_SIG_END - - i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops. - The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. In - this case we just clear out any partial frame data that might be in the buffer. */ - /* TODO: what if any junk in the buffer has reached the HDLC_FLAG_PROCEED_WITH_OUTPUT stage? */ - hdlc_buf->len = 0; - hdlc_buf->flags = 0; - hdlc_buf->contents = 0; - } - /*endif*/ - queue_missing_indicator(s, T38_DATA_NONE); - xx->current_rx_field_class = T38_FIELD_CLASS_NONE; - } - /*endif*/ - xx->corrupt_current_frame[0] = false; - break; - case T38_FIELD_T4_NON_ECM_DATA: - if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) - t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); - xx->current_rx_field_class = T38_FIELD_CLASS_NON_ECM; - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - queue_missing_indicator(s, data_type); - /*endif*/ - if (len > 0) - t38_non_ecm_buffer_inject(&s->core.non_ecm_to_modem, buf, len); - /*endif*/ - 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) - t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - /* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - /* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send HDLC signal end where - they should send non-ECM signal end. It is possible they also do the opposite. - We need to tolerate this. */ - if (xx->current_rx_field_class == T38_FIELD_CLASS_NON_ECM) - { - if (len > 0) - { - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - t38_non_ecm_buffer_inject(&s->core.non_ecm_to_modem, buf, len); - } - /*endif*/ - if (hdlc_buf->contents != (data_type | FLAG_DATA)) - queue_missing_indicator(s, data_type); - /*endif*/ - /* Don't flow control the data any more. Just pump out the remainder as fast as we can. */ - t38_non_ecm_buffer_push(&s->core.non_ecm_to_modem); - } - else - { - span_log(&s->logging, SPAN_LOG_WARNING, "T38_FIELD_NON_ECM_SIG_END received at the end of HDLC data!\n"); - if (s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents != (data_type | FLAG_DATA)) - { - queue_missing_indicator(s, data_type); - hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; - } - /*endif*/ - /* TODO: what if any junk in the buffer has reached the HDLC_FLAG_PROCEED_WITH_OUTPUT stage? */ - hdlc_buf->len = 0; - hdlc_buf->flags = 0; - hdlc_buf->contents = 0; - } - /*endif*/ - queue_missing_indicator(s, T38_DATA_NONE); - xx->current_rx_field_class = T38_FIELD_CLASS_NONE; - } - /*endif*/ - xx->corrupt_current_frame[0] = false; - break; - default: - break; - } - /*endswitch*/ - -#if 0 - if (span_log_test(&s->logging, SPAN_LOG_FLOW)) - { - int i; - - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Data: "); - for (i = 0; i < len; i++) - span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " %02X", buf[i]); - /*endfor*/ - } - /*endif*/ - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "\n"); -#endif - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void set_octets_per_data_packet(t38_gateway_state_t *s, int bit_rate) -{ - int octets; - - octets = s->core.ms_per_tx_chunk*bit_rate/(8*1000); - if (octets < 1) - octets = 1; - /*endif*/ - s->core.to_t38.octets_per_data_packet = octets; -} -/*- End of function --------------------------------------------------------*/ - -static int set_slow_packetisation(t38_gateway_state_t *s) -{ - set_octets_per_data_packet(s, 300); - s->t38x.current_tx_data_type = T38_DATA_V21; - return T38_IND_V21_PREAMBLE; -} -/*- End of function --------------------------------------------------------*/ - -static int set_fast_packetisation(t38_gateway_state_t *s) -{ - int ind; - - ind = T38_IND_NO_SIGNAL; - switch (s->core.fast_rx_active) - { - case FAX_MODEM_V17_RX: - set_octets_per_data_packet(s, s->core.fast_bit_rate); - switch (s->core.fast_bit_rate) - { - case 7200: - ind = (s->core.short_train) ? T38_IND_V17_7200_SHORT_TRAINING : T38_IND_V17_7200_LONG_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V17_7200; - break; - case 9600: - ind = (s->core.short_train) ? T38_IND_V17_9600_SHORT_TRAINING : T38_IND_V17_9600_LONG_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V17_9600; - break; - case 12000: - ind = (s->core.short_train) ? T38_IND_V17_12000_SHORT_TRAINING : T38_IND_V17_12000_LONG_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V17_12000; - break; - default: - case 14400: - ind = (s->core.short_train) ? T38_IND_V17_14400_SHORT_TRAINING : T38_IND_V17_14400_LONG_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V17_14400; - break; - } - /*endswitch*/ - break; - case FAX_MODEM_V27TER_RX: - set_octets_per_data_packet(s, s->core.fast_bit_rate); - switch (s->core.fast_bit_rate) - { - case 2400: - ind = T38_IND_V27TER_2400_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V27TER_2400; - break; - default: - case 4800: - ind = T38_IND_V27TER_4800_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V27TER_4800; - break; - } - /*endswitch*/ - break; - case FAX_MODEM_V29_RX: - set_octets_per_data_packet(s, s->core.fast_bit_rate); - switch (s->core.fast_bit_rate) - { - case 7200: - ind = T38_IND_V29_7200_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V29_7200; - break; - default: - case 9600: - ind = T38_IND_V29_9600_TRAINING; - s->t38x.current_tx_data_type = T38_DATA_V29_9600; - break; - } - /*endswitch*/ - break; - } - /*endswitch*/ - return ind; -} -/*- End of function --------------------------------------------------------*/ - -static void announce_training(t38_gateway_state_t *s) -{ - t38_core_send_indicator(&s->t38x.t38, set_fast_packetisation(s)); -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_rx_status(void *user_data, int status) -{ - t38_gateway_state_t *s; - - s = (t38_gateway_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM signal status is %s (%d)\n", signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_TRAINING_IN_PROGRESS: - if (s->core.timed_mode == TIMED_MODE_IDLE) - { - announce_training(s); - } - else - { - if (s->core.timed_mode == TIMED_MODE_TCF_PREDICTABLE_MODEM_START_PAST_V21_MODEM) - s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_SEEN; - else - s->core.samples_to_timeout = ms_to_samples(500); - /*endif*/ - set_fast_packetisation(s); - } - /*endif*/ - break; - case SIG_STATUS_TRAINING_FAILED: - 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.timed_mode = TIMED_MODE_IDLE; - s->core.samples_to_timeout = 0; - s->core.short_train = true; - to_t38_buffer_init(&s->core.to_t38); - break; - case SIG_STATUS_CARRIER_UP: - break; - case SIG_STATUS_CARRIER_DOWN: - switch (s->t38x.current_tx_data_type) - { - case T38_DATA_V17_7200: - case T38_DATA_V17_9600: - case T38_DATA_V17_12000: - case T38_DATA_V17_14400: - case T38_DATA_V27TER_2400: - case T38_DATA_V27TER_4800: - case T38_DATA_V29_7200: - case T38_DATA_V29_9600: - if (s->core.timed_mode != TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_ANNOUNCED) - { - /* TODO: If the carrier really did fall for good during the 500ms TEP blocking timeout, we - won't declare the no-signal condition. */ - non_ecm_push_residue(s); - t38_core_send_indicator(&s->t38x.t38, T38_IND_NO_SIGNAL); - } - /*endif*/ - restart_rx_modem(s); - break; - } - /*endswitch*/ - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected non-ECM special bit - %d!\n", status); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void to_t38_buffer_init(t38_gateway_to_t38_state_t *s) -{ - s->data_ptr = 0; - s->bit_stream = 0xFFFF; - s->bit_no = 0; - - s->in_bits = 0; - s->out_octets = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_push_residue(t38_gateway_state_t *t) -{ - t38_gateway_to_t38_state_t *s; - - s = &t->core.to_t38; - if (s->bit_no) - { - /* There is a fractional octet in progress. We might as well send every last bit we can. */ - s->data[s->data_ptr++] = (uint8_t) (s->bit_stream << (8 - s->bit_no)); - } - /*endif*/ - if (t38_core_send_data(&t->t38x.t38, t->t38x.current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, s->data, s->data_ptr, T38_PACKET_CATEGORY_IMAGE_DATA_END) < 0) - span_log(&t->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - s->in_bits += s->bits_absorbed; - s->out_octets += s->data_ptr; - s->data_ptr = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_push(t38_gateway_state_t *t) -{ - t38_gateway_to_t38_state_t *s; - - s = &t->core.to_t38; - if (s->data_ptr) - { - if (t38_core_send_data(&t->t38x.t38, t->t38x.current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, s->data, s->data_ptr, T38_PACKET_CATEGORY_IMAGE_DATA) < 0) - span_log(&t->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - s->in_bits += s->bits_absorbed; - s->out_octets += s->data_ptr; - s->bits_absorbed = 0; - s->data_ptr = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_put_bit(void *user_data, int bit) -{ - t38_gateway_state_t *t; - t38_gateway_to_t38_state_t *s; - - if (bit < 0) - { - non_ecm_rx_status(user_data, bit); - return; - } - /*endif*/ - t = (t38_gateway_state_t *) user_data; - s = &t->core.to_t38; - - s->in_bits++; - bit &= 1; - s->bit_stream = (s->bit_stream << 1) | bit; - if (++s->bit_no >= 8) - { - s->data[s->data_ptr++] = (uint8_t) s->bit_stream & 0xFF; - if (s->data_ptr >= s->octets_per_data_packet) - non_ecm_push(t); - /*endif*/ - s->bit_no = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit) -{ - t38_gateway_state_t *t; - t38_gateway_to_t38_state_t *s; - - if (bit < 0) - { - non_ecm_rx_status(user_data, bit); - return; - } - /*endif*/ - t = (t38_gateway_state_t *) user_data; - s = &t->core.to_t38; - - s->bits_absorbed++; - bit &= 1; - /* Drop any extra zero bits when we already have enough for an EOL symbol. */ - /* The snag here is that if we just look for 11 bits, a line ending with - a code that has trailing zero bits will cause problems. The longest run of - trailing zeros for any code is 3, so we need to look for at least 14 zeros - if we don't want to actually analyse the compressed data in depth. This means - we do not strip every fill bit, but we strip most of them. */ - if ((s->bit_stream & 0x3FFF) == 0 && bit == 0) - { - if (s->bits_absorbed > 2*8*s->octets_per_data_packet) - { - /* We need to pump out what we have, even though we have not accumulated a full - buffer of data. If we don't, we stand to delay rows excessively, so the far - end gateway (assuming the far end is a gateway) cannot play them out. */ - non_ecm_push(t); - } - /*endif*/ - return; - } - /*endif*/ - s->bit_stream = (s->bit_stream << 1) | bit; - if (++s->bit_no >= 8) - { - s->data[s->data_ptr++] = (uint8_t) s->bit_stream & 0xFF; - if (s->data_ptr >= s->octets_per_data_packet) - non_ecm_push(t); - /*endif*/ - s->bit_no = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_rx_status(hdlc_rx_state_t *t, int status) -{ - t38_gateway_state_t *s; - int category; - - s = (t38_gateway_state_t *) t->frame_user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC signal status is %s (%d)\n", signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_TRAINING_IN_PROGRESS: - announce_training(s); - break; - case SIG_STATUS_TRAINING_FAILED: - 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; - /* Behave like HDLC preamble has been announced. */ - t->framing_ok_announced = true; - to_t38_buffer_init(&s->core.to_t38); - break; - case SIG_STATUS_CARRIER_UP: - /* Reset the HDLC receiver. */ - t->raw_bit_stream = 0; - t->len = 0; - t->num_bits = 0; - t->flags_seen = 0; - t->framing_ok_announced = false; - to_t38_buffer_init(&s->core.to_t38); - break; - case SIG_STATUS_CARRIER_DOWN: - if (t->framing_ok_announced) - { - category = (s->t38x.current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA_END : T38_PACKET_CATEGORY_IMAGE_DATA_END; - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_SIG_END, NULL, 0, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - t38_core_send_indicator(&s->t38x.t38, T38_IND_NO_SIGNAL); - t->framing_ok_announced = false; - } - /*endif*/ - restart_rx_modem(s); - if (s->core.timed_mode == TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN) - { - /* If we are doing TCF, we need to announce the fast carrier training very - quickly, to ensure it starts 75+-20ms after the HDLC carrier ends. Waiting until - it trains will be too late. We need to announce the fast modem a fixed time after - the end of the V.21 carrier, in anticipation of its arrival. If we announce it, - and it doesn't arrive, we will worry about that later. */ - s->core.samples_to_timeout = ms_to_samples(75); - s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_PAST_V21_MODEM; - } - /*endif*/ - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected HDLC special bit - %d!\n", status); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void rx_flag_or_abort(hdlc_rx_state_t *t) -{ - t38_gateway_state_t *s; - t38_gateway_to_t38_state_t *u; - int category; - - s = (t38_gateway_state_t *) t->frame_user_data; - u = &s->core.to_t38; - if ((t->raw_bit_stream & 0x01)) - { - /* Hit HDLC abort */ - t->rx_aborts++; - if (t->flags_seen < t->framing_ok_threshold) - t->flags_seen = 0; - else - t->flags_seen = t->framing_ok_threshold - 1; - /*endif*/ - if (t->len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame aborted at %d\n", t->len); - /* If we have sent some of this frame we need to treat the abort as though it is a CRC error, - as reporting a bad CRC is the only way T.38 allows us to scrub a frame in progress. */ - /* It seems some boxes may not like us sending a _SIG_END here, and then another - when the carrier actually drops. Lets just send T38_FIELD_HDLC_FCS_OK here. */ - if (t->len > 2) - { - category = (s->t38x.current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_FCS_BAD, NULL, 0, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - } - /*endif*/ - } - /*endif*/ - } - else - { - /* Hit HDLC flag */ - if (t->flags_seen >= t->framing_ok_threshold) - { - category = (s->t38x.current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if (t->len) - { - /* This is not back-to-back flags */ - if (t->len >= 2) - { - if (u->data_ptr) - { - bit_reverse(u->data, t->buffer + t->len - 2 - u->data_ptr, u->data_ptr); - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_DATA, u->data, u->data_ptr, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - } - /*endif*/ - if (t->num_bits != 7) - { - t->rx_crc_errors++; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s, misaligned terminating flag at %d\n", t30_frametype(t->buffer[2]), t->len); - /* It seems some boxes may not like us sending a _SIG_END here, and then another - when the carrier actually drops. Lets just send T38_FIELD_HDLC_FCS_OK here. */ - if (t->len > 2) - { - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_FCS_BAD, NULL, 0, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - } - /*endif*/ - } - else if ((u->crc & 0xFFFF) != 0xF0B8) - { - t->rx_crc_errors++; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s, bad CRC at %d\n", t30_frametype(t->buffer[2]), t->len); - /* It seems some boxes may not like us sending a _SIG_END here, and then another - when the carrier actually drops. Lets just send T38_FIELD_HDLC_FCS_OK here. */ - if (t->len > 2) - { - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_FCS_BAD, NULL, 0, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - } - /*endif*/ - } - else - { - t->rx_frames++; - t->rx_bytes += t->len - 2; - 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); - if (s->core.real_time_frame_handler) - s->core.real_time_frame_handler(s->core.real_time_frame_user_data, true, t->buffer, t->len - 2); - /*endif*/ - } - else - { - /* 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; - } - /*endif*/ - /* It seems some boxes may not like us sending a _SIG_END here, and then another - when the carrier actually drops. Lets just send T38_FIELD_HDLC_FCS_OK here. */ - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_FCS_OK, NULL, 0, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - } - /*endif*/ - } - else - { - /* Frame too short */ - t->rx_length_errors++; - } - /*endif*/ - } - /*endif*/ - } - else - { - /* Check the flags are back-to-back when testing for valid preamble. This - greatly reduces the chances of false preamble detection, and anything - which doesn't send them back-to-back is badly broken. When we are one - flag away from OK we should not apply the back-to-back consition, as - between an abort and the following start of frame things might not be - octet aligned. */ - if (t->flags_seen != t->framing_ok_threshold - 1 && t->num_bits != 7) - t->flags_seen = 0; - /*endif*/ - if (++t->flags_seen >= t->framing_ok_threshold && !t->framing_ok_announced) - { - 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; - } - /*endif*/ - if (s->t38x.in_progress_rx_indicator == T38_IND_CNG) - set_next_tx_type(s); - /*endif*/ - t->framing_ok_announced = true; - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ - t->len = 0; - t->num_bits = 0; - u->crc = 0xFFFF; - u->data_ptr = 0; - s->t38x.corrupt_current_frame[1] = false; -} -/*- End of function --------------------------------------------------------*/ - -static void t38_hdlc_rx_put_bit(hdlc_rx_state_t *t, int new_bit) -{ - t38_gateway_state_t *s; - t38_gateway_to_t38_state_t *u; - int category; - - if (new_bit < 0) - { - hdlc_rx_status(t, new_bit); - return; - } - /*endif*/ - t->raw_bit_stream = (t->raw_bit_stream << 1) | (new_bit & 1); - if ((t->raw_bit_stream & 0x3E) == 0x3E) - { - /* There are at least 5 ones in a row. We could be at a: - - point where stuffing occurs - - a flag - - an abort - - the result of bit errors */ - /* Is this a bit to be skipped for destuffing? */ - if ((t->raw_bit_stream & 0x41) == 0) - return; - /*endif*/ - /* Is this a flag or abort? */ - if ((t->raw_bit_stream & 0xFE) == 0x7E) - { - rx_flag_or_abort(t); - return; - } - /*endif*/ - } - /*endif*/ - t->num_bits++; - if (t->flags_seen < t->framing_ok_threshold) - return; - /*endif*/ - t->byte_in_progress = (t->byte_in_progress >> 1) | ((t->raw_bit_stream & 0x01) << 7); - if (t->num_bits != 8) - return; - /*endif*/ - t->num_bits = 0; - s = (t38_gateway_state_t *) t->frame_user_data; - u = &s->core.to_t38; - if (t->len >= (int) sizeof(t->buffer)) - { - /* This is too long. Abandon the frame, and wait for the next flag octet. */ - if ((t->len + HDLC_TRAMISSION_LAG_OCTETS) >= u->octets_per_data_packet) - { - /* We will have sent some of this frame already, so we need to send termination of this bad HDLC frame. */ - category = (s->t38x.current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_FCS_BAD, NULL, 0, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - } - /*endif*/ - t->rx_length_errors++; - t->flags_seen = t->framing_ok_threshold - 1; - t->len = 0; - return; - } - /*endif*/ - t->buffer[t->len] = (uint8_t) t->byte_in_progress; - if (t->len == 1) - { - /* All valid HDLC frames in FAX communication begin 0xFF 0x03 or 0xFF 0x13. - Anything else is bogus. */ - if (t->buffer[0] != 0xFF || (t->buffer[1] & 0xEF) != 0x03) - { - /* Abandon the frame, and wait for the next flag octet. */ - /* If this is a real frame, where one of these first two octets has a bit - error, we will fail to forward the frame with a CRC error, as we do for - other bad frames. This will affect the timing of what goes forward. - Hopefully such timing changes will have less frequent bad effects than - the consequences of a bad bit stream simulating an HDLC frame start. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Bad HDLC frame header. Abandoning frame.\n"); - t->flags_seen = t->framing_ok_threshold - 1; - t->len = 0; - return; - } - /*endif*/ - } - /*endif*/ - /* Calculate the CRC progressively, before we start altering the frame */ - u->crc = crc_itu16_calc(&t->buffer[t->len], 1, u->crc); - /* Make the transmission lag by two octets, so we do not send the CRC, and - do not report the CRC result too late. */ - if (++t->len <= HDLC_TRAMISSION_LAG_OCTETS) - return; - /*endif*/ - if (s->t38x.current_tx_data_type == T38_DATA_V21) - { - /* The V.21 control messages need to be monitored, and possibly corrupted, to manage the - man-in-the-middle role of T.38 */ - edit_control_messages(s, 1, t->buffer, t->len); - } - if (++u->data_ptr >= u->octets_per_data_packet) - { - bit_reverse(u->data, &t->buffer[t->len - HDLC_TRAMISSION_LAG_OCTETS - u->data_ptr], u->data_ptr); - category = (s->t38x.current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if (t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_DATA, u->data, u->data_ptr, category) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "T.38 send failed\n"); - /*endif*/ - /* Since we delay transmission by 2 octets, we should now have sent the last of the data octets when - we have just received the last of the CRC octets. */ - u->data_ptr = 0; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int restart_rx_modem(t38_gateway_state_t *s) -{ - fax_modems_state_t *t; - - if (s->core.to_t38.in_bits || s->core.to_t38.out_octets) - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "%d incoming audio bits. %d outgoing T.38 octets\n", - s->core.to_t38.in_bits, - s->core.to_t38.out_octets); - s->core.to_t38.in_bits = 0; - s->core.to_t38.out_octets = 0; - } - /*endif*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "Restart rx modem - modem = %d, short train = %d, ECM = %d\n", - s->core.fast_rx_modem, - s->core.short_train, - s->core.ecm_mode); - - t = &s->audio.modems; - 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); - fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) t38_hdlc_rx_put_bit, &t->hdlc_rx); - hdlc_rx_init(&t->hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, NULL, s); -#if 0 - fsk_rx_signal_cutoff(&t->v21_rx, -39.09f); -#endif - if (s->core.image_data_mode && s->core.ecm_mode) - { - fax_modems_set_put_bit(t, (put_bit_func_t) t38_hdlc_rx_put_bit, &t->hdlc_rx); - } - else - { - if (s->core.image_data_mode && s->core.to_t38.fill_bit_removal) - fax_modems_set_put_bit(t, (put_bit_func_t) non_ecm_remove_fill_and_put_bit, s); - else - fax_modems_set_put_bit(t, (put_bit_func_t) non_ecm_put_bit, s); - /*endif*/ - } - /*endif*/ - to_t38_buffer_init(&s->core.to_t38); - s->core.to_t38.octets_per_data_packet = 1; - 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); - s->core.fast_rx_active = s->core.fast_rx_modem; - break; - case FAX_MODEM_V21_RX: - default: - //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); - s->core.fast_rx_active = FAX_MODEM_NONE; - break; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void update_rx_timing(t38_gateway_state_t *s, int len) -{ - if (s->core.samples_to_timeout > 0) - { - if ((s->core.samples_to_timeout -= len) <= 0) - { - switch (s->core.timed_mode) - { - case TIMED_MODE_TCF_PREDICTABLE_MODEM_START_PAST_V21_MODEM: - /* Timed announcement of training, 75ms after the DCS carrier fell. */ - announce_training(s); - s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_ANNOUNCED; - break; - case TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_SEEN: - /* Timed announcement of training, 75ms after the DCS carrier fell. */ - announce_training(s); - /* Use a timeout to ride over TEP, if it is present */ - s->core.samples_to_timeout = ms_to_samples(500); - s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_ANNOUNCED; - break; - case TIMED_MODE_TCF_PREDICTABLE_MODEM_START_FAST_MODEM_ANNOUNCED: - s->core.timed_mode = TIMED_MODE_IDLE; - span_log(&s->logging, SPAN_LOG_FLOW, "TEP jamming expired\n"); - break; - case TIMED_MODE_STARTUP: - /* Ensure a no-signal condition goes out the moment the received audio starts */ - t38_core_send_indicator(&s->t38x.t38, T38_IND_NO_SIGNAL); - s->core.timed_mode = TIMED_MODE_IDLE; - break; - } - /*endswitch*/ - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len) -{ - int i; - -#if defined(LOG_FAX_AUDIO) - if (s->audio.modems.audio_rx_log >= 0) - write(s->audio.modems.audio_rx_log, amp, len*sizeof(int16_t)); - /*endif*/ -#endif - update_rx_timing(s, len); - for (i = 0; i < len; i++) - amp[i] = dc_restore(&s->audio.modems.dc_restore, amp[i]); - /*endfor*/ - if (s->audio.modems.rx_handler) - s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len) -{ - /* To mitigate the effect of lost packets on a packet network we should - try to sustain the status quo. If there is no receive modem running, keep - things that way. If there is a receive modem running, try to sustain its - operation, without causing a phase hop, or letting its adaptive functions - diverge. */ -#if defined(LOG_FAX_AUDIO) - if (s->audio.modems.audio_rx_log >= 0) - { - int i; -#if defined(_MSC_VER) - int16_t *amp = (int16_t *) _alloca(sizeof(int16_t)*len); -#else - int16_t amp[len]; -#endif - - vec_zeroi16(amp, len); - write(s->audio.modems.audio_rx_log, amp, len*sizeof(int16_t)); - } -#endif - update_rx_timing(s, len); - /* TODO: handle the modems properly */ - s->audio.modems.rx_fillin_handler(s->audio.modems.rx_fillin_user_data, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len) -{ - int len; -#if defined(LOG_FAX_AUDIO) - int required_len; - - required_len = max_len; -#endif - 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, &[len], max_len - len); - if (len < max_len) - { - silence_gen_set(&s->audio.modems.silence_gen, 0); - set_next_tx_type(s); - } - /*endif*/ - } - /*endif*/ - } - /*endif*/ - if (s->audio.modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - vec_zeroi16(&[len], max_len - len); - len = max_len; - } - /*endif*/ -#if defined(LOG_FAX_AUDIO) - if (s->audio.modems.audio_tx_log >= 0) - { - if (len < required_len) - vec_zeroi16(&[len], required_len - len); - /*endif*/ - write(s->audio.modems.audio_tx_log, amp, required_len*sizeof(int16_t)); - } - /*endif*/ -#endif - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_gateway_get_transfer_statistics(t38_gateway_state_t *s, t38_stats_t *t) -{ - memset(t, 0, sizeof(*t)); - t->bit_rate = s->core.fast_bit_rate; - t->error_correcting_mode = s->core.ecm_mode; - t->pages_transferred = s->core.pages_confirmed; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t38_core_state_t *) t38_gateway_get_t38_core_state(t38_gateway_state_t *s) -{ - return &s->t38x.t38; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t38_gateway_get_logging_state(t38_gateway_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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, bool transmit_on_idle) -{ - s->audio.modems.transmit_on_idle = transmit_on_idle; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_gateway_set_supported_modems(t38_gateway_state_t *s, int supported_modems) -{ - s->core.supported_modems = supported_modems; - if ((s->core.supported_modems & T30_SUPPORT_V17)) - t38_set_fastest_image_data_rate(&s->t38x.t38, 14400); - else if ((s->core.supported_modems & T30_SUPPORT_V29)) - t38_set_fastest_image_data_rate(&s->t38x.t38, 9600); - else - t38_set_fastest_image_data_rate(&s->t38x.t38, 4800); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_gateway_set_nsx_suppression(t38_gateway_state_t *s, - const uint8_t *from_t38, - int from_t38_len, - const uint8_t *from_modem, - int from_modem_len) -{ - if (from_t38_len >= 0) - s->t38x.suppress_nsx_len[0] = ((from_t38_len < MAX_NSX_SUPPRESSION) ? from_t38_len : MAX_NSX_SUPPRESSION) + 3; - if (from_t38) - memcpy(s->t38x.suppress_nsx_string[0], from_t38, s->t38x.suppress_nsx_len[0]); - if (from_modem_len >= 0) - s->t38x.suppress_nsx_len[1] = ((from_modem_len < MAX_NSX_SUPPRESSION) ? from_modem_len : MAX_NSX_SUPPRESSION) + 3; - if (from_modem) - memcpy(s->t38x.suppress_nsx_string[1], from_modem, s->t38x.suppress_nsx_len[1]); -} -/*- End of function --------------------------------------------------------*/ - -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, bool remove) -{ - s->core.to_t38.fill_bit_removal = remove; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_gateway_set_real_time_frame_handler(t38_gateway_state_t *s, - t38_gateway_real_time_frame_handler_t handler, - void *user_data) -{ - s->core.real_time_frame_handler = handler; - s->core.real_time_frame_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_gateway_audio_init(t38_gateway_state_t *s) -{ - fax_modems_init(&s->audio.modems, - false, - NULL, - hdlc_underflow_handler, - non_ecm_put_bit, - t38_non_ecm_buffer_get_bit, - tone_detected, - 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); - 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. */ - fsk_rx_signal_cutoff(&s->audio.modems.v21_rx, -30.0f); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_gateway_t38_init(t38_gateway_state_t *t, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data) -{ - t38_gateway_t38_state_t *s; - - s = &t->t38x; - t38_core_init(&s->t38, - process_rx_indicator, - process_rx_data, - process_rx_missing, - (void *) t, - tx_packet_handler, - tx_packet_user_data); - t38_set_redundancy_control(&s->t38, T38_PACKET_CATEGORY_INDICATOR, INDICATOR_TX_COUNT); - t38_set_redundancy_control(&s->t38, T38_PACKET_CATEGORY_CONTROL_DATA, DATA_TX_COUNT); - t38_set_redundancy_control(&s->t38, T38_PACKET_CATEGORY_CONTROL_DATA_END, DATA_END_TX_COUNT); - t38_set_redundancy_control(&s->t38, T38_PACKET_CATEGORY_IMAGE_DATA, DATA_TX_COUNT); - t38_set_redundancy_control(&s->t38, T38_PACKET_CATEGORY_IMAGE_DATA_END, DATA_END_TX_COUNT); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data) -{ - if (tx_packet_handler == NULL) - return NULL; - /*endif*/ - if (s == NULL) - { - if ((s = (t38_gateway_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "T.38G"); - - 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); - t38_gateway_set_supported_modems(s, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); - t38_gateway_set_nsx_suppression(s, (const uint8_t *) "\xFF\x00\x00", 3, (const uint8_t *) "\xFF\x00\x00", 3); - - s->core.to_t38.octets_per_data_packet = 1; - 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); - restart_rx_modem(s); - s->core.timed_mode = TIMED_MODE_STARTUP; - s->core.samples_to_timeout = 1; -#if defined(LOG_FAX_AUDIO) - { - char buf[100 + 1]; - struct tm *tm; - time_t now; - - time(&now); - tm = localtime(&now); - sprintf(buf, - "/tmp/t38-rx-audio-%p-%02d%02d%02d%02d%02d%02d", - s, - tm->tm_year%100, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - s->audio.modems.audio_rx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666); - sprintf(buf, - "/tmp/t38-tx-audio-%p-%02d%02d%02d%02d%02d%02d", - s, - tm->tm_year%100, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - s->audio.modems.audio_tx_log = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0666); - } -#endif - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_gateway_release(t38_gateway_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_gateway_free(t38_gateway_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_non_ecm_buffer.c b/libs/spandsp/src/t38_non_ecm_buffer.c deleted file mode 100644 index 99fa456a96..0000000000 --- a/libs/spandsp/src/t38_non_ecm_buffer.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_non_ecm_buffer.c - A rate adapting buffer for T.38 non-ECM image - * and TCF data - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2007, 2008 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 -#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/logging.h" -#include "spandsp/queue.h" -#include "spandsp/dc_restore.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/t38_non_ecm_buffer.h" - -#include "spandsp/private/t38_non_ecm_buffer.h" - -/* Phases */ -enum -{ - TCF_AT_INITIAL_ALL_ONES = 0, - TCF_AT_ALL_ZEROS = 1, - IMAGE_WAITING_FOR_FIRST_EOL = 2, - IMAGE_IN_PROGRESS = 3 -}; - -static void restart_buffer(t38_non_ecm_buffer_state_t *s) -{ - /* This should be called when draining the buffer is complete, which should - occur before any fresh data can possibly arrive to begin refilling it. */ - s->octet = 0xFF; - s->flow_control_fill_octet = 0xFF; - s->input_phase = (s->image_data_mode) ? IMAGE_WAITING_FOR_FIRST_EOL : TCF_AT_INITIAL_ALL_ONES; - s->bit_stream = 0xFFFF; - s->out_ptr = 0; - s->in_ptr = 0; - s->latest_eol_ptr = 0; - s->data_finished = false; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_non_ecm_buffer_get_bit(void *user_data) -{ - t38_non_ecm_buffer_state_t *s; - int bit; - - s = (t38_non_ecm_buffer_state_t *) user_data; - - if (s->bit_no <= 0) - { - /* We need another byte */ - if (s->out_ptr != s->latest_eol_ptr) - { - s->octet = s->data[s->out_ptr]; - s->out_ptr = (s->out_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - } - else - { - if (s->data_finished) - { - /* The queue is empty, and we have received the end of data signal. This must - really be the end to transmission. */ - restart_buffer(s); - return SIG_STATUS_END_OF_DATA; - } - /* The queue is blocked, but this does not appear to be the end of the data. Idle with - fill octets, which should be safe at this point. */ - s->octet = s->flow_control_fill_octet; - s->flow_control_fill_octets++; - } - s->out_octets++; - s->bit_no = 8; - } - s->bit_no--; - bit = (s->octet >> 7) & 1; - s->octet <<= 1; - return bit; -} -/*- End of function --------------------------------------------------------*/ - -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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, const uint8_t *buf, int len) -{ - int i; - int upper; - int lower; - - /* TCF consists of: - - zero or more ones, followed by - - about 1.5s of zeros - There may be a little junk at the end, as the modem shuts down. - - We can stuff with extra ones in the initial period of all ones, and we can stuff with extra - zeros once the zeros start. The thing we need to be wary about is the odd zero bit in the - midst of the ones, due to a bit error. */ - - /* Non-ECM image data consists of: - - zero or more ones, followed by - - zero or more zeros, followed by - - an EOL (end of line), which marks the start of the image, followed by - - a succession of data rows, with an EOL at the end of each, followed by - - an RTC (return to control) - There may be a little junk at the end, as the modem shuts down. - - An EOL 11 zeros followed by a one in a T.4 1D image or 11 zeros followed by a one followed - by a one or a zero in a T.4 2D image. An RTC consists of 6 EOLs in succession, with no - pixel data between them. - - We can stuff with ones until we get the first EOL into our buffer, then we can stuff with - zeros in front of each EOL at any point up the the RTC. We should not pad between the EOLs - which make up the RTC. Most FAX machines don't care about this, but a few will not recognise - the RTC if here is padding between the EOLs. - - We need to buffer whole rows before we output their beginning, so there is no possibility - of underflow mid-row. */ - - /* FoIP has latency issues, because of the fairly tight timeouts in the T.30 spec. We must - ensure our buffering does everything needed to avoid underflows, and to meet the minimum - row length requirements imposed by many mechanical FAX machines. We cannot, however, - afford to bulk up the data, by sending superfluous bytes. The resulting loop delay could - provoke an erroneous timeout of the acknowledgement signal. */ - - i = 0; - switch (s->input_phase) - { - case TCF_AT_INITIAL_ALL_ONES: - /* Dump initial 0xFF bytes. We will add enough of our own to makes things flow - smoothly. If we don't strip these off, we might end up delaying the start of - forwarding by a substantial amount, as we could end up with a large block of 0xFF - bytes before the real data begins. This is especially true with PC FAX - systems. This test is very simplistic, as bit errors could confuse it. */ - for ( ; i < len; i++) - { - if (buf[i] != 0xFF) - { - s->input_phase = TCF_AT_ALL_ZEROS; - s->flow_control_fill_octet = 0x00; - break; - } - } - /* Fall through */ - case TCF_AT_ALL_ZEROS: - for ( ; i < len; i++) - { - s->data[s->in_ptr] = buf[i]; - s->latest_eol_ptr = s->in_ptr; - /* TODO: We can't buffer overflow, since we wrap around. However, the tail could - overwrite itself if things fall badly behind. */ - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - s->in_octets++; - } - break; - case IMAGE_WAITING_FOR_FIRST_EOL: - /* Dump anything up to the first EOL. Let the output side stuff with 0xFF bytes while waiting - for that first EOL. What occurs before the first EOL is expected to be a period of all ones - and then a period of all zeros. We really don't care what junk might be there. By definition, - the image only starts at the first EOL. */ - for ( ; i < len; i++) - { - if (buf[i]) - { - /* There might be an EOL here. Look for at least 11 zeros, followed by a one, split - between two octets. Between those two octets we can insert numerous zero octets - as a means of flow control. Note that we stuff in blocks of 8 bits, and not at - the minimal level. */ - /* Or'ing with 0x800 here is to avoid zero words looking like they have -1 - trailing zeros */ - upper = bottom_bit(s->bit_stream | 0x800); - lower = top_bit(buf[i]); - if ((upper - lower) > (11 - 8)) - { - /* This is an EOL - our first row is beginning. */ - s->input_phase = IMAGE_IN_PROGRESS; - /* Start a new row */ - s->row_bits = lower - 8; - s->latest_eol_ptr = s->in_ptr; - s->flow_control_fill_octet = 0x00; - - /* If we push out two bytes of zero, and our latest non-zero byte - we should definitely form a proper EOL to begin things, with a - few harmless extra zero bits at the front. */ - s->data[s->in_ptr] = 0x00; - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - s->data[s->in_ptr] = 0x00; - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - s->data[s->in_ptr] = buf[i]; - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - s->in_octets += 3; - s->bit_stream = (s->bit_stream << 8) | buf[i]; - i++; - break; - } - } - s->bit_stream = (s->bit_stream << 8) | buf[i]; - } - if (i >= len) - break; - /* Fall through */ - case IMAGE_IN_PROGRESS: - /* Now we have seen an EOL, we can stuff with zeros just in front of that EOL, or any - subsequent EOL that does not immediately follow a previous EOL (i.e. a candidate RTC). - We need to track our way through the image data, allowing the output side to only send - up to the last EOL. This prevents the possibility of underflow mid-row, where we cannot - safely stuff anything in the bit stream. */ - for ( ; i < len; i++) - { - if (buf[i]) - { - /* There might be an EOL here. Look for at least 11 zeros, followed by a one, split - between two octets. Between those two octets we can insert numerous zero octets - as a means of flow control. Note that we stuff in blocks of 8 bits, and not at - the minimal level. */ - /* Or'ing with 0x800 here is to avoid zero words looking like they have -1 - trailing zeros */ - upper = bottom_bit(s->bit_stream | 0x800); - lower = top_bit(buf[i]); - if ((upper - lower) > (11 - 8)) - { - /* This is an EOL. */ - s->row_bits += (8 - lower); - /* Make sure we don't stretch back to back EOLs, as that could spoil the RTC. - This is a slightly crude check, as we don't know if we are processing a T.4 1D - or T.4 2D image. Accepting 12 or 12 bits apart as meaning back to back is fine, - as no 1D image row could be 1 bit long. */ - if (s->row_bits < 12 || s->row_bits > 13) - { - /* If the row is too short, extend it in chunks of a whole byte. */ - /* TODO: extend by the precise amount we should, instead of this - rough approach. */ - while (s->row_bits < s->min_bits_per_row) - { - s->min_row_bits_fill_octets++; - s->data[s->in_ptr] = 0; - s->row_bits += 8; - /* TODO: We can't buffer overflow, since we wrap around. However, - the tail could overwrite itself if things fall badly behind. */ - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - } - /* This is now the limit for the output side, before it starts - stuffing. */ - s->latest_eol_ptr = s->in_ptr; - } - /* Start a new row */ - s->row_bits = lower - 8; - s->in_rows++; - } - } - s->bit_stream = (s->bit_stream << 8) | buf[i]; - s->data[s->in_ptr] = buf[i]; - s->row_bits += 8; - /* TODO: We can't buffer overflow, since we wrap around. However, the tail could overwrite - itself if things fall badly behind. */ - s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); - s->in_octets++; - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_non_ecm_buffer_report_input_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging) -{ - if (s->in_octets || s->min_row_bits_fill_octets) - { - span_log(logging, - SPAN_LOG_FLOW, - "%d+%d incoming non-ECM octets, %d rows.\n", - s->in_octets, - s->min_row_bits_fill_octets, - s->in_rows); - s->in_octets = 0; - s->in_rows = 0; - s->min_row_bits_fill_octets = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging) -{ - if (s->out_octets || s->flow_control_fill_octets) - { - span_log(logging, - SPAN_LOG_FLOW, - "%d+%d outgoing non-ECM octets, %d rows.\n", - s->out_octets - s->flow_control_fill_octets, - s->flow_control_fill_octets, - s->out_rows); - s->out_octets = 0; - s->out_rows = 0; - s->flow_control_fill_octets = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -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 = 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, bool image_mode, int min_bits_per_row) -{ - if (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 = image_mode; - s->min_bits_per_row = min_bits_per_row; - restart_buffer(s); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_non_ecm_buffer_release(t38_non_ecm_buffer_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_non_ecm_buffer_free(t38_non_ecm_buffer_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c deleted file mode 100644 index 6532aacb9a..0000000000 --- a/libs/spandsp/src/t38_terminal.c +++ /dev/null @@ -1,1581 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_terminal.c - T.38 termination, less the packet exchange part - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2008 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/queue.h" -#include "spandsp/power_meter.h" -#include "spandsp/complex.h" -#include "spandsp/tone_generate.h" -#include "spandsp/async.h" -#include "spandsp/hdlc.h" -#include "spandsp/fsk.h" -#include "spandsp/v29tx.h" -#include "spandsp/v29rx.h" -#include "spandsp/v27ter_tx.h" -#include "spandsp/v27ter_rx.h" -#include "spandsp/v17tx.h" -#include "spandsp/v17rx.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/t30_fcf.h" -#include "spandsp/t35.h" -#include "spandsp/t30.h" -#include "spandsp/t30_api.h" -#include "spandsp/t30_logging.h" -#include "spandsp/t38_core.h" -#include "spandsp/t38_terminal.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/timezone.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" -#include "spandsp/private/t30.h" -#include "spandsp/private/t38_core.h" -#include "spandsp/private/t38_terminal.h" - -/* Settings suitable for paced transmission over a UDP transport */ -#define DEFAULT_US_PER_TX_CHUNK 30000 - -#define INDICATOR_TX_COUNT 3 -#define DATA_TX_COUNT 1 -#define DATA_END_TX_COUNT 3 - -/* Settings suitable for unpaced transmission over a TCP transport */ -#define MAX_OCTETS_PER_UNPACED_CHUNK 300 - -/* Backstop timeout if reception of packets stops in the middle of a burst */ -#define MID_RX_TIMEOUT 15000 - -enum -{ - T38_CHUNKING_MERGE_FCS_WITH_DATA = 0x0001, - T38_CHUNKING_WHOLE_FRAMES = 0x0002, - T38_CHUNKING_ALLOW_TEP_TIME = 0x0004, - T38_CHUNKING_SEND_REGULAR_INDICATORS = 0x0008, - T38_CHUNKING_SEND_2S_REGULAR_INDICATORS = 0x0010 -}; - -enum -{ - T38_TIMED_STEP_NONE = 0, - T38_TIMED_STEP_NON_ECM_MODEM = 0x10, - T38_TIMED_STEP_NON_ECM_MODEM_2 = 0x11, - T38_TIMED_STEP_NON_ECM_MODEM_3 = 0x12, - T38_TIMED_STEP_NON_ECM_MODEM_4 = 0x13, - T38_TIMED_STEP_NON_ECM_MODEM_5 = 0x14, - T38_TIMED_STEP_HDLC_MODEM = 0x20, - T38_TIMED_STEP_HDLC_MODEM_2 = 0x21, - T38_TIMED_STEP_HDLC_MODEM_3 = 0x22, - T38_TIMED_STEP_HDLC_MODEM_4 = 0x23, - T38_TIMED_STEP_HDLC_MODEM_5 = 0x24, - T38_TIMED_STEP_CED = 0x30, - T38_TIMED_STEP_CED_2 = 0x31, - T38_TIMED_STEP_CED_3 = 0x32, - T38_TIMED_STEP_CNG = 0x40, - T38_TIMED_STEP_CNG_2 = 0x41, - T38_TIMED_STEP_PAUSE = 0x50, - T38_TIMED_STEP_NO_SIGNAL = 0x60 -}; - -static __inline__ int front_end_status(t38_terminal_state_t *s, int status) -{ - t30_front_end_status(&s->t30, status); - if (s->t38_fe.timed_step == T38_TIMED_STEP_NONE) - return -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void hdlc_accept_frame(t38_terminal_state_t *s, const uint8_t *msg, int len, int ok) -{ - t30_hdlc_accept(&s->t30, msg, len, ok); -} -/*- End of function --------------------------------------------------------*/ - -static int extra_bits_in_stuffed_frame(const uint8_t buf[], int len) -{ - int bitstream; - int ones; - int stuffed; - int i; - int j; - - ones = 0; - stuffed = 0; - /* We should really append the CRC, and include the stuffed bits for that, to get - the exact number of bits in the frame. */ - //len = crc_itu16_append(buf, len); - for (i = 0; i < len; i++) - { - bitstream = buf[i]; - for (j = 0; j < 8; j++) - { - if ((bitstream & 1)) - { - if (++ones >= 5) - { - ones = 0; - stuffed++; - } - /*endif*/ - } - else - { - ones = 0; - } - /*endif*/ - bitstream >>= 1; - } - /*endfor*/ - } - /*endfor*/ - /* The total length of the frame is: - the number of bits in the body - + the number of additional bits in the body due to stuffing - + the number of bits in the CRC - + the number of additional bits in the CRC due to stuffing - + 16 bits for the two terminating flag octets. - Lets just allow 3 bits for the CRC, which is the worst case. It - avoids calculating the real CRC, and the worst it can do is cause - a flag octet's worth of additional output. - */ - return stuffed + 16 + 3 + 16; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_no, int expected_seq_no) -{ - t38_terminal_state_t *s; - - s = (t38_terminal_state_t *) user_data; - s->t38_fe.rx_data_missing = true; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator) -{ - t38_terminal_state_t *s; - t38_terminal_front_end_state_t *fe; - - s = (t38_terminal_state_t *) user_data; - fe = &s->t38_fe; - - /* Protect against T.38 stuff arriving after we've actually finished. */ - if (fe->current_rx_type == T30_MODEM_DONE) - return 0; - /*endif*/ - - if (t->current_rx_indicator == indicator) - { - /* This is probably due to the far end repeating itself, or slipping - preamble messages in between HDLC frames. T.38/V.1.3 tells us to - ignore it. Its harmless. */ - return 0; - } - /*endif*/ - /* In termination mode we don't care very much about indicators telling us training - is starting. We only care about V.21 preamble starting, for timeout control, and - the actual data. */ - switch (indicator) - { - case T38_IND_NO_SIGNAL: - if (t->current_rx_indicator == T38_IND_V21_PREAMBLE - && - (fe->current_rx_type == T30_MODEM_V21 || fe->current_rx_type == T30_MODEM_CNG)) - { - hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, true); - } - /*endif*/ - fe->timeout_rx_samples = 0; - front_end_status(s, T30_FRONT_END_SIGNAL_ABSENT); - break; - case T38_IND_CNG: - /* We are completely indifferent to the startup tones. They serve no purpose for us. - We can't even assume that the existance of a tone means the far end is achieving - proper communication. Some T.38 gateways will just send out a CED or CNG indicator - without having seen anything from the far end FAX terminal. - Just report them for completeness. */ - front_end_status(s, T30_FRONT_END_CNG_PRESENT); - break; - case T38_IND_CED: - front_end_status(s, T30_FRONT_END_CED_PRESENT); - break; - case T38_IND_V21_PREAMBLE: - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); - break; - case T38_IND_V27TER_2400_TRAINING: - case T38_IND_V27TER_4800_TRAINING: - case T38_IND_V29_7200_TRAINING: - case T38_IND_V29_9600_TRAINING: - case T38_IND_V17_7200_SHORT_TRAINING: - case T38_IND_V17_7200_LONG_TRAINING: - case T38_IND_V17_9600_SHORT_TRAINING: - case T38_IND_V17_9600_LONG_TRAINING: - case T38_IND_V17_12000_SHORT_TRAINING: - case T38_IND_V17_12000_LONG_TRAINING: - case T38_IND_V17_14400_SHORT_TRAINING: - case T38_IND_V17_14400_LONG_TRAINING: - case T38_IND_V34_CNTL_CHANNEL_1200: - case T38_IND_V34_PRI_CHANNEL: - case T38_IND_V33_12000_TRAINING: - case T38_IND_V33_14400_TRAINING: - /* We really don't care what kind of modem is delivering the following image data. - We only care that some kind of fast modem signal is coming next. */ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT); - break; - case T38_IND_V8_ANSAM: - case T38_IND_V8_SIGNAL: - case T38_IND_V34_CC_RETRAIN: - /* V.34 support is a work in progress. */ - break; - default: - front_end_status(s, T30_FRONT_END_SIGNAL_ABSENT); - break; - } - /*endswitch*/ - fe->hdlc_rx.len = 0; - fe->rx_data_missing = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int fake_rx_indicator(t38_core_state_t *t, t38_terminal_state_t *s, int indicator) -{ - int ret; - - ret = process_rx_indicator(t, s, indicator); - t->current_rx_indicator = indicator; - return ret; -} -/*- End of function --------------------------------------------------------*/ - -static void process_hdlc_data(t38_terminal_front_end_state_t *fe, const uint8_t *buf, int len) -{ - if (fe->hdlc_rx.len + len <= T38_MAX_HDLC_LEN) - { - bit_reverse(fe->hdlc_rx.buf + fe->hdlc_rx.len, buf, len); - fe->hdlc_rx.len += len; - } - else - { - fe->rx_data_missing = true; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len) -{ - t38_terminal_state_t *s; - t38_terminal_front_end_state_t *fe; -#if defined(_MSC_VER) - uint8_t *buf2 = (uint8_t *) _alloca(len); -#else - uint8_t buf2[len]; -#endif - - s = (t38_terminal_state_t *) user_data; - fe = &s->t38_fe; - - /* Protect against T.38 stuff arriving after we've actually finished. */ - if (fe->current_rx_type == T30_MODEM_DONE) - return 0; - /*endif*/ - - /* In termination mode we don't care very much what the data type is apart from a couple of - special cases. */ - switch (data_type) - { - case T38_DATA_V8: - switch (field_type) - { - case T38_FIELD_CM_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0])); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len); - /*endif*/ - //front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - break; - case T38_FIELD_JM_MESSAGE: - if (len >= 2) - span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len)); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len); - /*endif*/ - //front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - break; - case T38_FIELD_CI_MESSAGE: - if (len >= 1) - span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len); - /*endif*/ - //front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - break; - default: - break; - } - /*endswitch*/ - return 0; - case T38_DATA_V34_PRI_RATE: - switch (field_type) - { - case T38_FIELD_V34RATE: - if (len >= 3) - { - /* Just get and store the rate. The front end has no real interest in the - actual bit rate. */ - fe->t38.v34_rate = t38_v34rate_to_bps(buf, len); - span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", fe->t38.v34_rate); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len); - } - /*endif*/ - break; - default: - break; - } - /*endswitch*/ - return 0; - default: - break; - } - /*endswitch*/ - switch (field_type) - { - case T38_FIELD_HDLC_DATA: - if (fe->timeout_rx_samples == 0) - { - /* HDLC can just start without any signal indicator on some platforms, even when - there is zero packet loss. Nasty, but true. Its a good idea to be tolerant of - loss, though, so accepting a sudden start of HDLC data is the right thing to do. */ - fake_rx_indicator(t, s, T38_IND_V21_PREAMBLE); - /* 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; - /*endif*/ - } - /*endif*/ - if (len > 0) - { - process_hdlc_data(fe, buf, len); - } - /*endif*/ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - break; - case T38_FIELD_HDLC_FCS_OK: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (fe->hdlc_rx.len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK (%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, !fe->rx_data_missing); - fe->hdlc_rx.len = 0; - } - /*endif*/ - fe->rx_data_missing = false; - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - break; - case T38_FIELD_HDLC_FCS_BAD: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (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); - fe->hdlc_rx.len = 0; - } - /*endif*/ - 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: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (fe->hdlc_rx.len > 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK, sig end (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean"); - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing); - fe->hdlc_rx.len = 0; - } - /*endif*/ - 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); - /*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); - break; - case T38_FIELD_HDLC_FCS_BAD_SIG_END: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n"); - /* The sender has incorrectly included data in this message. Cisco implemented inserting - HDLC data here and Commetrex followed for compatibility reasons. We should, too. */ - process_hdlc_data(fe, buf, len); - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - 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); - fe->hdlc_rx.len = 0; - } - /*endif*/ - 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); - /*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); - break; - case T38_FIELD_HDLC_SIG_END: - if (len > 0) - { - span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_SIG_END!\n"); - /* The sender has incorrectly included data in this message, but there seems nothing meaningful - it could be. There could not be an FCS good/bad report beyond this. */ - } - /*endif*/ - /* Some T.38 implementations send multiple T38_FIELD_HDLC_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - /* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send this message at the - end of non-ECM data. We need to tolerate this. We use the generic receive complete - indication, rather than the specific HDLC carrier down. */ - /* This message is expected under 2 circumstances. One is as an alternative to T38_FIELD_HDLC_FCS_OK_SIG_END - - i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops. - The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */ - fe->hdlc_rx.len = 0; - fe->rx_data_missing = false; - front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - } - /*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); - break; - case T38_FIELD_T4_NON_ECM_DATA: - if (!fe->rx_signal_present) - { - t30_non_ecm_put_bit(&s->t30, SIG_STATUS_TRAINING_SUCCEEDED); - fe->rx_signal_present = true; - } - /*endif*/ - if (len > 0) - { - bit_reverse(buf2, buf, len); - t30_non_ecm_put(&s->t30, buf2, len); - } - /*endif*/ - fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); - break; - case T38_FIELD_T4_NON_ECM_SIG_END: - /* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with - incrementing sequence numbers, which are actually repeats. They get through to this point because - of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */ - if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - { - if (len > 0) - { - if (!fe->rx_signal_present) - { - t30_non_ecm_put_bit(&s->t30, SIG_STATUS_TRAINING_SUCCEEDED); - fe->rx_signal_present = true; - } - /*endif*/ - bit_reverse(buf2, buf, len); - t30_non_ecm_put(&s->t30, buf2, len); - } - /*endif*/ - /* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send HDLC signal end where - they should send non-ECM signal end. It is possible they also do the opposite. - We need to tolerate this, so we use the generic receive complete - indication, rather than the specific non-ECM carrier down. */ - front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - } - /*endif*/ - 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; - default: - break; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void send_hdlc(void *user_data, const uint8_t *msg, int len) -{ - t38_terminal_state_t *s; - - s = (t38_terminal_state_t *) user_data; - if (len == 0) - { - /* A length of zero means shut down the HDLC transmission */ - /* Setting len to -1 makes HDLC shut down */ - s->t38_fe.hdlc_tx.len = -1; - return; - } - /*endif*/ - if (len == -1) - { - /* A length of -1 means flush any buffered HDLC data */ - s->t38_fe.hdlc_tx.len = 0; - s->t38_fe.hdlc_tx.ptr = 0; - return; - } - /*endif*/ - if (s->t38_fe.us_per_tx_chunk) - s->t38_fe.hdlc_tx.extra_bits = extra_bits_in_stuffed_frame(msg, len); - /*endif*/ - bit_reverse(s->t38_fe.hdlc_tx.buf, msg, len); - s->t38_fe.hdlc_tx.len = len; - s->t38_fe.hdlc_tx.ptr = 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int bits_to_us(t38_terminal_state_t *s, int bits) -{ - if (s->t38_fe.us_per_tx_chunk == 0 || s->t38_fe.tx_bit_rate == 0) - return 0; - /*endif*/ - return bits*1000000/s->t38_fe.tx_bit_rate; -} -/*- End of function --------------------------------------------------------*/ - -static void set_octets_per_data_packet(t38_terminal_state_t *s, int bit_rate) -{ - s->t38_fe.tx_bit_rate = bit_rate; - if (s->t38_fe.us_per_tx_chunk) - { - s->t38_fe.octets_per_data_packet = (s->t38_fe.us_per_tx_chunk/1000)*bit_rate/(8*1000); - /* Make sure we have a positive number (i.e. we didn't truncate to zero). */ - if (s->t38_fe.octets_per_data_packet < 1) - s->t38_fe.octets_per_data_packet = 1; - /*endif*/ - } - else - { - s->t38_fe.octets_per_data_packet = MAX_OCTETS_PER_UNPACED_CHUNK; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static int set_no_signal(t38_terminal_state_t *s) -{ - int delay; - - if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS)) - { - if ((delay = t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - s->t38_fe.timed_step = T38_TIMED_STEP_NO_SIGNAL; - if ((s->t38_fe.chunking_modes & T38_CHUNKING_SEND_2S_REGULAR_INDICATORS)) - s->t38_fe.timeout_tx_samples = s->t38_fe.next_tx_samples + us_to_samples(2000000); - else - s->t38_fe.timeout_tx_samples = 0; - /*endif*/ - return s->t38_fe.us_per_tx_chunk; - } - /*endif*/ - if ((delay = t38_core_send_indicator(&s->t38_fe.t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - s->t38_fe.timed_step = T38_TIMED_STEP_NONE; - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_no_signal(t38_terminal_state_t *s) -{ - int delay; - - if ((delay = t38_core_send_indicator(&s->t38_fe.t38, 0x100 | T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - if (s->t38_fe.timeout_tx_samples && s->t38_fe.next_tx_samples >= s->t38_fe.timeout_tx_samples) - s->t38_fe.timed_step = T38_TIMED_STEP_NONE; - /*endif*/ - return s->t38_fe.us_per_tx_chunk; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_non_ecm(t38_terminal_state_t *s) -{ - t38_terminal_front_end_state_t *fe; - uint8_t buf[MAX_OCTETS_PER_UNPACED_CHUNK + 50]; - int res; - int delay; - int len; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_NON_ECM_MODEM: - /* Create a 75ms silence */ - if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL) - { - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - } - else - { - if (fe->us_per_tx_chunk) - delay = 75000; - /*endif*/ - } - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_2; - fe->timeout_tx_samples = fe->next_tx_samples - + us_to_samples(t38_core_send_training_delay(&fe->t38, fe->next_tx_indicator)); - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_NON_ECM_MODEM_2: - /* Switch on a fast modem, and give the training time to complete */ - if ((fe->chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS)) - { - if ((delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - if (fe->next_tx_samples >= fe->timeout_tx_samples) - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_3; - /*endif*/ - return fe->us_per_tx_chunk; - } - /*endif*/ - if ((delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_3; - break; - case T38_TIMED_STEP_NON_ECM_MODEM_3: - /* Send a chunk of non-ECM image data */ - /* T.38 says it is OK to send the last of the non-ECM data in the signal end message. - However, I think the early versions of T.38 said the signal end message should not - contain data. Hopefully, following the current spec will not cause compatibility - issues. */ - len = t30_non_ecm_get(&s->t30, buf, fe->octets_per_data_packet); - if (len < 0) - return -1; - /*endif*/ - if (len > 0) - bit_reverse(buf, buf, len); - /*endif*/ - if (len < fe->octets_per_data_packet) - { - /* That's the end of the image data. */ - if (fe->us_per_tx_chunk) - { - /* Pad the end of the data with some zeros. If we just stop abruptly - at the end of the EOLs, some ATAs fail to clean up properly before - shutting down their transmit modem, and the last few rows of the image - are lost or corrupted. Simply delaying the no-signal message does not - help for all implentations. It is usually ignored, which is probably - the right thing to do after receiving a message saying the signal has - ended. */ - memset(buf + len, 0, fe->octets_per_data_packet - len); - fe->non_ecm_trailer_bytes = 3*fe->octets_per_data_packet + len; - len = fe->octets_per_data_packet; - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_4; - } - else - { - /* If we are sending quickly there seems no point in doing any padding */ - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_5; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - break; - } - /*endif*/ - } - /*endif*/ - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA)) < 0) - return res; - /*endif*/ - if (fe->us_per_tx_chunk) - delay = bits_to_us(s, 8*len); - /*endif*/ - break; - case T38_TIMED_STEP_NON_ECM_MODEM_4: - /* Send padding */ - len = fe->octets_per_data_packet; - fe->non_ecm_trailer_bytes -= fe->octets_per_data_packet; - if (fe->non_ecm_trailer_bytes <= 0) - { - len += fe->non_ecm_trailer_bytes; - memset(buf, 0, len); - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_SIG_END, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA_END)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_5; - /* Allow a bit more time than the data will take to play out, to ensure the far ATA does not - cut things short. */ - if (fe->us_per_tx_chunk) - delay = bits_to_us(s, 8*len) + 60000; - /*endif*/ - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - break; - } - /*endif*/ - memset(buf, 0, len); - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_T4_NON_ECM_DATA, buf, len, T38_PACKET_CATEGORY_IMAGE_DATA)) < 0) - return res; - /*endif*/ - if (fe->us_per_tx_chunk) - delay = bits_to_us(s, 8*len); - /*endif*/ - break; - case T38_TIMED_STEP_NON_ECM_MODEM_5: - /* This should not be needed, since the message above indicates the end of the signal, but it - seems like it can improve compatibility with quirky implementations. */ - delay = set_no_signal(s); - if (fe->queued_timed_step != T38_TIMED_STEP_NONE) - { - fe->timed_step = fe->queued_timed_step; - fe->queued_timed_step = T38_TIMED_STEP_NONE; - } - else - { - fe->timed_step = T38_TIMED_STEP_NONE; - } - /*endif*/ - return delay; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_hdlc(t38_terminal_state_t *s) -{ - t38_terminal_front_end_state_t *fe; - uint8_t buf[MAX_OCTETS_PER_UNPACED_CHUNK + 50]; - t38_data_field_t data_fields[2]; - int category; - int previous; - int res; - int delay; - int i; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_HDLC_MODEM: - /* Create a 75ms silence */ - if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL) - { - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - } - else - { - delay = (fe->us_per_tx_chunk) ? 75000 : 0; - } - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_2; - fe->timeout_tx_samples = fe->next_tx_samples - + us_to_samples(t38_core_send_training_delay(&fe->t38, fe->next_tx_indicator)) - + us_to_samples(t38_core_send_flags_delay(&fe->t38, fe->next_tx_indicator)) - + us_to_samples(delay); - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_HDLC_MODEM_2: - /* Send HDLC preambling */ - if ((fe->chunking_modes & T38_CHUNKING_SEND_REGULAR_INDICATORS)) - { - if ((delay = t38_core_send_indicator(&fe->t38, 0x100 | fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - if (fe->next_tx_samples >= fe->timeout_tx_samples) - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - /*endif*/ - return fe->us_per_tx_chunk; - } - /*endif*/ - if ((delay = t38_core_send_indicator(&fe->t38, fe->next_tx_indicator)) < 0) - return delay; - /*endif*/ - delay += t38_core_send_flags_delay(&fe->t38, fe->next_tx_indicator); - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - break; - case T38_TIMED_STEP_HDLC_MODEM_3: - /* Send a chunk of HDLC data */ - i = fe->hdlc_tx.len - fe->hdlc_tx.ptr; - if (fe->octets_per_data_packet >= i) - { - /* The last part of an HDLC frame */ - if ((fe->chunking_modes & T38_CHUNKING_MERGE_FCS_WITH_DATA)) - { - /* Copy the data, as we might be about to refill the buffer it is in */ - memcpy(buf, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i); - data_fields[0].field_type = T38_FIELD_HDLC_DATA; - data_fields[0].field = buf; - data_fields[0].field_len = i; - - /* Now see about the next HDLC frame. This will tell us whether to send FCS_OK or FCS_OK_SIG_END */ - fe->hdlc_tx.ptr = 0; - fe->hdlc_tx.len = 0; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - /* The above step should have got the next HDLC step ready - either another frame, or an instruction to stop transmission. */ - if (fe->hdlc_tx.len >= 0) - { - data_fields[1].field_type = T38_FIELD_HDLC_FCS_OK; - data_fields[1].field = NULL; - data_fields[1].field_len = 0; - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - delay = bits_to_us(s, i*8 + fe->hdlc_tx.extra_bits); - } - else - { - data_fields[1].field_type = T38_FIELD_HDLC_FCS_OK_SIG_END; - data_fields[1].field = NULL; - data_fields[1].field_len = 0; - 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_multi_field(&fe->t38, fe->current_tx_data_type, data_fields, 2, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_5; - /* We add a bit of extra time here, as with some implementations - the carrier falling too abruptly causes data loss. */ - delay = bits_to_us(s, i*8 + fe->hdlc_tx.extra_bits); - if (fe->us_per_tx_chunk) - delay += 100000; - /*endif*/ - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - } - /*endif*/ - break; - } - /*endif*/ - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_4; - } - else - { - i = fe->octets_per_data_packet; - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data(&fe->t38, fe->current_tx_data_type, T38_FIELD_HDLC_DATA, &fe->hdlc_tx.buf[fe->hdlc_tx.ptr], i, category)) < 0) - return res; - /*endif*/ - fe->hdlc_tx.ptr += i; - } - /*endif*/ - delay = bits_to_us(s, i*8); - break; - case T38_TIMED_STEP_HDLC_MODEM_4: - /* End of HDLC frame */ - previous = fe->current_tx_data_type; - fe->hdlc_tx.ptr = 0; - fe->hdlc_tx.len = 0; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - /* The above step should have got the next HDLC step ready - either another frame, or an instruction to stop transmission. */ - if (fe->hdlc_tx.len >= 0) - { - if (fe->hdlc_tx.len == 0) - { - /* Now, how did we get here? We have finished a frame, but have no new frame to - send, and no end of transmission condition. */ - span_log(&s->logging, SPAN_LOG_FLOW, "No new frame or end transmission condition.\n"); - } - /*endif*/ - /* Finish the current frame off, and prepare for the next one. */ - category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA : T38_PACKET_CATEGORY_IMAGE_DATA; - if ((res = t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK, NULL, 0, category)) < 0) - return res; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_3; - /* We should now wait enough time for everything to clear through an analogue modem at the far end. */ - delay = bits_to_us(s, fe->hdlc_tx.extra_bits); - } - else - { - /* End of transmission */ - 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; - /*endif*/ - fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_5; - /* We add a bit of extra time here, as with some implementations - the carrier falling too abruptly causes data loss. */ - delay = bits_to_us(s, fe->hdlc_tx.extra_bits); - if (fe->us_per_tx_chunk) - delay += 100000; - /*endif*/ - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - } - /*endif*/ - break; - case T38_TIMED_STEP_HDLC_MODEM_5: - /* Note that some boxes do not like us sending a T38_FIELD_HDLC_SIG_END at this point. - A T38_IND_NO_SIGNAL should always be OK. */ - delay = set_no_signal(s); - if (fe->queued_timed_step != T38_TIMED_STEP_NONE) - { - fe->timed_step = fe->queued_timed_step; - fe->queued_timed_step = T38_TIMED_STEP_NONE; - } - else - { - fe->timed_step = T38_TIMED_STEP_NONE; - } - /*endif*/ - return delay; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_ced(t38_terminal_state_t *s) -{ - t38_terminal_front_end_state_t *fe; - int delay; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_CED: - /* It seems common practice to start with a no signal indicator, though - this is not a specified requirement. Since we should be sending 200ms - of silence, starting the delay with a no signal indication makes sense. - We do need a 200ms delay, as that is a specification requirement. */ - fe->timed_step = T38_TIMED_STEP_CED_2; - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - delay = (fe->us_per_tx_chunk) ? 200000 : 0; - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_CED_2: - /* Initial 200ms delay over. Send the CED indicator */ - fe->timed_step = T38_TIMED_STEP_CED_3; - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_CED)) < 0) - return delay; - /*endif*/ - fe->current_tx_data_type = T38_DATA_NONE; - break; - case T38_TIMED_STEP_CED_3: - /* End of CED */ - fe->timed_step = fe->queued_timed_step; - if (front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE) < 0) - return -1; - /*endif*/ - return 0; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -static int stream_cng(t38_terminal_state_t *s) -{ - t38_terminal_front_end_state_t *fe; - int delay; - - fe = &s->t38_fe; - for (delay = 0; delay == 0; ) - { - switch (fe->timed_step) - { - case T38_TIMED_STEP_CNG: - /* It seems common practice to start with a no signal indicator, though - this is not a specified requirement of the T.38 spec. Since we should - be sending 200ms of silence, according to T.30, starting that delay with - a no signal indication makes sense. */ - fe->timed_step = T38_TIMED_STEP_CNG_2; - if ((delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL)) < 0) - return delay; - /*endif*/ - delay = (fe->us_per_tx_chunk) ? 200000 : 0; - fe->next_tx_samples = fe->samples; - break; - case T38_TIMED_STEP_CNG_2: - /* Initial short delay over. Send the CNG indicator. CNG persists until something - coming the other way interrupts it, or a long timeout controlled by the T.30 engine - expires. */ - delay = t38_core_send_indicator(&fe->t38, T38_IND_CNG); - fe->timed_step = fe->queued_timed_step; - fe->current_tx_data_type = T38_DATA_NONE; - return delay; - } - /*endswitch*/ - } - /*endfor*/ - return delay; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_terminal_send_timeout(t38_terminal_state_t *s, int samples) -{ - t38_terminal_front_end_state_t *fe; - int delay; - - fe = &s->t38_fe; - if (fe->current_rx_type == T30_MODEM_DONE || fe->current_tx_type == T30_MODEM_DONE) - return true; - /*endif*/ - - fe->samples += samples; - t30_timer_update(&s->t30, samples); - if (fe->timeout_rx_samples && fe->samples > fe->timeout_rx_samples) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Timeout mid-receive\n"); - fe->timeout_rx_samples = 0; - front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); - } - /*endif*/ - if (fe->timed_step == T38_TIMED_STEP_NONE) - 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; - /*endif*/ - /* Its time to send something */ - delay = 0; - switch ((fe->timed_step & 0xFFF0)) - { - case T38_TIMED_STEP_NON_ECM_MODEM: - delay = stream_non_ecm(s); - break; - case T38_TIMED_STEP_HDLC_MODEM: - delay = stream_hdlc(s); - break; - case T38_TIMED_STEP_CED: - delay = stream_ced(s); - break; - case T38_TIMED_STEP_CNG: - delay = stream_cng(s); - break; - case T38_TIMED_STEP_PAUSE: - /* End of timed pause */ - fe->timed_step = T38_TIMED_STEP_NONE; - front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE); - break; - case T38_TIMED_STEP_NO_SIGNAL: - delay = stream_no_signal(s); - break; - } - /*endswitch*/ - if (delay < 0) - { - t30_terminate(&s->t30); - return true; - } - /*endif*/ - fe->next_tx_samples += us_to_samples(delay); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static void set_rx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) -{ - t38_terminal_state_t *s; - - s = (t38_terminal_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "Set rx type %d\n", type); - s->t38_fe.current_rx_type = type; -} -/*- End of function --------------------------------------------------------*/ - -static void start_tx(t38_terminal_front_end_state_t *fe, int use_hdlc) -{ - int step; - - /* The actual transmission process depends on whether we are sending at a paced manner, - for interaction with a traditional FAX machine, or streaming as fast as we can, normally - over a TCP connection to a machine directly connected to the internet. */ - - step = (use_hdlc) ? T38_TIMED_STEP_HDLC_MODEM : T38_TIMED_STEP_NON_ECM_MODEM; - if (fe->timed_step == T38_TIMED_STEP_NONE) - { - fe->queued_timed_step = T38_TIMED_STEP_NONE; - fe->timed_step = step; - } - else - { - fe->queued_timed_step = step; - } - /*endif*/ - if (fe->next_tx_samples < fe->samples) - fe->next_tx_samples = fe->samples; - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) -{ - t38_terminal_state_t *s; - t38_terminal_front_end_state_t *fe; - - s = (t38_terminal_state_t *) user_data; - fe = &s->t38_fe; - span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); - if (fe->current_tx_type == type) - return; - /*endif*/ - - set_octets_per_data_packet(s, bit_rate); - switch (type) - { - case T30_MODEM_NONE: - /* If a "no signal" indicator is waiting to be played out, don't disturb it. */ - if (fe->timed_step != T38_TIMED_STEP_NON_ECM_MODEM_5 && fe->timed_step != T38_TIMED_STEP_HDLC_MODEM_5) - fe->timed_step = T38_TIMED_STEP_NONE; - /*endif*/ - fe->current_tx_data_type = T38_DATA_NONE; - break; - case T30_MODEM_PAUSE: - if (s->t38_fe.us_per_tx_chunk) - fe->next_tx_samples = fe->samples + ms_to_samples(short_train); - else - fe->next_tx_samples = fe->samples; - /*endif*/ - if (fe->timed_step == T38_TIMED_STEP_NONE) - { - fe->queued_timed_step = T38_TIMED_STEP_NONE; - fe->timed_step = T38_TIMED_STEP_PAUSE; - } - else - { - fe->queued_timed_step = T38_TIMED_STEP_PAUSE; - } - /*endif*/ - fe->current_tx_data_type = T38_DATA_NONE; - break; - case T30_MODEM_CED: - fe->next_tx_samples = fe->samples; - fe->timed_step = T38_TIMED_STEP_CED; - fe->current_tx_data_type = T38_DATA_NONE; - break; - case T30_MODEM_CNG: - fe->next_tx_samples = fe->samples; - fe->timed_step = T38_TIMED_STEP_CNG; - fe->current_tx_data_type = T38_DATA_NONE; - break; - case T30_MODEM_V21: - fe->next_tx_indicator = T38_IND_V21_PREAMBLE; - fe->current_tx_data_type = T38_DATA_V21; - start_tx(fe, use_hdlc); - break; - case T30_MODEM_V27TER: - switch (bit_rate) - { - case 2400: - fe->next_tx_indicator = T38_IND_V27TER_2400_TRAINING; - fe->current_tx_data_type = T38_DATA_V27TER_2400; - break; - case 4800: - fe->next_tx_indicator = T38_IND_V27TER_4800_TRAINING; - fe->current_tx_data_type = T38_DATA_V27TER_4800; - break; - } - /*endswitch*/ - start_tx(fe, use_hdlc); - break; - case T30_MODEM_V29: - switch (bit_rate) - { - case 7200: - fe->next_tx_indicator = T38_IND_V29_7200_TRAINING; - fe->current_tx_data_type = T38_DATA_V29_7200; - break; - case 9600: - fe->next_tx_indicator = T38_IND_V29_9600_TRAINING; - fe->current_tx_data_type = T38_DATA_V29_9600; - break; - } - /*endswitch*/ - start_tx(fe, use_hdlc); - break; - case T30_MODEM_V17: - switch (bit_rate) - { - case 7200: - fe->next_tx_indicator = (short_train) ? T38_IND_V17_7200_SHORT_TRAINING : T38_IND_V17_7200_LONG_TRAINING; - fe->current_tx_data_type = T38_DATA_V17_7200; - break; - case 9600: - fe->next_tx_indicator = (short_train) ? T38_IND_V17_9600_SHORT_TRAINING : T38_IND_V17_9600_LONG_TRAINING; - fe->current_tx_data_type = T38_DATA_V17_9600; - break; - case 12000: - fe->next_tx_indicator = (short_train) ? T38_IND_V17_12000_SHORT_TRAINING : T38_IND_V17_12000_LONG_TRAINING; - fe->current_tx_data_type = T38_DATA_V17_12000; - break; - case 14400: - fe->next_tx_indicator = (short_train) ? T38_IND_V17_14400_SHORT_TRAINING : T38_IND_V17_14400_LONG_TRAINING; - fe->current_tx_data_type = T38_DATA_V17_14400; - break; - } - /*endswitch*/ - start_tx(fe, use_hdlc); - break; - case T30_MODEM_DONE: - span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); - fe->timed_step = T38_TIMED_STEP_NONE; - fe->current_tx_data_type = T38_DATA_NONE; - break; - } - /*endswitch*/ - fe->current_tx_type = type; -} -/*- End of function --------------------------------------------------------*/ - -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); - 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); - else - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_INDICATOR, 1); - /*endif*/ - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA, 1); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA_END, 1); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA, 1); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA_END, 1); - s->t38_fe.us_per_tx_chunk = 0; - s->t38_fe.chunking_modes &= ~T38_CHUNKING_SEND_REGULAR_INDICATORS; - s->t38_fe.chunking_modes |= T38_CHUNKING_MERGE_FCS_WITH_DATA; - } - else - { - /* Paced streaming mode, as used for UDP transports */ - 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); - else - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_INDICATOR, INDICATOR_TX_COUNT); - /*endif*/ - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA, DATA_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_CONTROL_DATA_END, DATA_END_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA, DATA_TX_COUNT); - t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_IMAGE_DATA_END, DATA_END_TX_COUNT); - s->t38_fe.us_per_tx_chunk = DEFAULT_US_PER_TX_CHUNK; - if ((config & (T38_TERMINAL_OPTION_REGULAR_INDICATORS | T38_TERMINAL_OPTION_2S_REPEATING_INDICATORS))) - s->t38_fe.chunking_modes |= T38_CHUNKING_SEND_REGULAR_INDICATORS; - else - s->t38_fe.chunking_modes &= ~T38_CHUNKING_SEND_REGULAR_INDICATORS; - /*endif*/ - if ((config & T38_TERMINAL_OPTION_2S_REPEATING_INDICATORS)) - s->t38_fe.chunking_modes |= T38_CHUNKING_SEND_2S_REGULAR_INDICATORS; - else - s->t38_fe.chunking_modes &= ~T38_CHUNKING_SEND_2S_REGULAR_INDICATORS; - /*endif*/ - } - /*endif*/ - set_octets_per_data_packet(s, 300); -} -/*- End of function --------------------------------------------------------*/ - -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; - else - s->t38_fe.chunking_modes &= ~T38_CHUNKING_ALLOW_TEP_TIME; - /*endif*/ - t38_set_tep_handling(&s->t38_fe.t38, use_tep); -} -/*- End of function --------------------------------------------------------*/ - -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; - else - s->t38_fe.iaf &= ~T30_IAF_MODE_NO_FILL_BITS; - /*endif*/ - t30_set_iaf_mode(&s->t30, s->t38_fe.iaf); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t30_state_t *) t38_terminal_get_t30_state(t38_terminal_state_t *s) -{ - return &s->t30; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t38_core_state_t *) t38_terminal_get_t38_core_state(t38_terminal_state_t *s) -{ - return &s->t38_fe.t38; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_terminal_t38_fe_restart(t38_terminal_state_t *t) -{ - t38_terminal_front_end_state_t *s; - - s = &t->t38_fe; - t38_core_restart(&s->t38); - - s->current_tx_type = -1; - 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; - - s->current_tx_data_type = T38_DATA_NONE; - s->next_tx_samples = 0; - - s->hdlc_tx.ptr = 0; - s->hdlc_tx.extra_bits = 0; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_terminal_t38_fe_init(t38_terminal_state_t *t, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data) -{ - t38_terminal_front_end_state_t *s; - - s = &t->t38_fe; - t38_core_init(&s->t38, - process_rx_indicator, - process_rx_data, - process_rx_missing, - (void *) t, - tx_packet_handler, - tx_packet_user_data); - t38_set_fastest_image_data_rate(&s->t38, 14400); - - 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; - s->iaf = T30_IAF_MODE_T38; - - s->current_tx_data_type = T38_DATA_NONE; - s->next_tx_samples = 0; - s->chunking_modes = T38_CHUNKING_ALLOW_TEP_TIME; - - s->hdlc_tx.ptr = 0; - s->hdlc_tx.extra_bits = 0; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t38_terminal_get_logging_state(t38_terminal_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_terminal_restart(t38_terminal_state_t *s, - bool calling_party) -{ - t38_terminal_t38_fe_restart(s); - t30_restart(&s->t30, calling_party); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t38_terminal_state_t *) t38_terminal_init(t38_terminal_state_t *s, - bool calling_party, - t38_tx_packet_handler_t tx_packet_handler, - void *tx_packet_user_data) -{ - if (tx_packet_handler == NULL) - return NULL; - /*endif*/ - - if (s == NULL) - { - if ((s = (t38_terminal_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "T.38T"); - - t38_terminal_t38_fe_init(s, tx_packet_handler, tx_packet_user_data); - - t38_terminal_set_config(s, 0); - - t30_init(&s->t30, - calling_party, - set_rx_type, - (void *) s, - set_tx_type, - (void *) s, - send_hdlc, - (void *) s); - t30_set_iaf_mode(&s->t30, s->t38_fe.iaf); - t30_set_supported_modems(&s->t30, - T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17 | T30_SUPPORT_IAF); - t30_restart(&s->t30, calling_party); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_terminal_release(t38_terminal_state_t *s) -{ - t30_release(&s->t30); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t38_terminal_free(t38_terminal_state_t *s) -{ - t38_terminal_release(s); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t42.c b/libs/spandsp/src/t42.c deleted file mode 100644 index 697f623106..0000000000 --- a/libs/spandsp/src/t42.c +++ /dev/null @@ -1,1436 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t42.c - ITU T.42 JPEG for 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/saturated.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/private/logging.h" -#include "spandsp/private/t81_t82_arith_coding.h" -#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" -#if defined(T42_USE_LUTS) -#include "cielab_luts.h" -#endif - -typedef struct -{ - float L; - float a; - float b; -} cielab_t; - -typedef struct -{ - uint8_t tag[5]; - const char *name; - float xn; - float yn; - float zn; -} illuminant_t; - -static const illuminant_t illuminants[] = -{ - {"\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}, /* Mid-morning/mid-afternoon daylight */ - {"", "CIE D55/10°", 95.799f, 100.000f, 90.926f}, - {"\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}, /* North sky daylight */ - {"", "CIE D75/10°", 94.416f, 100.000f, 120.641f}, - {"\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}, /* D65 simulator, daylight simulator */ - {"", "F07/10°", 95.792f, 100.000f, 107.686f}, - {"\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}, /* Incandescent/tungsten */ - {"", "A/10°", 111.144f, 100.000f, 35.200f}, - {"\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} -}; - -/* 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) -{ - uint16_t value; - - value = ((uint16_t) s[0] << 8) | (uint16_t) s[1]; - return value; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -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 --------------------------------------------------------*/ -#endif - -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 --------------------------------------------------------*/ - -SPAN_DECLARE(bool) t42_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len) -{ - int type; - int seg; - int pos; - - /* 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(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) - { - lab->x_n = new_xn/100.0f; - lab->y_n = new_yn/100.0f; - lab->z_n = new_zn/100.0f; - } - else - { - 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 *lab, int L_min, int L_max, int a_min, int a_max, int b_min, int b_max, int ab_are_signed) -{ - lab->range_L = L_max - L_min; - lab->range_a = a_max - a_min; - lab->range_b = b_max - b_min; - - 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; - - lab->range_L /= (256.0f - 1.0f); - lab->range_a /= (256.0f - 1.0f); - lab->range_b /= (256.0f - 1.0f); - - lab->ab_are_signed = ab_are_signed; -} -/*- End of function --------------------------------------------------------*/ - -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) -{ - 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); - - lab->offset_L = L_P; - lab->offset_a = a_P; - lab->offset_b = b_P; - - lab->ab_are_signed = false; -} -/*- End of function --------------------------------------------------------*/ - -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] = { 0 }; - - 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); - 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(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 --------------------------------------------------------*/ - -void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12]) -{ - int i; - int val[6]; - - for (i = 0; i < 6; i++) - val[i] = pack_16(&code[2*i]); - span_log(logging, - SPAN_LOG_FLOW, - "Gamut L=[%d,%d], a*=[%d,%d], b*=[%d,%d]\n", - val[0], - val[1], - val[2], - val[3], - val[4], - val[5]); - set_lab_gamut2(s, val[0], val[1], val[2], val[3], val[4], val[5]); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void itu_to_lab(lab_params_t *s, cielab_t *lab, const uint8_t in[3]) -{ - uint8_t a; - uint8_t b; - - /* T.4 E.6.4 */ - lab->L = s->range_L*(in[0] - s->offset_L); - a = in[1]; - b = in[2]; - if (s->ab_are_signed) - { - a += 128; - b += 128; - } - lab->a = s->range_a*(a - s->offset_a); - lab->b = s->range_b*(b - s->offset_b); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void lab_to_itu(lab_params_t *s, uint8_t out[3], const cielab_t *lab) -{ - /* T.4 E.6.4 */ - out[0] = saturateu8(floorf(lab->L/s->range_L + s->offset_L)); - out[1] = saturateu8(floorf(lab->a/s->range_a + s->offset_a)); - out[2] = saturateu8(floorf(lab->b/s->range_b + s->offset_b)); - if (s->ab_are_signed) - { - out[1] -= 128; - out[2] -= 128; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srgb[], int pixels) -{ - float x; - float y; - float z; - float r; - float g; - float b; - float xx; - float yy; - float zz; - cielab_t l; - int i; - - for (i = 0; i < 3*pixels; i += 3) - { -#if defined(T42_USE_LUTS) - r = srgb_to_linear[srgb[i]]; - g = srgb_to_linear[srgb[i + 1]]; - b = srgb_to_linear[srgb[i + 2]]; -#else - r = srgb[i]/256.0f; - g = srgb[i + 1]/256.0f; - b = srgb[i + 2]/256.0f; - - /* sRGB to linear RGB */ - r = (r > 0.04045f) ? powf((r + 0.055f)/1.055f, 2.4f) : r/12.92f; - g = (g > 0.04045f) ? powf((g + 0.055f)/1.055f, 2.4f) : g/12.92f; - b = (b > 0.04045f) ? powf((b + 0.055f)/1.055f, 2.4f) : b/12.92f; -#endif - - /* Linear RGB to XYZ */ - x = 0.4124f*r + 0.3576f*g + 0.1805f*b; - y = 0.2126f*r + 0.7152f*g + 0.0722f*b; - z = 0.0193f*r + 0.1192f*g + 0.9505f*b; - - /* Normalise for the illuminant */ - 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); - yy = (y <= 0.008856f) ? (7.787f*y + 0.1379f) : cbrtf(y); - zz = (z <= 0.008856f) ? (7.787f*z + 0.1379f) : cbrtf(z); - l.L = 116.0f*yy - 16.0f; - l.a = 500.0f*(xx - yy); - l.b = 200.0f*(yy - zz); - - lab_to_itu(s, lab, &l); - - lab += 3; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) lab_to_srgb(lab_params_t *s, uint8_t srgb[], const uint8_t lab[], int pixels) -{ - float x; - float y; - float z; - float r; - float g; - float b; - float ll; - cielab_t l; - int val; - int i; - - for (i = 0; i < 3*pixels; i += 3) - { - itu_to_lab(s, &l, lab); - - /* Lab to XYZ */ - ll = (1.0f/116.0f)*(l.L + 16.0f); - y = ll; - y = (y <= 0.2068f) ? (0.1284f*(y - 0.1379f)) : y*y*y; - x = ll + (1.0f/500.0f)*l.a; - x = (x <= 0.2068f) ? (0.1284f*(x - 0.1379f)) : x*x*x; - z = ll - (1.0f/200.0f)*l.b; - z = (z <= 0.2068f) ? (0.1284f*(z - 0.1379f)) : z*z*z; - - /* Normalise for the illuminant */ - x *= s->x_n; - y *= s->y_n; - z *= s->z_n; - - /* XYZ to linear RGB */ - r = 3.2406f*x - 1.5372f*y - 0.4986f*z; - g = -0.9689f*x + 1.8758f*y + 0.0415f*z; - b = 0.0557f*x - 0.2040f*y + 1.0570f*z; - -#if defined(T42_USE_LUTS) - val = r*4096.0f; - srgb[i] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; - val = g*4096.0f; - srgb[i + 1] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; - val = b*4096.0f; - srgb[i + 2] = linear_to_srgb[(val < 0) ? 0 : (val < 4095) ? val : 4095]; -#else - /* Linear RGB to sRGB */ - r = (r > 0.0031308f) ? (1.055f*powf(r, 1.0f/2.4f) - 0.055f) : r*12.92f; - g = (g > 0.0031308f) ? (1.055f*powf(g, 1.0f/2.4f) - 0.055f) : g*12.92f; - b = (b > 0.0031308f) ? (1.055f*powf(b, 1.0f/2.4f) - 0.055f) : b*12.92f; - - srgb[i] = saturateu8(floorf(r*256.0f)); - srgb[i + 1] = saturateu8(floorf(g*256.0f)); - srgb[i + 2] = saturateu8(floorf(b*256.0f)); -#endif - lab += 3; - } -} -/*- End of function --------------------------------------------------------*/ - -static int is_itu_fax(t42_decode_state_t *s, jpeg_saved_marker_ptr ptr) -{ - const uint8_t *data; - int ok; - int val[6]; - - ok = false; - for ( ; ptr; ptr = ptr->next) - { - 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; - } - } - - return ok; -} -/*- End of function --------------------------------------------------------*/ - -static void set_itu_fax(t42_encode_state_t *s) -{ - uint8_t data[50]; - int val[6]; - - 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 (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"); - 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); - } - - 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"); - memcpy(data, "G3FAX\2", 6); - if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0) - { - memcpy(&data[6], s->illuminant_code, 4); - } - else - { - 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); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t42_encode_set_options(t42_encode_state_t *s, - uint32_t l0, - 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 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 --------------------------------------------------------*/ - -SPAN_DECLARE(void) t42_encode_abort(t42_encode_state_t *s) -{ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t42_encode_comment(t42_encode_state_t *s, const uint8_t comment[], size_t len) -{ -} -/*- End of function --------------------------------------------------------*/ - -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) -{ - 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 s->image_width; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t42_encode_get_image_length(t42_encode_state_t *s) -{ - return s->image_length; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_encode_get_compressed_image_size(t42_encode_state_t *s) -{ - return s->compressed_image_size; -} -/*- End of function --------------------------------------------------------*/ - -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 --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t42_encode_get_logging_state(t42_encode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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; - - 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 --------------------------------------------------------*/ - -SPAN_DECLARE(t42_encode_state_t *) t42_encode_init(t42_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 = (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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_encode_release(t42_encode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_encode_free(t42_encode_state_t *s) -{ - int ret; - - ret = t42_encode_release(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 --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_decode_put(t42_decode_state_t *s, const uint8_t data[], size_t len) -{ - 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 *) span_realloc(s->compressed_buf, s->compressed_image_size + len + 10000)) == NULL) - return -1; - s->buf_size = s->compressed_image_size + len + 10000; - s->compressed_buf = buf; - } - memcpy(&s->compressed_buf[s->compressed_image_size], data, len); - s->compressed_image_size += len; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_decode_set_row_write_handler(t42_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; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_decode_set_comment_handler(t42_decode_state_t *s, - uint32_t max_comment_len, - t4_row_write_handler_t handler, - void *user_data) -{ - s->max_comment_len = max_comment_len; - s->comment_handler = handler; - s->comment_user_data = user_data; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_decode_set_image_size_constraints(t42_decode_state_t *s, - uint32_t max_xd, - uint32_t max_yd) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t42_decode_get_image_width(t42_decode_state_t *s) -{ - return s->image_width; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t42_decode_get_image_length(t42_decode_state_t *s) -{ - return s->image_length; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_decode_get_compressed_image_size(t42_decode_state_t *s) -{ - return s->compressed_image_size; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t42_decode_get_logging_state(t42_decode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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 --------------------------------------------------------*/ - -SPAN_DECLARE(t42_decode_state_t *) t42_decode_init(t42_decode_state_t *s, - t4_row_write_handler_t handler, - void *user_data) -{ - if (s == NULL) - { - if ((s = (t42_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.42"); - - s->row_write_handler = handler; - s->row_write_user_data = user_data; - - s->buf_size = 0; - s->compressed_buf = NULL; - - t42_decode_restart(s); - - return s; -} -/*- End of function --------------------------------------------------------*/ - -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) - { - span_free(s->comment); - s->comment = NULL; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_decode_free(t42_decode_state_t *s) -{ - int ret; - - ret = t42_decode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t42_t43_local.h b/libs/spandsp/src/t42_t43_local.h deleted file mode 100644 index 45230e57d3..0000000000 --- a/libs/spandsp/src/t42_t43_local.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t42_t43_local.h - definitions for T.42 and T.43 shared 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(_T42_T43_LOCAL_H_) -#define _T42_T43_LOCAL_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -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) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t43.c b/libs/spandsp/src/t43.c deleted file mode 100644 index d21bdbaeca..0000000000 --- a/libs/spandsp/src/t43.c +++ /dev/null @@ -1,934 +0,0 @@ -/* - * 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 --------------------------------------------------------*/ - -#if 0 -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 --------------------------------------------------------*/ -#endif - -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_release(&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) - { - 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->ptr = 0; - s->row = 0; - s->plane_ptr = 0; - s->current_bit_plane++; - 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 deleted file mode 100644 index 56bb1ac7cd..0000000000 --- a/libs/spandsp/src/t4_rx.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_rx.c - ITU T.4 FAX image receive processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2007, 2010 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.h" -#include "spandsp/version.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" - -/*! 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 >= 20120922 && defined(HAVE_TIF_DIR_H) -extern TIFFFieldArray tiff_fx_field_array; -#endif -#endif - -SPAN_DECLARE(const char *) t4_compression_to_str(int compression) -{ - switch (compression) - { - case T4_COMPRESSION_NONE: - return "None"; - case T4_COMPRESSION_T4_1D: - return "T.4 1-D"; - case T4_COMPRESSION_T4_2D: - return "T.4 2-D"; - case T4_COMPRESSION_T6: - return "T.6"; - case T4_COMPRESSION_T85: - return "T.85"; - 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 "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) t4_image_type_to_str(int type) -{ - switch (type) - { - case T4_IMAGE_TYPE_BILEVEL: - 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 "???"; -} -/*- End of function --------------------------------------------------------*/ - -static int set_tiff_directory_info(t4_rx_state_t *s) -{ - time_t now; - struct tm *tm; - char buf[256 + 1]; - uint16_t resunit; - float x_resolution; - float y_resolution; - t4_rx_tiff_state_t *t; - int32_t output_compression; - int32_t output_t4_options; - int bits_per_sample; - int samples_per_pixel; - int photometric; - 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; - output_t4_options = 0; - switch (t->compression) - { - case T4_COMPRESSION_T4_1D: - default: - output_compression = COMPRESSION_CCITT_T4; - output_t4_options = GROUP3OPT_FILLBITS; - break; - case T4_COMPRESSION_T4_2D: - output_compression = COMPRESSION_CCITT_T4; - output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; - break; - case T4_COMPRESSION_T6: - output_compression = COMPRESSION_CCITT_T6; - break; - 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 - 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; -#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); - switch (output_compression) - { - case COMPRESSION_CCITT_T4: - TIFFSetField(t->tiff_file, TIFFTAG_T4OPTIONS, output_t4_options); - TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); - break; - case COMPRESSION_CCITT_T6: - 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; - case COMPRESSION_T43: - 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); - TIFFSetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel); - 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; - y_resolution = s->metadata.y_resolution/100.0f; - /* Metric seems the sane thing to use in the 21st century, but a lot of lousy software - gets FAX resolutions wrong, and more get it wrong using metric than using inches. */ -#if 0 - TIFFSetField(t->tiff_file, TIFFTAG_XRESOLUTION, x_resolution); - TIFFSetField(t->tiff_file, TIFFTAG_YRESOLUTION, y_resolution); - resunit = RESUNIT_CENTIMETER; - TIFFSetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); -#else - TIFFSetField(t->tiff_file, TIFFTAG_XRESOLUTION, floorf(x_resolution*CM_PER_INCH + 0.5f)); - TIFFSetField(t->tiff_file, TIFFTAG_YRESOLUTION, floorf(y_resolution*CM_PER_INCH + 0.5f)); - resunit = RESUNIT_INCH; - TIFFSetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); -#endif - TIFFSetField(t->tiff_file, TIFFTAG_SOFTWARE, "Spandsp " SPANDSP_RELEASE_DATETIME_STRING); - if (gethostname(buf, sizeof(buf)) == 0) - TIFFSetField(t->tiff_file, TIFFTAG_HOSTCOMPUTER, buf); - -#if defined(TIFFTAG_FAXDCS) - if (s->metadata.dcs) - TIFFSetField(t->tiff_file, TIFFTAG_FAXDCS, s->metadata.dcs); -#endif - if (s->metadata.sub_address) - TIFFSetField(t->tiff_file, TIFFTAG_FAXSUBADDRESS, s->metadata.sub_address); - if (s->metadata.far_ident) - TIFFSetField(t->tiff_file, TIFFTAG_IMAGEDESCRIPTION, s->metadata.far_ident); - if (s->metadata.vendor) - TIFFSetField(t->tiff_file, TIFFTAG_MAKE, s->metadata.vendor); - if (s->metadata.model) - TIFFSetField(t->tiff_file, TIFFTAG_MODEL, s->metadata.model); - - time(&now); - tm = localtime(&now); - sprintf(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(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->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. */ - TIFFSetField(t->tiff_file, TIFFTAG_PAGENUMBER, s->current_page, 1); - /* 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; - s->metadata.image_length = 0; - switch (s->current_decoder) - { - case 0: - switch (t->compression) - { - 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) - { - 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); - } - } - } - s->metadata.image_length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); - break; - 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_T88) - case T4_COMPRESSION_T88: - s->metadata.image_length = t88_decode_get_image_length(&s->decoder.t88); - break; -#endif - 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, 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); - TIFFSetField(t->tiff_file, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6); - TIFFSetField(t->tiff_file, TIFFTAG_VERSIONYEAR, "1998"); - if (s->current_page == 0) - { - /* 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; -} -/*- End of function --------------------------------------------------------*/ - -static int open_tiff_output_file(t4_rx_state_t *s, const char *file) -{ - if ((s->tiff.tiff_file = TIFFOpen(file, "w")) == NULL) - return -1; - 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 --------------------------------------------------------*/ - -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; -#if defined(SPANDSP_SUPPORT_TIFF_FX) && TIFFLIB_VERSION >= 20120922 && defined(HAVE_TIF_DIR_H) - toff_t diroff; -#endif - - t = &s->tiff; - 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); - /* ...and write out the image... */ - 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 TIFFLIB_VERSION >= 20120922 && defined(HAVE_TIF_DIR_H) - 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); - - diroff = 0; - if (!TIFFWriteCustomDirectory(t->tiff_file, &diroff)) - 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)) - span_log(&s->logging, SPAN_LOG_WARNING, "Failed to set directory.\n"); - if (!TIFFSetField(t->tiff_file, TIFFTAG_GLOBALPARAMETERSIFD, diroff)) - 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); - } -#endif - } -#endif - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int close_tiff_output_file(t4_rx_state_t *s) -{ - int i; - t4_rx_tiff_state_t *t; - - t = &s->tiff; - /* Perform any operations needed to tidy up a written TIFF file before - closure. */ - if (s->current_page > 1) - { - /* We need to edit the TIFF directories. Until now we did not know - the total page count, so the TIFF file currently says one. Now we - need to set the correct total page count associated with each page. */ - for (i = 0; i < s->current_page; i++) - { - if (!TIFFSetDirectory(t->tiff_file, (tdir_t) i)) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to set directory to page %d.\n", s->tiff.file, i); - TIFFSetField(t->tiff_file, TIFFTAG_PAGENUMBER, i, s->current_page); - if (!TIFFWriteDirectory(t->tiff_file)) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", s->tiff.file, i); - } - } - TIFFClose(t->tiff_file); - t->tiff_file = NULL; - if (s->tiff.file) - { - /* Try not to leave a file behind, if we didn't receive any pages to - put in it. */ - if (s->current_page == 0) - { - if (remove(s->tiff.file) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to remove file.\n", s->tiff.file); - } - span_free((char *) s->tiff.file); - } - s->tiff.file = NULL; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void tiff_rx_release(t4_rx_state_t *s) -{ - if (s->tiff.tiff_file) - close_tiff_output_file(s); - if (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; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_rx_put_bit(t4_rx_state_t *s, int bit) -{ - /* We only put bit by bit for T.4-1D and T.4-2D */ - s->line_image_size += 1; - return t4_t6_decode_put_bit(&s->decoder.t4_t6, 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; - - if (s->image_put_handler) - return s->image_put_handler((void *) &s->decoder, buf, len); - - return T4_DECODE_OK; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_rx_state_t *s, int resolution) -{ - s->metadata.y_resolution = resolution; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_rx_state_t *s, int resolution) -{ - s->metadata.x_resolution = resolution; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_dcs(t4_rx_state_t *s, const char *dcs) -{ - s->metadata.dcs = (dcs && dcs[0]) ? dcs : NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_sub_address(t4_rx_state_t *s, const char *sub_address) -{ - s->metadata.sub_address = (sub_address && sub_address[0]) ? sub_address : NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_far_ident(t4_rx_state_t *s, const char *ident) -{ - s->metadata.far_ident = (ident && ident[0]) ? ident : NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_vendor(t4_rx_state_t *s, const char *vendor) -{ - s->metadata.vendor = vendor; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_rx_set_model(t4_rx_state_t *s, const char *model) -{ - s->metadata.model = model; -} -/*- End of function --------------------------------------------------------*/ - -static bool select_tiff_compression(t4_rx_state_t *s, int output_image_type) -{ - 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)))) - { - 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_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_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->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->metadata.image_width = width; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_handler_t handler, void *user_data) -{ - s->row_handler = handler; - s->row_handler_user_data = user_data; - switch (s->current_decoder) - { - 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_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; -} -/*- End of function --------------------------------------------------------*/ - -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->compression = s->metadata.compression; - switch (s->current_decoder) - { - 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); - t->image_type = t->type; - t->image_width = t->width; - t->image_length = t->length; - t->line_image_size = t4_t6_decode_get_compressed_image_size(&s->decoder.t4_t6)/8; - 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_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); - t->image_type = t->type; - t->image_width = t->width; - 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_compression_to_str(s->metadata.compression)); - - switch (s->current_decoder) - { - 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_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; - 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_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; - - time (&s->tiff.page_start_time); - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int tiff_row_write_handler(void *user_data, const uint8_t buf[], size_t len) -{ - t4_rx_state_t *s; - uint8_t *t; - - s = (t4_rx_state_t *) user_data; - if (buf && len > 0) - { - if (s->tiff.image_size + len >= s->tiff.image_buffer_size) - { - 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; - } - memcpy(&s->tiff.image_buffer[s->tiff.image_size], buf, len); - s->tiff.image_size += len; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) -{ - int length; - - length = 0; - - if (s->image_put_handler) - s->image_put_handler((void *) &s->decoder, NULL, 0); - - switch (s->current_decoder) - { - 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_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) - return -1; - - if (s->tiff.tiff_file) - { - if (write_tiff_image(s) == 0) - s->current_page++; - s->tiff.image_size = 0; - } - else - { - s->current_page++; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t4_rx_get_logging_state(t4_rx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t4_rx_state_t *) t4_rx_init(t4_rx_state_t *s, const char *file, int supported_output_compressions) -{ - bool alloced; - - alloced = false; - if (s == NULL) - { - if ((s = (t4_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - alloced = true; - } -#if defined(SPANDSP_SUPPORT_TIFF_FX) - TIFF_FX_init(); -#endif - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "T.4"); - - span_log(&s->logging, SPAN_LOG_FLOW, "Start rx document\n"); - - 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; - s->row_handler_user_data = s; - - if (file) - { - s->tiff.pages_in_file = 0; - if (open_tiff_output_file(s, file) < 0) - { - if (alloced) - span_free(s); - return NULL; - } - /* Save the file name for logging reports. */ - s->tiff.file = strdup(file); - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s) -{ - if (s->tiff.file) - tiff_rx_release(s); - release_current_decoder(s); - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_rx_free(t4_rx_state_t *s) -{ - int ret; - - ret = t4_rx_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_decode.c b/libs/spandsp/src/t4_t6_decode.c deleted file mode 100644 index 6b2d8c34a9..0000000000 --- a/libs/spandsp/src/t4_t6_decode.c +++ /dev/null @@ -1,894 +0,0 @@ -//#define T4_STATE_DEBUGGING -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_t6_encode.c - ITU T.4 and T.6 FAX image decompression - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2007 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. - */ - -/* - * This file has origins in the T.4 and T.6 support in libtiff, which requires - * the following notice in any derived source code: - * - * Copyright (c) 1990-1997 Sam Leffler - * Copyright (c) 1991-1997 Silicon Graphics, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that (i) the above copyright notices and this permission notice appear in - * all copies of the software and related documentation, and (ii) the names of - * Sam Leffler and Silicon Graphics may not be used in any advertising or - * publicity relating to the software without the specific, prior written - * permission of Sam Leffler and Silicon Graphics. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR - * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, - * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF - * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - * - * Decoder support is derived from code in Frank Cringle's viewfax program; - * Copyright (C) 1990, 1995 Frank D. Cringle. - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" - -/*! The number of centimetres in one inch */ -#define CM_PER_INCH 2.54f - -/*! The number of EOLs to expect at the end of a T.4 page */ -#define EOLS_TO_END_ANY_RX_PAGE 6 -/*! The number of EOLs to check at the end of a T.4 page */ -#define EOLS_TO_END_T4_RX_PAGE 5 -/*! The number of EOLs to check at the end of a T.6 page */ -#define EOLS_TO_END_T6_RX_PAGE 2 - -#include "t4_t6_decode_states.h" - -#if defined(T4_STATE_DEBUGGING) -static void STATE_TRACE(const char *format, ...) -{ - va_list arg_ptr; - - va_start(arg_ptr, format); - vprintf(format, arg_ptr); - va_end(arg_ptr); -} -/*- End of function --------------------------------------------------------*/ -#else -#define STATE_TRACE(...) /**/ -#endif - -static int free_buffers(t4_t6_decode_state_t *s) -{ - if (s->cur_runs) - { - span_free(s->cur_runs); - s->cur_runs = NULL; - } - if (s->ref_runs) - { - span_free(s->ref_runs); - s->ref_runs = NULL; - } - if (s->row_buf) - { - span_free(s->row_buf); - s->row_buf = NULL; - } - s->bytes_per_row = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void add_run_to_row(t4_t6_decode_state_t *s) -{ - if (s->run_length >= 0) - { - s->row_len += s->run_length; - /* Don't allow rows to grow too long, and overflow the buffers */ - if (s->row_len <= s->image_width) - s->cur_runs[s->a_cursor++] = s->run_length; - } - s->run_length = 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void update_row_bit_info(t4_t6_decode_state_t *s) -{ - if (s->row_bits > s->max_row_bits) - s->max_row_bits = s->row_bits; - if (s->row_bits < s->min_row_bits) - s->min_row_bits = s->row_bits; - s->row_bits = 0; -} -/*- End of function --------------------------------------------------------*/ - -static int put_decoded_row(t4_t6_decode_state_t *s) -{ - static const int msbmask[9] = - { - 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff - }; - uint32_t i; - uint32_t *p; - int fudge; - int x; - int j; - int row_pos; - - if (s->run_length) - add_run_to_row(s); - update_row_bit_info(s); -#if defined(T4_STATE_DEBUGGING) - /* Dump the runs of black and white for analysis */ - { - int total; - - total = 0; - for (x = 0; x < s->b_cursor; x++) - total += s->ref_runs[x]; - printf("Ref (%d)", total); - for (x = 0; x < s->b_cursor; x++) - printf(" %" PRIu32, s->ref_runs[x]); - printf("\n"); - total = 0; - for (x = 0; x < s->a_cursor; x++) - total += s->cur_runs[x]; - printf("Cur (%d)", total); - for (x = 0; x < s->a_cursor; x++) - printf(" %" PRIu32, s->cur_runs[x]); - printf("\n"); - } -#endif - row_pos = 0; - if (s->row_len == s->image_width) - { - STATE_TRACE("%d Good row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D"); - if (s->curr_bad_row_run) - { - if (s->curr_bad_row_run > s->longest_bad_row_run) - s->longest_bad_row_run = s->curr_bad_row_run; - s->curr_bad_row_run = 0; - } - /* Convert the runs to a bit image of the row */ - /* White/black/white... runs, always starting with white. That means the first run could be - zero length. */ - for (x = 0, fudge = 0; x < s->a_cursor; x++, fudge ^= 0xFF) - { - i = s->cur_runs[x]; - if ((int) i >= s->pixels) - { - s->pixel_stream = (s->pixel_stream << s->pixels) | (msbmask[s->pixels] & fudge); - for (i += (8 - s->pixels); i >= 8; i -= 8) - { - s->pixels = 8; - s->row_buf[row_pos++] = (uint8_t) s->pixel_stream; - s->pixel_stream = fudge; - } - } - s->pixel_stream = (s->pixel_stream << i) | (msbmask[i] & fudge); - s->pixels -= i; - } - s->image_length++; - } - else - { - STATE_TRACE("%d Bad row - %d %s\n", s->image_length, s->row_len, (s->row_is_2d) ? "2D" : "1D"); - /* Try to clean up the bad runs, and produce something reasonable as the reference - row for the next row. Use a copy of the previous good row as the actual current - row. If the row only fell apart near the end, reusing it might be the best - solution. */ - for (j = 0, fudge = 0; j < s->a_cursor && fudge < s->image_width; j++) - fudge += s->cur_runs[j]; - if (fudge < s->image_width) - { - /* Try to pad with white, and avoid black, to minimise mess on the image. */ - if ((s->a_cursor & 1)) - { - /* We currently finish in white. We could extend that, but it is probably of - the right length. Changing it would only further mess up what happens in the - next row. It seems better to add a black spot, and an extra white run. */ - s->cur_runs[s->a_cursor++] = 1; - fudge++; - if (fudge < s->image_width) - s->cur_runs[s->a_cursor++] = s->image_width - fudge; - } - else - { - /* We currently finish on black, so we add an extra white run to fill out the line. */ - s->cur_runs[s->a_cursor++] = s->image_width - fudge; - } - } - else - { - /* Trim the last element to align with the proper image width */ - s->cur_runs[s->a_cursor] += (s->image_width - fudge); - } - /* Ensure there is a previous line to copy from. */ - /* Reuse the previous row as the current one. If this is the first row - the row buffer will already contain a suitable white row */ - s->image_length++; - s->bad_rows++; - s->curr_bad_row_run++; - } - - /* Pad the row as it becomes the reference row, so there are no odd runs to pick up if we - step off the end of the list. */ - s->cur_runs[s->a_cursor] = 0; - s->cur_runs[s->a_cursor + 1] = 0; - - /* Swap the buffers */ - p = s->cur_runs; - s->cur_runs = s->ref_runs; - s->ref_runs = p; - - s->b_cursor = 1; - s->a_cursor = 0; - s->b1 = s->ref_runs[0]; - s->a0 = 0; - - s->run_length = 0; - if (s->row_write_handler) - return s->row_write_handler(s->row_write_user_data, s->row_buf, s->bytes_per_row); - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void drop_rx_bits(t4_t6_decode_state_t *s, int bits) -{ - /* Only remove one bit right now. The rest need to be removed step by step, - checking for a misaligned EOL along the way. This is time consuming, but - if we don't do it a single bit error can severely damage an image. */ - s->row_bits += bits; - s->rx_skip_bits += (bits - 1); - s->rx_bits--; - s->rx_bitstream >>= 1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void force_drop_rx_bits(t4_t6_decode_state_t *s, int bits) -{ - /* This should only be called to drop the bits of an EOL, as that is the - only place where it is safe to drop them all at once. */ - s->row_bits += bits; - s->rx_skip_bits = 0; - s->rx_bits -= bits; - s->rx_bitstream >>= bits; -} -/*- End of function --------------------------------------------------------*/ - -static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) -{ - int bits; - int old_a0; - - /* We decompress bit by bit, as the data stream is received. We need to - scan continuously for EOLs, so we might as well work this way. */ - s->rx_bitstream |= (bit_string << s->rx_bits); - /* The longest item we need to scan for is 13 bits long (a 2D EOL), so we - need a minimum of 13 bits in the buffer to proceed with any bit stream - analysis. */ - if ((s->rx_bits += quantity) < 13) - 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; - /* Check if the image hasn't even started. */ - if (s->consecutive_eols < 0) - { - /* We are waiting for the very first EOL (1D or 2D only). */ - /* We need to take this bit by bit, as the EOL could be anywhere, - and any junk could preceed it. */ - while ((s->rx_bitstream & 0xFFF) != 0x800) - { - s->rx_bitstream >>= 1; - if (--s->rx_bits < 13) - 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_T4_1D) - { - s->row_is_2d = false; - force_drop_rx_bits(s, 12); - } - else - { - s->row_is_2d = !(s->rx_bitstream & 0x1000); - force_drop_rx_bits(s, 13); - } - } - } - - while (s->rx_bits >= 13) - { - /* We need to check for EOLs bit by bit through the whole stream. If - we just try looking between code words, we will miss an EOL when a bit - error has throw the code words completely out of step. The can mean - recovery takes many lines, and the image gets really messed up. */ - /* Although EOLs are not inserted at the end of each row of a T.6 image, - they are still perfectly valid, and can terminate an image. */ - if ((s->rx_bitstream & 0x0FFF) == 0x0800) - { - STATE_TRACE("EOL\n"); - if (s->row_len == 0) - { - /* A zero length row - i.e. 2 consecutive EOLs - is distinctly - the end of page condition. That's all we actually get on a - T.6 page. However, there are a minimum of 6 EOLs at the end of - any T.4 page. We can look for more than 2 EOLs in case bit - errors simulate the end of page condition at the wrong point. - Such robust checking is irrelevant for a T.6 page, as it should - be error free. */ - /* Note that for a T.6 page we should get here on the very first - EOL, as the row length should be zero at that point. Therefore - we should count up both EOLs, unless there is some bogus partial - row ahead of them. */ - s->consecutive_eols++; - 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; - } - } - else - { - if (s->consecutive_eols >= EOLS_TO_END_T4_RX_PAGE) - { - s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; - return true; - } - } - } - else - { - /* The EOLs are not back-to-back, so they are not part of the - end of page condition. */ - if (s->run_length > 0) - add_run_to_row(s); - s->consecutive_eols = 0; - if (put_decoded_row(s)) - return true; - } - if (s->encoding == T4_COMPRESSION_T4_2D) - { - s->row_is_2d = !(s->rx_bitstream & 0x1000); - force_drop_rx_bits(s, 13); - } - else - { - force_drop_rx_bits(s, 12); - } - s->in_black = false; - s->black_white = 0; - s->run_length = 0; - s->row_len = 0; - continue; - } - if (s->rx_skip_bits) - { - /* We are clearing out the remaining bits of the last code word we - absorbed. */ - s->rx_skip_bits--; - s->rx_bits--; - s->rx_bitstream >>= 1; - continue; - } - if (s->row_is_2d && s->black_white == 0) - { - bits = s->rx_bitstream & 0x7F; - STATE_TRACE("State %d, %d - ", - t4_2d_table[bits].state, - t4_2d_table[bits].width); - if (s->row_len >= s->image_width) - { - drop_rx_bits(s, t4_2d_table[bits].width); - continue; - } - if (s->a_cursor) - { - /* Move past a0, always staying on the current colour */ - for ( ; s->b1 <= s->a0; s->b_cursor += 2) - s->b1 += (s->ref_runs[s->b_cursor] + s->ref_runs[s->b_cursor + 1]); - } - switch (t4_2d_table[bits].state) - { - case S_Horiz: - STATE_TRACE("Horiz %d %d %d\n", - s->image_width, - s->a0, - s->a_cursor); - /* We now need to extract a white/black or black/white pair of runs, using the 1D - method. If the first of the pair takes us exactly to the end of the row, there - should still be a zero length element for the second of the pair. */ - s->in_black = s->a_cursor & 1; - s->black_white = 2; - break; - case S_Vert: - STATE_TRACE("Vert[%d] %d %d %d %d\n", - t4_2d_table[bits].param, - s->image_width, - s->a0, - s->b1, - s->run_length); - old_a0 = s->a0; - s->a0 = s->b1 + t4_2d_table[bits].param; - /* We need to check if a bad or malicious image is failing to move forward along the row. - Going back is obviously bad. We also need to avoid a stall on the spot, except for the - special case of the start of the row. Zero movement as the very first element in the - row is perfectly normal. */ - if (s->a0 <= old_a0) - { - if (s->a0 < old_a0 || s->b_cursor > 1) - { - /* Undo the update we just started, and carry on as if this code does not exist */ - /* TODO: we really should record that something wasn't right at this point. */ - s->a0 = old_a0; - break; - } - } - s->run_length += (s->a0 - old_a0); - add_run_to_row(s); - /* We need to move one step in one direction or the other, to change to the - opposite colour */ - if (t4_2d_table[bits].param >= 0) - { - s->b1 += s->ref_runs[s->b_cursor++]; - } - else - { - if (s->b_cursor) - s->b1 -= s->ref_runs[--s->b_cursor]; - } - break; - case S_Pass: - STATE_TRACE("Pass %d %d %d %d %d\n", - s->image_width, - s->a0, - s->b1, - s->ref_runs[s->b_cursor], - s->ref_runs[s->b_cursor + 1]); - s->b1 += s->ref_runs[s->b_cursor++]; - old_a0 = s->a0; - s->a0 = s->b1; - s->run_length += (s->a0 - old_a0); - s->b1 += s->ref_runs[s->b_cursor++]; - break; - case S_Ext: - /* We do not currently handle any kind of extension */ - STATE_TRACE("Ext %d %d %d 0x%x\n", - s->image_width, - s->a0, - ((s->rx_bitstream >> t4_2d_table[bits].width) & 0x7), - s->rx_bitstream); - /* TODO: The uncompressed option should be implemented. */ - break; - case S_Null: - STATE_TRACE("Null\n"); - break; - default: - STATE_TRACE("Unexpected T.4 state\n"); - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected T.4 state %d\n", t4_2d_table[bits].state); - break; - } - drop_rx_bits(s, t4_2d_table[bits].width); - } - else - { - if (s->in_black) - { - bits = s->rx_bitstream & 0x1FFF; - STATE_TRACE("State %d, %d - Black %d %d %d\n", - t4_1d_black_table[bits].state, - t4_1d_black_table[bits].width, - s->image_width, - s->a0, - t4_1d_black_table[bits].param); - switch (t4_1d_black_table[bits].state) - { - case S_MakeUpB: - case S_MakeUp: - s->run_length += t4_1d_black_table[bits].param; - s->a0 += t4_1d_black_table[bits].param; - break; - case S_TermB: - s->in_black = false; - if (s->row_len < s->image_width) - { - s->run_length += t4_1d_black_table[bits].param; - s->a0 += t4_1d_black_table[bits].param; - add_run_to_row(s); - } - if (s->black_white) - s->black_white--; - break; - default: - /* Bad black */ - s->black_white = 0; - break; - } - drop_rx_bits(s, t4_1d_black_table[bits].width); - } - else - { - bits = s->rx_bitstream & 0xFFF; - STATE_TRACE("State %d, %d - White %d %d %d\n", - t4_1d_white_table[bits].state, - t4_1d_white_table[bits].width, - s->image_width, - s->a0, - t4_1d_white_table[bits].param); - switch (t4_1d_white_table[bits].state) - { - case S_MakeUpW: - case S_MakeUp: - s->run_length += t4_1d_white_table[bits].param; - s->a0 += t4_1d_white_table[bits].param; - break; - case S_TermW: - s->in_black = true; - if (s->row_len < s->image_width) - { - s->run_length += t4_1d_white_table[bits].param; - s->a0 += t4_1d_white_table[bits].param; - add_run_to_row(s); - } - if (s->black_white) - s->black_white--; - break; - default: - /* Bad white */ - s->black_white = 0; - break; - } - drop_rx_bits(s, t4_1d_white_table[bits].width); - } - } - if (s->a0 >= s->image_width) - s->a0 = s->image_width - 1; - - 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 - cause us to do bad things. Bad encoders have actually been seen, which - demand such protection. */ - if (s->black_white == 0 && s->row_len >= s->image_width) - { - STATE_TRACE("EOL T.6\n"); - if (s->run_length > 0) - add_run_to_row(s); - if (put_decoded_row(s)) - return true; - s->in_black = false; - s->black_white = 0; - s->run_length = 0; - s->row_len = 0; - } - } - } - return false; -} -/*- End of function --------------------------------------------------------*/ - -static void t4_t6_decode_rx_status(t4_t6_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: - t4_t6_decode_put(s, NULL, 0); - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected rx status - %d!\n", status); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -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; - } - s->compressed_image_size++; - if (put_bits(s, bit & 1, 1)) - return T4_DECODE_OK; - return T4_DECODE_MORE_DATA; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_put(t4_t6_decode_state_t *s, const uint8_t buf[], size_t len) -{ - int i; - uint8_t byte; - - if (len == 0) - { - /* Finalise the image */ - if (s->consecutive_eols != EOLS_TO_END_ANY_RX_PAGE) - { - /* Push enough zeros (13) through the decoder to flush out any remaining codes */ - put_bits(s, 0, 8); - put_bits(s, 0, 5); - } - if (s->curr_bad_row_run) - { - if (s->curr_bad_row_run > s->longest_bad_row_run) - s->longest_bad_row_run = s->curr_bad_row_run; - s->curr_bad_row_run = 0; - } - /* Don't worry about the return value here. We are finishing anyway. */ - if (s->row_write_handler) - s->row_write_handler(s->row_write_user_data, NULL, 0); - s->rx_bits = 0; - s->rx_skip_bits = 0; - s->rx_bitstream = 0; - s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; - return T4_DECODE_OK; - } - - for (i = 0; i < len; i++) - { - s->compressed_image_size += 8; - byte = buf[i]; - if (put_bits(s, byte & 0xFF, 8)) - return T4_DECODE_OK; - } - return T4_DECODE_MORE_DATA; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_set_row_write_handler(t4_t6_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; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_set_encoding(t4_t6_decode_state_t *s, int encoding) -{ - switch (encoding) - { - case T4_COMPRESSION_T4_1D: - case T4_COMPRESSION_T4_2D: - case T4_COMPRESSION_T6: - s->encoding = encoding; - return 0; - } - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_width(t4_t6_decode_state_t *s) -{ - return s->image_width; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t4_t6_decode_get_image_length(t4_t6_decode_state_t *s) -{ - return s->image_length; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_get_compressed_image_size(t4_t6_decode_state_t *s) -{ - return s->compressed_image_size; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t4_t6_decode_get_logging_state(t4_t6_decode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width) -{ - int bytes_per_row; - int run_space; - uint32_t *bufptr; - uint8_t *bufptr8; - - /* Calculate the scanline/tile width. */ - run_space = (image_width + 4)*sizeof(uint32_t); - 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 *) span_realloc(s->cur_runs, run_space)) == NULL) - return -1; - s->cur_runs = bufptr; - if ((bufptr = (uint32_t *) span_realloc(s->ref_runs, run_space)) == NULL) - return -1; - s->ref_runs = bufptr; - s->image_width = image_width; - } - bytes_per_row = (image_width + 7)/8; - if (bytes_per_row != s->bytes_per_row) - { - 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; - } - - s->rx_bits = 0; - s->rx_skip_bits = 0; - s->rx_bitstream = 0; - s->row_bits = 0; - s->min_row_bits = INT_MAX; - s->max_row_bits = 0; - - s->compressed_image_size = 0; - s->bad_rows = 0; - s->longest_bad_row_run = 0; - s->curr_bad_row_run = 0; - s->image_length = 0; - s->pixel_stream = 0; - s->pixels = 8; - - s->row_len = 0; - 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_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_T6) ? 0 : -1; - - if (s->cur_runs) - memset(s->cur_runs, 0, run_space); - /* Initialise the reference line to all white */ - if (s->ref_runs) - { - memset(s->ref_runs, 0, run_space); - s->ref_runs[0] = s->image_width; - } - if (s->row_buf) - memset(s->row_buf, 0, s->bytes_per_row); - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t4_t6_decode_state_t *) t4_t6_decode_init(t4_t6_decode_state_t *s, - int encoding, - int image_width, - t4_row_write_handler_t handler, - void *user_data) -{ - if (s == NULL) - { - if ((s = (t4_t6_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.4/T.6"); - - s->encoding = encoding; - s->row_write_handler = handler; - s->row_write_user_data = user_data; - t4_t6_decode_restart(s, image_width); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_release(t4_t6_decode_state_t *s) -{ - free_buffers(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_decode_free(t4_t6_decode_state_t *s) -{ - int ret; - - ret = t4_t6_decode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_decode_states.h b/libs/spandsp/src/t4_t6_decode_states.h deleted file mode 100644 index daf0e1a711..0000000000 --- a/libs/spandsp/src/t4_t6_decode_states.h +++ /dev/null @@ -1,12484 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_t6_decode_states.h - state tables for T.4/T.6 FAX image decoding - * - * 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. - */ - -/* Legitimate runs of zero bits which are the tail end of one code - plus the start of the next code do not exceed 10 bits. */ - -/* Finite state machine state codes */ -enum -{ - S_Null = 0, - S_Pass = 1, - S_Horiz = 2, - S_Vert = 3, - S_Ext = 4, - S_TermW = 5, - S_TermB = 6, - S_MakeUpW = 7, - S_MakeUpB = 8, - S_MakeUp = 9, - S_EOL = 10 -}; - -/*! T.4 finite state machine state table entry */ -typedef struct -{ - /*! State */ - uint8_t state; - /*! Width of code in bits */ - uint8_t width; - /*! Run length in bits */ - int16_t param; -} t4_table_entry_t; - -static const t4_table_entry_t t4_2d_table[128] = -{ - {S_Null, 1, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Vert, 6, -2}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Vert, 7, -3}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Vert, 6, 2}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Ext, 7, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Vert, 6, -2}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Vert, 7, 3}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Vert, 6, 2}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0}, - {S_Pass, 4, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, -1}, - {S_Vert, 1, 0}, - {S_Horiz, 3, 0}, - {S_Vert, 1, 0}, - {S_Vert, 3, 1}, - {S_Vert, 1, 0} -}; - -static const t4_table_entry_t t4_1d_white_table[4096] = -{ - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 11, 1792}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 11, 1856}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2112}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2368}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 1984}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 11, 1920}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2240}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2496}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_EOL, 12, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 11, 1792}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 11, 1856}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2176}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2432}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2048}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 11, 1920}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1472}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1216}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 960}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 704}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2304}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 832}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1600}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1344}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1088}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_Null, 1, 0}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 39}, - {S_TermW, 6, 16}, - {S_MakeUpW, 8, 576}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 55}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 45}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 53}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 448}, - {S_TermW, 4, 6}, - {S_TermW, 8, 35}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 51}, - {S_TermW, 6, 15}, - {S_TermW, 8, 63}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1536}, - {S_TermW, 4, 5}, - {S_TermW, 8, 43}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1280}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 29}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 33}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 49}, - {S_TermW, 6, 14}, - {S_TermW, 8, 61}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 47}, - {S_TermW, 4, 3}, - {S_TermW, 8, 59}, - {S_TermW, 4, 5}, - {S_TermW, 8, 41}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1024}, - {S_TermW, 4, 6}, - {S_TermW, 8, 31}, - {S_TermW, 5, 8}, - {S_TermW, 8, 57}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 9, 768}, - {S_TermW, 4, 6}, - {S_TermW, 8, 37}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 320}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_MakeUp, 12, 2560}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 7, 20}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 24}, - {S_TermW, 6, 14}, - {S_TermW, 7, 28}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 23}, - {S_TermW, 4, 3}, - {S_TermW, 7, 27}, - {S_TermW, 4, 5}, - {S_TermW, 8, 40}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 896}, - {S_TermW, 4, 6}, - {S_TermW, 7, 19}, - {S_TermW, 5, 8}, - {S_TermW, 8, 56}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 46}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 8, 54}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 512}, - {S_TermW, 4, 6}, - {S_TermW, 8, 36}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 52}, - {S_TermW, 6, 15}, - {S_TermW, 8, 0}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_MakeUpW, 9, 1728}, - {S_TermW, 4, 5}, - {S_TermW, 8, 44}, - {S_TermW, 6, 17}, - {S_MakeUpW, 9, 1408}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 30}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 6, 12}, - {S_TermW, 5, 9}, - {S_MakeUpW, 6, 1664}, - {S_TermW, 4, 6}, - {S_TermW, 8, 34}, - {S_MakeUpW, 5, 128}, - {S_TermW, 8, 50}, - {S_TermW, 6, 14}, - {S_TermW, 8, 62}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 8, 48}, - {S_TermW, 4, 3}, - {S_TermW, 8, 60}, - {S_TermW, 4, 5}, - {S_TermW, 8, 42}, - {S_TermW, 6, 16}, - {S_MakeUpW, 9, 1152}, - {S_TermW, 4, 6}, - {S_TermW, 8, 32}, - {S_TermW, 5, 8}, - {S_TermW, 8, 58}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 7, 22}, - {S_TermW, 4, 3}, - {S_TermW, 5, 11}, - {S_TermW, 4, 5}, - {S_TermW, 7, 26}, - {S_TermW, 5, 9}, - {S_MakeUpW, 8, 640}, - {S_TermW, 4, 6}, - {S_TermW, 8, 38}, - {S_MakeUpW, 5, 128}, - {S_TermW, 7, 25}, - {S_TermW, 6, 15}, - {S_MakeUpW, 8, 384}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7}, - {S_TermW, 6, 13}, - {S_TermW, 4, 3}, - {S_TermW, 7, 18}, - {S_TermW, 4, 5}, - {S_TermW, 7, 21}, - {S_TermW, 6, 17}, - {S_MakeUpW, 7, 256}, - {S_TermW, 4, 6}, - {S_TermW, 6, 1}, - {S_TermW, 5, 8}, - {S_MakeUpW, 6, 192}, - {S_MakeUpW, 5, 64}, - {S_TermW, 5, 10}, - {S_TermW, 4, 4}, - {S_TermW, 4, 2}, - {S_TermW, 4, 7} -}; - -static const t4_table_entry_t t4_1d_black_table[8192] = -{ - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1792}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 23}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 20}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 25}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 128}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 56}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 30}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1856}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 57}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 21}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 54}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 52}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 48}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2112}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 44}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 36}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 384}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 28}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 60}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 40}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2368}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 1984}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 50}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 34}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1664}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 26}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1408}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 32}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1920}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 61}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 42}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1024}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 768}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 62}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2240}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 46}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 38}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 512}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 19}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 24}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 22}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2496}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_EOL, 12, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1792}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 23}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 20}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 25}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 192}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1280}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 31}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1856}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 58}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 21}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 896}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 640}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 49}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2176}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 45}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 37}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 448}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 29}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1536}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 41}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2432}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2048}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 51}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 35}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 320}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 27}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 59}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 33}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1920}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 256}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 43}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1152}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 55}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 63}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2304}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 47}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 39}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 53}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 19}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 24}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 22}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2560}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1792}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 23}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 20}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 25}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 128}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 56}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 30}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1856}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 57}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 21}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 54}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 52}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 48}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2112}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 44}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 36}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 384}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 28}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 60}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 40}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2368}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 1984}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 50}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 34}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1728}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 26}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1472}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 32}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1920}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 61}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 42}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1088}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 832}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 62}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2240}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 46}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 38}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 576}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 19}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 24}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 22}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2496}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_EOL, 12, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1792}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 23}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 20}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 25}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 192}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1344}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 31}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1856}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 58}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 21}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 960}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 704}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 49}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2176}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 45}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 37}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 448}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 29}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1600}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 41}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2432}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 18}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 17}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2048}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 51}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 35}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 320}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 27}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 59}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 33}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 11, 1920}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 12, 256}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 43}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 13, 1216}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 9, 15}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 55}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 63}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2304}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 47}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 39}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 12, 53}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_Null, 1, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 13}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 19}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 24}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 11, 22}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUp, 12, 2560}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 10}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 16}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 10, 0}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_MakeUpB, 10, 64}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 9}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 11}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 8, 14}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 6, 8}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 7, 12}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 6}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2}, - {S_TermB, 5, 7}, - {S_TermB, 2, 3}, - {S_TermB, 3, 1}, - {S_TermB, 2, 2}, - {S_TermB, 4, 5}, - {S_TermB, 2, 3}, - {S_TermB, 3, 4}, - {S_TermB, 2, 2} -}; - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_encode.c b/libs/spandsp/src/t4_t6_encode.c deleted file mode 100644 index b62b2d5b18..0000000000 --- a/libs/spandsp/src/t4_t6_encode.c +++ /dev/null @@ -1,1189 +0,0 @@ -//#define T4_STATE_DEBUGGING -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_t6_encode.c - ITU T.4 and T.6 FAX image compression - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2007 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. - */ - -/* - * This file has origins in the T.4 and T.6 support in libtiff, which requires - * the following notice in any derived source code: - * - * Copyright (c) 1990-1997 Sam Leffler - * Copyright (c) 1991-1997 Silicon Graphics, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that (i) the above copyright notices and this permission notice appear in - * all copies of the software and related documentation, and (ii) the names of - * Sam Leffler and Silicon Graphics may not be used in any advertising or - * publicity relating to the software without the specific, prior written - * permission of Sam Leffler and Silicon Graphics. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR - * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, - * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF - * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" - -/*! The number of EOLs to be sent at the end of a T.4 page */ -#define EOLS_TO_END_T4_TX_PAGE 6 -/*! The number of EOLs to be sent at the end of a T.6 page */ -#define EOLS_TO_END_T6_TX_PAGE 2 - -#if defined(T4_STATE_DEBUGGING) -static void STATE_TRACE(const char *format, ...) -{ - va_list arg_ptr; - - va_start(arg_ptr, format); - vprintf(format, arg_ptr); - va_end(arg_ptr); -} -/*- End of function --------------------------------------------------------*/ -#else -#define STATE_TRACE(...) /**/ -#endif - -/*! T.4 run length table entry */ -typedef struct -{ - /*! Length of T.4 code, in bits */ - uint16_t length; - /*! T.4 code */ - uint16_t code; - /*! Run length, in bits */ - int16_t run_length; -} t4_run_table_entry_t; - -/* Legitimate runs of zero bits which are the tail end of one code - plus the start of the next code do not exceed 10 bits. */ - -/* - * Note that these tables are ordered such that the index into the table - * is known to be either the run length, or (run length / 64) + a fixed - * offset. - */ -static const t4_run_table_entry_t t4_white_codes[] = -{ - { 8, 0x00AC, 0}, /* 0011 0101 */ - { 6, 0x0038, 1}, /* 0001 11 */ - { 4, 0x000E, 2}, /* 0111 */ - { 4, 0x0001, 3}, /* 1000 */ - { 4, 0x000D, 4}, /* 1011 */ - { 4, 0x0003, 5}, /* 1100 */ - { 4, 0x0007, 6}, /* 1110 */ - { 4, 0x000F, 7}, /* 1111 */ - { 5, 0x0019, 8}, /* 1001 1 */ - { 5, 0x0005, 9}, /* 1010 0 */ - { 5, 0x001C, 10}, /* 0011 1 */ - { 5, 0x0002, 11}, /* 0100 0 */ - { 6, 0x0004, 12}, /* 0010 00 */ - { 6, 0x0030, 13}, /* 0000 11 */ - { 6, 0x000B, 14}, /* 1101 00 */ - { 6, 0x002B, 15}, /* 1101 01 */ - { 6, 0x0015, 16}, /* 1010 10 */ - { 6, 0x0035, 17}, /* 1010 11 */ - { 7, 0x0072, 18}, /* 0100 111 */ - { 7, 0x0018, 19}, /* 0001 100 */ - { 7, 0x0008, 20}, /* 0001 000 */ - { 7, 0x0074, 21}, /* 0010 111 */ - { 7, 0x0060, 22}, /* 0000 011 */ - { 7, 0x0010, 23}, /* 0000 100 */ - { 7, 0x000A, 24}, /* 0101 000 */ - { 7, 0x006A, 25}, /* 0101 011 */ - { 7, 0x0064, 26}, /* 0010 011 */ - { 7, 0x0012, 27}, /* 0100 100 */ - { 7, 0x000C, 28}, /* 0011 000 */ - { 8, 0x0040, 29}, /* 0000 0010 */ - { 8, 0x00C0, 30}, /* 0000 0011 */ - { 8, 0x0058, 31}, /* 0001 1010 */ - { 8, 0x00D8, 32}, /* 0001 1011 */ - { 8, 0x0048, 33}, /* 0001 0010 */ - { 8, 0x00C8, 34}, /* 0001 0011 */ - { 8, 0x0028, 35}, /* 0001 0100 */ - { 8, 0x00A8, 36}, /* 0001 0101 */ - { 8, 0x0068, 37}, /* 0001 0110 */ - { 8, 0x00E8, 38}, /* 0001 0111 */ - { 8, 0x0014, 39}, /* 0010 1000 */ - { 8, 0x0094, 40}, /* 0010 1001 */ - { 8, 0x0054, 41}, /* 0010 1010 */ - { 8, 0x00D4, 42}, /* 0010 1011 */ - { 8, 0x0034, 43}, /* 0010 1100 */ - { 8, 0x00B4, 44}, /* 0010 1101 */ - { 8, 0x0020, 45}, /* 0000 0100 */ - { 8, 0x00A0, 46}, /* 0000 0101 */ - { 8, 0x0050, 47}, /* 0000 1010 */ - { 8, 0x00D0, 48}, /* 0000 1011 */ - { 8, 0x004A, 49}, /* 0101 0010 */ - { 8, 0x00CA, 50}, /* 0101 0011 */ - { 8, 0x002A, 51}, /* 0101 0100 */ - { 8, 0x00AA, 52}, /* 0101 0101 */ - { 8, 0x0024, 53}, /* 0010 0100 */ - { 8, 0x00A4, 54}, /* 0010 0101 */ - { 8, 0x001A, 55}, /* 0101 1000 */ - { 8, 0x009A, 56}, /* 0101 1001 */ - { 8, 0x005A, 57}, /* 0101 1010 */ - { 8, 0x00DA, 58}, /* 0101 1011 */ - { 8, 0x0052, 59}, /* 0100 1010 */ - { 8, 0x00D2, 60}, /* 0100 1011 */ - { 8, 0x004C, 61}, /* 0011 0010 */ - { 8, 0x00CC, 62}, /* 0011 0011 */ - { 8, 0x002C, 63}, /* 0011 0100 */ - { 5, 0x001B, 64}, /* 1101 1 */ - { 5, 0x0009, 128}, /* 1001 0 */ - { 6, 0x003A, 192}, /* 0101 11 */ - { 7, 0x0076, 256}, /* 0110 111 */ - { 8, 0x006C, 320}, /* 0011 0110 */ - { 8, 0x00EC, 384}, /* 0011 0111 */ - { 8, 0x0026, 448}, /* 0110 0100 */ - { 8, 0x00A6, 512}, /* 0110 0101 */ - { 8, 0x0016, 576}, /* 0110 1000 */ - { 8, 0x00E6, 640}, /* 0110 0111 */ - { 9, 0x0066, 704}, /* 0110 0110 0 */ - { 9, 0x0166, 768}, /* 0110 0110 1 */ - { 9, 0x0096, 832}, /* 0110 1001 0 */ - { 9, 0x0196, 896}, /* 0110 1001 1 */ - { 9, 0x0056, 960}, /* 0110 1010 0 */ - { 9, 0x0156, 1024}, /* 0110 1010 1 */ - { 9, 0x00D6, 1088}, /* 0110 1011 0 */ - { 9, 0x01D6, 1152}, /* 0110 1011 1 */ - { 9, 0x0036, 1216}, /* 0110 1100 0 */ - { 9, 0x0136, 1280}, /* 0110 1100 1 */ - { 9, 0x00B6, 1344}, /* 0110 1101 0 */ - { 9, 0x01B6, 1408}, /* 0110 1101 1 */ - { 9, 0x0032, 1472}, /* 0100 1100 0 */ - { 9, 0x0132, 1536}, /* 0100 1100 1 */ - { 9, 0x00B2, 1600}, /* 0100 1101 0 */ - { 6, 0x0006, 1664}, /* 0110 00 */ - { 9, 0x01B2, 1728}, /* 0100 1101 1 */ - {11, 0x0080, 1792}, /* 0000 0001 000 */ - {11, 0x0180, 1856}, /* 0000 0001 100 */ - {11, 0x0580, 1920}, /* 0000 0001 101 */ - {12, 0x0480, 1984}, /* 0000 0001 0010 */ - {12, 0x0C80, 2048}, /* 0000 0001 0011 */ - {12, 0x0280, 2112}, /* 0000 0001 0100 */ - {12, 0x0A80, 2176}, /* 0000 0001 0101 */ - {12, 0x0680, 2240}, /* 0000 0001 0110 */ - {12, 0x0E80, 2304}, /* 0000 0001 0111 */ - {12, 0x0380, 2368}, /* 0000 0001 1100 */ - {12, 0x0B80, 2432}, /* 0000 0001 1101 */ - {12, 0x0780, 2496}, /* 0000 0001 1110 */ - {12, 0x0F80, 2560}, /* 0000 0001 1111 */ -}; - -static const t4_run_table_entry_t t4_black_codes[] = -{ - {10, 0x03B0, 0}, /* 0000 1101 11 */ - { 3, 0x0002, 1}, /* 010 */ - { 2, 0x0003, 2}, /* 11 */ - { 2, 0x0001, 3}, /* 10 */ - { 3, 0x0006, 4}, /* 011 */ - { 4, 0x000C, 5}, /* 0011 */ - { 4, 0x0004, 6}, /* 0010 */ - { 5, 0x0018, 7}, /* 0001 1 */ - { 6, 0x0028, 8}, /* 0001 01 */ - { 6, 0x0008, 9}, /* 0001 00 */ - { 7, 0x0010, 10}, /* 0000 100 */ - { 7, 0x0050, 11}, /* 0000 101 */ - { 7, 0x0070, 12}, /* 0000 111 */ - { 8, 0x0020, 13}, /* 0000 0100 */ - { 8, 0x00E0, 14}, /* 0000 0111 */ - { 9, 0x0030, 15}, /* 0000 1100 0 */ - {10, 0x03A0, 16}, /* 0000 0101 11 */ - {10, 0x0060, 17}, /* 0000 0110 00 */ - {10, 0x0040, 18}, /* 0000 0010 00 */ - {11, 0x0730, 19}, /* 0000 1100 111 */ - {11, 0x00B0, 20}, /* 0000 1101 000 */ - {11, 0x01B0, 21}, /* 0000 1101 100 */ - {11, 0x0760, 22}, /* 0000 0110 111 */ - {11, 0x00A0, 23}, /* 0000 0101 000 */ - {11, 0x0740, 24}, /* 0000 0010 111 */ - {11, 0x00C0, 25}, /* 0000 0011 000 */ - {12, 0x0530, 26}, /* 0000 1100 1010 */ - {12, 0x0D30, 27}, /* 0000 1100 1011 */ - {12, 0x0330, 28}, /* 0000 1100 1100 */ - {12, 0x0B30, 29}, /* 0000 1100 1101 */ - {12, 0x0160, 30}, /* 0000 0110 1000 */ - {12, 0x0960, 31}, /* 0000 0110 1001 */ - {12, 0x0560, 32}, /* 0000 0110 1010 */ - {12, 0x0D60, 33}, /* 0000 0110 1011 */ - {12, 0x04B0, 34}, /* 0000 1101 0010 */ - {12, 0x0CB0, 35}, /* 0000 1101 0011 */ - {12, 0x02B0, 36}, /* 0000 1101 0100 */ - {12, 0x0AB0, 37}, /* 0000 1101 0101 */ - {12, 0x06B0, 38}, /* 0000 1101 0110 */ - {12, 0x0EB0, 39}, /* 0000 1101 0111 */ - {12, 0x0360, 40}, /* 0000 0110 1100 */ - {12, 0x0B60, 41}, /* 0000 0110 1101 */ - {12, 0x05B0, 42}, /* 0000 1101 1010 */ - {12, 0x0DB0, 43}, /* 0000 1101 1011 */ - {12, 0x02A0, 44}, /* 0000 0101 0100 */ - {12, 0x0AA0, 45}, /* 0000 0101 0101 */ - {12, 0x06A0, 46}, /* 0000 0101 0110 */ - {12, 0x0EA0, 47}, /* 0000 0101 0111 */ - {12, 0x0260, 48}, /* 0000 0110 0100 */ - {12, 0x0A60, 49}, /* 0000 0110 0101 */ - {12, 0x04A0, 50}, /* 0000 0101 0010 */ - {12, 0x0CA0, 51}, /* 0000 0101 0011 */ - {12, 0x0240, 52}, /* 0000 0010 0100 */ - {12, 0x0EC0, 53}, /* 0000 0011 0111 */ - {12, 0x01C0, 54}, /* 0000 0011 1000 */ - {12, 0x0E40, 55}, /* 0000 0010 0111 */ - {12, 0x0140, 56}, /* 0000 0010 1000 */ - {12, 0x01A0, 57}, /* 0000 0101 1000 */ - {12, 0x09A0, 58}, /* 0000 0101 1001 */ - {12, 0x0D40, 59}, /* 0000 0010 1011 */ - {12, 0x0340, 60}, /* 0000 0010 1100 */ - {12, 0x05A0, 61}, /* 0000 0101 1010 */ - {12, 0x0660, 62}, /* 0000 0110 0110 */ - {12, 0x0E60, 63}, /* 0000 0110 0111 */ - {10, 0x03C0, 64}, /* 0000 0011 11 */ - {12, 0x0130, 128}, /* 0000 1100 1000 */ - {12, 0x0930, 192}, /* 0000 1100 1001 */ - {12, 0x0DA0, 256}, /* 0000 0101 1011 */ - {12, 0x0CC0, 320}, /* 0000 0011 0011 */ - {12, 0x02C0, 384}, /* 0000 0011 0100 */ - {12, 0x0AC0, 448}, /* 0000 0011 0101 */ - {13, 0x06C0, 512}, /* 0000 0011 0110 0 */ - {13, 0x16C0, 576}, /* 0000 0011 0110 1 */ - {13, 0x0A40, 640}, /* 0000 0010 0101 0 */ - {13, 0x1A40, 704}, /* 0000 0010 0101 1 */ - {13, 0x0640, 768}, /* 0000 0010 0110 0 */ - {13, 0x1640, 832}, /* 0000 0010 0110 1 */ - {13, 0x09C0, 896}, /* 0000 0011 1001 0 */ - {13, 0x19C0, 960}, /* 0000 0011 1001 1 */ - {13, 0x05C0, 1024}, /* 0000 0011 1010 0 */ - {13, 0x15C0, 1088}, /* 0000 0011 1010 1 */ - {13, 0x0DC0, 1152}, /* 0000 0011 1011 0 */ - {13, 0x1DC0, 1216}, /* 0000 0011 1011 1 */ - {13, 0x0940, 1280}, /* 0000 0010 1001 0 */ - {13, 0x1940, 1344}, /* 0000 0010 1001 1 */ - {13, 0x0540, 1408}, /* 0000 0010 1010 0 */ - {13, 0x1540, 1472}, /* 0000 0010 1010 1 */ - {13, 0x0B40, 1536}, /* 0000 0010 1101 0 */ - {13, 0x1B40, 1600}, /* 0000 0010 1101 1 */ - {13, 0x04C0, 1664}, /* 0000 0011 0010 0 */ - {13, 0x14C0, 1728}, /* 0000 0011 0010 1 */ - {11, 0x0080, 1792}, /* 0000 0001 000 */ - {11, 0x0180, 1856}, /* 0000 0001 100 */ - {11, 0x0580, 1920}, /* 0000 0001 101 */ - {12, 0x0480, 1984}, /* 0000 0001 0010 */ - {12, 0x0C80, 2048}, /* 0000 0001 0011 */ - {12, 0x0280, 2112}, /* 0000 0001 0100 */ - {12, 0x0A80, 2176}, /* 0000 0001 0101 */ - {12, 0x0680, 2240}, /* 0000 0001 0110 */ - {12, 0x0E80, 2304}, /* 0000 0001 0111 */ - {12, 0x0380, 2368}, /* 0000 0001 1100 */ - {12, 0x0B80, 2432}, /* 0000 0001 1101 */ - {12, 0x0780, 2496}, /* 0000 0001 1110 */ - {12, 0x0F80, 2560}, /* 0000 0001 1111 */ -}; - -static void update_row_bit_info(t4_t6_encode_state_t *s) -{ - if (s->row_bits > s->max_row_bits) - s->max_row_bits = s->row_bits; - if (s->row_bits < s->min_row_bits) - s->min_row_bits = s->row_bits; - s->row_bits = 0; -} -/*- End of function --------------------------------------------------------*/ - -static int free_buffers(t4_t6_encode_state_t *s) -{ - if (s->cur_runs) - { - span_free(s->cur_runs); - s->cur_runs = NULL; - } - if (s->ref_runs) - { - span_free(s->ref_runs); - s->ref_runs = NULL; - } - if (s->bitstream) - { - span_free(s->bitstream); - s->bitstream = NULL; - } - s->bytes_per_row = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int put_encoded_bits(t4_t6_encode_state_t *s, uint32_t bits, int length) -{ - /* We might be called with a large length value, to spew out a mass of zero bits for - minimum row length padding. */ - s->tx_bitstream |= (bits << s->tx_bits); - s->tx_bits += length; - s->row_bits += length; - while (s->tx_bits >= 8) - { - s->bitstream[s->bitstream_iptr++] = (uint8_t) s->tx_bitstream; - s->tx_bitstream >>= 8; - s->tx_bits -= 8; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -/* - * Write the sequence of codes that describes the specified span of zero's or one's. - * The appropriate table that holds the make-up and terminating codes is supplied. - */ -static __inline__ int put_1d_span(t4_t6_encode_state_t *s, int32_t span, const t4_run_table_entry_t *tab) -{ - const t4_run_table_entry_t *te; - - te = &tab[63 + (2560 >> 6)]; - while (span >= 2560 + 64) - { - if (put_encoded_bits(s, te->code, te->length)) - return -1; - span -= te->run_length; - } - te = &tab[63 + (span >> 6)]; - if (span >= 64) - { - if (put_encoded_bits(s, te->code, te->length)) - return -1; - span -= te->run_length; - } - if (put_encoded_bits(s, tab[span].code, tab[span].length)) - return -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int row_to_run_lengths(uint32_t list[], const uint8_t row[], int width) -{ - uint32_t flip; - uint32_t x; - int span; - int entry; - int frag; - int rem; - int limit; - int i; - int pos; - - /* Deal with whole words first. We know we are starting on a word boundary. */ - entry = 0; - flip = 0; - limit = (width >> 3) & ~3; - span = 0; - pos = 0; - for (i = 0; i < limit; i += sizeof(uint32_t)) - { - x = *((uint32_t *) &row[i]); - if (x != flip) - { - x = ((uint32_t) row[i] << 24) - | ((uint32_t) row[i + 1] << 16) - | ((uint32_t) row[i + 2] << 8) - | ((uint32_t) row[i + 3]); - /* We know we are going to find at least one transition. */ - frag = 31 - top_bit(x ^ flip); - pos += ((i << 3) - span + frag); - list[entry++] = pos; - x <<= frag; - flip ^= 0xFFFFFFFF; - rem = 32 - frag; - /* Now see if there are any more */ - while ((frag = 31 - top_bit(x ^ flip)) < rem) - { - pos += frag; - list[entry++] = pos; - x <<= frag; - flip ^= 0xFFFFFFFF; - rem -= frag; - } - /* Save the remainder of the word */ - span = (i << 3) + 32 - rem; - } - } - /* Now deal with some whole bytes, if there are any left. */ - limit = width >> 3; - flip &= 0xFF000000; - if (i < limit) - { - for ( ; i < limit; i++) - { - x = (uint32_t) row[i] << 24; - if (x != flip) - { - /* We know we are going to find at least one transition. */ - frag = 31 - top_bit(x ^ flip); - pos += ((i << 3) - span + frag); - list[entry++] = pos; - x <<= frag; - flip ^= 0xFF000000; - rem = 8 - frag; - /* Now see if there are any more */ - while ((frag = 31 - top_bit(x ^ flip)) < rem) - { - pos += frag; - list[entry++] = pos; - x <<= frag; - flip ^= 0xFF000000; - rem -= frag; - } - /* Save the remainder of the word */ - span = (i << 3) + 8 - rem; - } - } - } - /* Deal with any left over fractional byte. */ - span = (i << 3) - span; - if ((rem = width & 7)) - { - x = row[i]; - x <<= 24; - do - { - frag = 31 - top_bit(x ^ flip); - if (frag > rem) - frag = rem; - pos += (span + frag); - list[entry++] = pos; - x <<= frag; - span = 0; - flip ^= 0xFF000000; - rem -= frag; - } - while (rem > 0); - } - else - { - if (span) - { - pos += span; - list[entry++] = pos; - } - } -#if defined(T4_STATE_DEBUGGING) - /* Dump the runs of black and white for analysis */ - { - int prev; - int x; - - printf("Runs (%d)", list[entry - 1]); - prev = 0; - for (x = 0; x < entry; x++) - { - printf(" %" PRIu32, list[x] - prev); - prev = list[x]; - } - printf("\n"); - } -#endif - return entry; -} -/*- End of function --------------------------------------------------------*/ - -#define pixel_is_black(x,bit) (((x)[(bit) >> 3] << ((bit) & 7)) & 0x80) - -/* - * Write an EOL code to the output stream. We also handle writing the tag - * bit for the next scanline when doing 2D encoding. - */ -static void encode_eol(t4_t6_encode_state_t *s) -{ - uint32_t code; - int length; - - if (s->encoding == T4_COMPRESSION_T4_2D) - { - code = 0x0800 | ((!s->row_is_2d) << 12); - length = 13; - } - else - { - /* T.4 1D EOL, or T.6 EOFB */ - code = 0x800; - length = 12; - } - if (s->row_bits) - { - /* 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_T6) - { - if (s->row_bits + length < s->min_bits_per_row) - put_encoded_bits(s, 0, s->min_bits_per_row - (s->row_bits + length)); - } - put_encoded_bits(s, code, length); - update_row_bit_info(s); - } - else - { - /* We don't pad zero length rows. They are the consecutive EOLs which end a page. */ - put_encoded_bits(s, code, length); - /* Don't do the full update row bit info, or the minimum suddenly drops to the - length of an EOL. Just clear the row bits, so we treat the next EOL as an - end of page EOL, with no padding. */ - s->row_bits = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -/* - * 2D-encode a row of pixels. Consult ITU specification T.4 for the algorithm. - */ -static void encode_2d_row(t4_t6_encode_state_t *s, const uint8_t *row_buf) -{ - static const t4_run_table_entry_t codes[] = - { - {7, 0x60, 0}, /* VR3 0000 011 */ - {6, 0x30, 0}, /* VR2 0000 11 */ - {3, 0x06, 0}, /* VR1 011 */ - {1, 0x01, 0}, /* V0 1 */ - {3, 0x02, 0}, /* VL1 010 */ - {6, 0x10, 0}, /* VL2 0000 10 */ - {7, 0x20, 0}, /* VL3 0000 010 */ - {3, 0x04, 0}, /* horizontal 001 */ - {4, 0x08, 0} /* pass 0001 */ - }; - - /* The reference or starting changing element on the coding line. At the start of the coding - line, a0 is set on an imaginary white changing element situated just before the first element - on the line. During the coding of the coding line, the position of a0 is defined by the - previous coding mode. (See T.4/4.2.1.3.2.) */ - int a0; - /* The next changing element to the right of a0 on the coding line. */ - int a1; - /* The next changing element to the right of a1 on the coding line. */ - int a2; - /* The first changing element on the reference line to the right of a0 and of opposite colour to a0. */ - int b1; - /* The next changing element to the right of b1 on the reference line. */ - int b2; - int diff; - int a_cursor; - int b_cursor; - int cur_steps; - uint32_t *p; - - /* - b1 b2 - XX XX XX XX XX -- -- -- -- -- XX XX XX -- -- -- -- -- - XX XX XX -- -- -- -- -- XX XX XX XX XX XX -- -- -- -- - a0 a1 a2 - - - a) Pass mode - This mode is identified when the position of b2 lies to the left of a1. When this mode - has been coded, a0 is set on the element of the coding line below b2 in preparation for - the next coding (i.e. on a0'). - - b1 b2 - XX XX XX XX -- -- XX XX XX -- -- -- -- -- - XX XX -- -- -- -- -- -- -- -- -- -- XX XX - a0 a0' a1 - Pass mode - - - However, the state where b2 occurs just above a1, as shown in the figure below, is not - considered as a pass mode. - - b1 b2 - XX XX XX XX -- -- XX XX XX -- -- -- -- -- - XX XX -- -- -- -- -- -- -- XX XX XX XX XX - a0 a1 - Not pass mode - - - b) Vertical mode - When this mode is identified, the position of a1 is coded relative to the position of b1. - The relative distance a1b1 can take on one of seven values V(0), VR(1), VR(2), VR(3), - VL(1), VL(2) and VL(3), each of which is represented by a separate code word. The - subscripts R and L indicate that a1 is to the right or left respectively of b1, and the - number in brackets indicates the value of the distance a1b1. After vertical mode coding - has occurred, the position of a0 is set on a1 (see figure below). - - c) Horizontal mode - When this mode is identified, both the run-lengths a0a1 and a1a2 are coded using the code - words H + M(a0a1) + M(a1a2). H is the flag code word 001 taken from the two-dimensional - code table. M(a0a1) and M(a1a2) are code words which represent the length and "colour" - of the runs a0a1 and a1a2 respectively and are taken from the appropriate white or black - one-dimensional code tables. After a horizontal mode coding, the position of a0 is set on - a2 (see figure below). - - Vertical - - b1 b2 - -- XX XX XX XX XX -- -- -- -- -- -- -- -- XX XX XX XX -- -- -- - -- -- -- -- -- -- -- -- -- -- -- -- XX XX XX XX XX XX XX -- -- - a0 a1 a2 - <-------- a0a1 --------><-------- a1a2 ------------> - Horizontal mode - Vertical and horizontal modes - */ - /* The following implements the 2-D encoding section of the flow chart in Figure7/T.4 */ - cur_steps = row_to_run_lengths(s->cur_runs, row_buf, s->image_width); - /* Stretch the row a little, so when we step by 2 we are guaranteed to - hit an entry showing the row length. */ - s->cur_runs[cur_steps] = - s->cur_runs[cur_steps + 1] = - s->cur_runs[cur_steps + 2] = s->cur_runs[cur_steps - 1]; - - a0 = 0; - a1 = s->cur_runs[0]; - b1 = s->ref_runs[0]; - a_cursor = 0; - b_cursor = 0; - for (;;) - { - b2 = s->ref_runs[b_cursor + 1]; - if (b2 >= a1) - { - diff = b1 - a1; - if (abs(diff) <= 3) - { - /* Vertical mode coding */ - put_encoded_bits(s, codes[diff + 3].code, codes[diff + 3].length); - a0 = a1; - a_cursor++; - } - else - { - /* Horizontal mode coding */ - a2 = s->cur_runs[a_cursor + 1]; - put_encoded_bits(s, codes[7].code, codes[7].length); - if (a0 + a1 == 0 || pixel_is_black(row_buf, a0) == 0) - { - put_1d_span(s, a1 - a0, t4_white_codes); - put_1d_span(s, a2 - a1, t4_black_codes); - } - else - { - put_1d_span(s, a1 - a0, t4_black_codes); - put_1d_span(s, a2 - a1, t4_white_codes); - } - a0 = a2; - a_cursor += 2; - } - if (a0 >= s->image_width) - break; - if (a_cursor >= cur_steps) - a_cursor = cur_steps - 1; - a1 = s->cur_runs[a_cursor]; - } - else - { - /* Pass mode coding */ - put_encoded_bits(s, codes[8].code, codes[8].length); - /* We now set a0 to somewhere in the middle of its current run, - but we know are aren't moving beyond that run. */ - a0 = b2; - if (a0 >= s->image_width) - break; - } - /* We need to hunt for the correct position in the reference row, as the - runs there have no particular alignment with the runs in the current - row. */ - if (pixel_is_black(row_buf, a0)) - b_cursor |= 1; - else - b_cursor &= ~1; - if (a0 < (int) s->ref_runs[b_cursor]) - { - for ( ; b_cursor >= 0; b_cursor -= 2) - { - if (a0 >= (int) s->ref_runs[b_cursor]) - break; - } - b_cursor += 2; - } - else - { - for ( ; b_cursor < s->ref_steps; b_cursor += 2) - { - if (a0 < (int) s->ref_runs[b_cursor]) - break; - } - if (b_cursor >= s->ref_steps) - b_cursor = s->ref_steps - 1; - } - b1 = s->ref_runs[b_cursor]; - } - /* Swap the buffers */ - s->ref_steps = cur_steps; - p = s->cur_runs; - s->cur_runs = s->ref_runs; - s->ref_runs = p; -} -/*- End of function --------------------------------------------------------*/ - -/* - * 1D-encode a row of pixels. The encoding is a sequence of all-white or - * all-black spans of pixels encoded with Huffman codes. - */ -static void encode_1d_row(t4_t6_encode_state_t *s, const uint8_t *row_buf) -{ - int i; - - /* Do our work in the reference row buffer, and it is already in place if - we need a reference row for a following 2D encoded row. */ - s->ref_steps = row_to_run_lengths(s->ref_runs, row_buf, s->image_width); - put_1d_span(s, s->ref_runs[0], t4_white_codes); - for (i = 1; i < s->ref_steps; i++) - put_1d_span(s, s->ref_runs[i] - s->ref_runs[i - 1], (i & 1) ? t4_black_codes : t4_white_codes); - /* Stretch the row a little, so when we step by 2 we are guaranteed to - hit an entry showing the row length */ - s->ref_runs[s->ref_steps] = - s->ref_runs[s->ref_steps + 1] = - s->ref_runs[s->ref_steps + 2] = s->ref_runs[s->ref_steps - 1]; -} -/*- End of function --------------------------------------------------------*/ - -static int encode_row(t4_t6_encode_state_t *s, const uint8_t *row_buf, size_t len) -{ - switch (s->encoding) - { - 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_T4_2D: - encode_eol(s); - if (s->row_is_2d) - { - encode_2d_row(s, row_buf); - s->rows_to_next_1d_row--; - } - else - { - encode_1d_row(s, row_buf); - 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->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1; - } - break; - default: - case T4_COMPRESSION_T4_1D: - encode_eol(s); - encode_1d_row(s, row_buf); - break; - } - s->image_length++; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int finalise_page(t4_t6_encode_state_t *s) -{ - int i; - - 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++) - encode_eol(s); - } - else - { - /* Attach an RTC (return to control == 6 x EOLs) to the end of the page */ - s->row_is_2d = false; - for (i = 0; i < EOLS_TO_END_T4_TX_PAGE; i++) - encode_eol(s); - } - /* Force any partial byte in progress to flush using ones. Any post EOL padding when - sending is normally ones, so this is consistent. */ - put_encoded_bits(s, 0xFF, 7); - /* Flag that page generation has finished */ - s->row_bits = -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int get_next_row(t4_t6_encode_state_t *s) -{ - int len; -#if defined(_MSC_VER) - uint8_t *row_buf = (uint8_t *) _alloca(s->bytes_per_row); -#else - uint8_t row_buf[s->bytes_per_row]; -#endif - - if (s->row_bits < 0 || s->row_read_handler == NULL) - return -1; - s->bitstream_iptr = 0; - s->bitstream_optr = 0; - s->bit_pos = 7; - /* A row may not actually fill a byte of output buffer space in T.6 mode, - so we loop here until we have at least one byte of output bit stream, - and can continue outputting. */ - do - { - len = s->row_read_handler(s->row_read_user_data, row_buf, s->bytes_per_row); - if (len == s->bytes_per_row) - encode_row(s, row_buf, len); - else - finalise_page(s); - } - while (len > 0 && s->bitstream_iptr == 0); - s->compressed_image_size += 8*s->bitstream_iptr; - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_image_complete(t4_t6_encode_state_t *s) -{ - if (s->bitstream_optr >= s->bitstream_iptr) - { - if (get_next_row(s) < 0) - return SIG_STATUS_END_OF_DATA; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_get_bit(t4_t6_encode_state_t *s) -{ - int bit; - - if (s->bitstream_optr >= s->bitstream_iptr) - { - if (get_next_row(s) < 0) - return SIG_STATUS_END_OF_DATA; - } - bit = (s->bitstream[s->bitstream_optr] >> (7 - s->bit_pos)) & 1; - if (--s->bit_pos < 0) - { - s->bitstream_optr++; - s->bit_pos = 7; - } - return bit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_get(t4_t6_encode_state_t *s, uint8_t buf[], int max_len) -{ - int len; - int n; - - for (len = 0; len < max_len; len += n) - { - if (s->bitstream_optr >= s->bitstream_iptr) - { - if (get_next_row(s) < 0) - return len; - } - n = s->bitstream_iptr - s->bitstream_optr; - if (n > max_len - len) - n = max_len - len; - memcpy(&buf[len], &s->bitstream[s->bitstream_optr], n); - s->bitstream_optr += n; - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_set_row_read_handler(t4_t6_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(int) t4_t6_encode_set_encoding(t4_t6_encode_state_t *s, int encoding) -{ - switch (encoding) - { - 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 = (s->encoding == T4_COMPRESSION_T6); - return 0; - } - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_t6_encode_set_min_bits_per_row(t4_t6_encode_state_t *s, int 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 --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_set_image_width(t4_t6_encode_state_t *s, int image_width) -{ - int run_space; - uint32_t *bufptr; - uint8_t *bufptr8; - - /* TODO: Are we too late to change the width */ - if (s->bytes_per_row == 0 || image_width != s->image_width) - { - s->image_width = image_width; - s->bytes_per_row = (s->image_width + 7)/8; - run_space = (s->image_width + 4)*sizeof(uint32_t); - - if ((bufptr = (uint32_t *) span_realloc(s->cur_runs, run_space)) == NULL) - return -1; - s->cur_runs = bufptr; - if ((bufptr = (uint32_t *) span_realloc(s->ref_runs, run_space)) == NULL) - return -1; - s->ref_runs = bufptr; - if ((bufptr8 = (uint8_t *) span_realloc(s->bitstream, (s->image_width + 1)*sizeof(uint16_t))) == NULL) - return -1; - s->bitstream = bufptr8; - } - return 0; -} -/*- 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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t4_t6_encode_get_image_length(t4_t6_encode_state_t *s) -{ - return s->image_length; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_get_compressed_image_size(t4_t6_encode_state_t *s) -{ - return s->compressed_image_size; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_t6_encode_set_max_2d_rows_per_1d_row(t4_t6_encode_state_t *s, int max) -{ - static const struct - { - int code; - int max_rows; - } 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}, - {-1, -1} - }; - int i; - int res; - - if (max < 0) - { - /* Its actually a resolution code we need to translate into an appropriate - number of rows. Note that we only hit on exact known resolutions. */ - res = -max; - max = 2; - for (i = 0; y_res_table[i].code > 0; i++) - { - if (res == y_res_table[i].code) - { - max = y_res_table[i].max_rows; - break; - } - } - } - s->max_rows_to_next_1d_row = max; - s->rows_to_next_1d_row = max - 1; - s->row_is_2d = false; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t4_t6_encode_get_logging_state(t4_t6_encode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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_T6); - s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1; - - s->tx_bitstream = 0; - s->bitstream_iptr = 0; - s->bitstream_optr = 0; - s->bit_pos = 7; - s->tx_bits = 0; - s->row_bits = 0; - s->min_row_bits = INT_MAX; - s->max_row_bits = 0; - s->image_length = 0; - s->compressed_image_size = 0; - - s->ref_runs[0] = - s->ref_runs[1] = - s->ref_runs[2] = - s->ref_runs[3] = s->image_width; - s->ref_steps = 1; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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 *) 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.4/T.6"); - - s->encoding = encoding; - s->row_read_handler = handler; - s->row_read_user_data = user_data; - - s->max_rows_to_next_1d_row = 2; - t4_t6_encode_restart(s, image_width, image_length); - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_release(t4_t6_encode_state_t *s) -{ - free_buffers(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_t6_encode_free(t4_t6_encode_state_t *s) -{ - int ret; - - ret = t4_t6_encode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c deleted file mode 100644 index 47353b62ae..0000000000 --- a/libs/spandsp/src/t4_tx.c +++ /dev/null @@ -1,2640 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_tx.c - ITU T.4 FAX image transmit processing - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2007, 2010 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/bit_operations.h" -#include "spandsp/async.h" -#include "spandsp/timezone.h" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/image_translate.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" -#include "spandsp/t42.h" -#include "spandsp/t43.h" -#include "spandsp/t4_t6_decode.h" -#include "spandsp/t4_t6_encode.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 "spandsp/private/t4_t6_decode.h" -#include "spandsp/private/t4_t6_encode.h" -#include "spandsp/private/image_translate.h" -#include "spandsp/private/t4_rx.h" -#include "spandsp/private/t4_tx.h" - -#include "faxfont.h" - -#if defined(SPANDSP_SUPPORT_TIFF_FX) && defined(HAVE_TIF_DIR_H) -#include -#endif - -/*! The number of centimetres in one inch */ -#define CM_PER_INCH 2.54f - -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_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 >= 20120922 && defined(HAVE_TIF_DIR_H) -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", 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 }, - { 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 }, -}; - -TIFFFieldArray tiff_fx_field_array = { tfiatOther, 0, 12, tiff_fx_tiff_fields }; -#endif - -static TIFFExtendProc _ParentExtender = NULL; - -static void TIFFFXDefaultDirectory(TIFF *tif) -{ - /* Install the extended tag field info */ - TIFFMergeFieldInfo(tif, tiff_fx_tiff_field_info, 12); - - /* Since we may have overriddden another directory method, we call it now to - allow it to set up the rest of its own methods. */ - if (_ParentExtender) - (*_ParentExtender)(tif); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) TIFF_FX_init(void) -{ - static int first_time = true; - - if (!first_time) - return; - first_time = false; - - /* Grab the inherited method and install */ - _ParentExtender = TIFFSetTagExtender(TIFFFXDefaultDirectory); -} -/*- End of function --------------------------------------------------------*/ -#endif - -static int code_to_x_resolution(int code) -{ - 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 --------------------------------------------------------*/ - -#if 0 -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 = 0; - 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 --------------------------------------------------------*/ -#endif - -#if defined(SPANDSP_SUPPORT_TIFF_FX) -static int read_colour_map(t4_tx_state_t *s, int bits_per_sample) -{ - int i; - uint16_t *map_L; - uint16_t *map_a; - uint16_t *map_b; - uint16_t *map_z; - - map_L = NULL; - map_a = NULL; - map_b = NULL; - map_z = NULL; - if (!TIFFGetField(s->tiff.tiff_file, TIFFTAG_COLORMAP, &map_L, &map_a, &map_b, &map_z)) - return -1; - - /* TODO: This only allows for 8 bit deep maps */ - 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 < 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; - s->colour_map[3*i + 2] = (map_b[i] >> 8) & 0xFF; - 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]); - } -#else - /* Sweep the colormap in the order that seems to work for l04x_02x.tif */ - for (i = 0; i < s->colour_map_entries; i++) - { - 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, 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; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static int get_tiff_directory_info(t4_tx_state_t *s) -{ -#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" - }; - char *u; - char uu[10]; - float *fl_parms; - toff_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; - 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; - TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); - samples_per_pixel = 1; - TIFFGetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); - if (samples_per_pixel == 1 && bits_per_sample == 1) - 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) - t->image_type = T4_IMAGE_TYPE_GRAY_12BIT; - else if (samples_per_pixel == 3 && bits_per_sample == 8) - t->image_type = T4_IMAGE_TYPE_COLOUR_8BIT; - else if (samples_per_pixel == 3 && bits_per_sample > 8) - t->image_type = T4_IMAGE_TYPE_COLOUR_12BIT; - else - 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 = parm32; - parm32 = 0; - TIFFGetField(t->tiff_file, TIFFTAG_IMAGELENGTH, &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); - - /* 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; - -#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)) - { - 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); - - 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. */ - diroff = 0; - if (TIFFGetField(t->tiff_file, TIFFTAG_GLOBALPARAMETERSIFD, &diroff)) - { -#if TIFFLIB_VERSION >= 20120922 && defined(HAVE_TIF_DIR_H) - 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 - } -#endif - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int test_tiff_directory_info(t4_tx_state_t *s) -{ - uint16_t res_unit; - uint32_t parm32; - uint16_t bits_per_sample; - uint16_t samples_per_pixel; - int image_type; - float x_resolution; - float y_resolution; - t4_tx_tiff_state_t *t; - - t = &s->tiff; - bits_per_sample = 1; - TIFFGetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); - samples_per_pixel = 1; - TIFFGetField(t->tiff_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); - if (samples_per_pixel == 1 && bits_per_sample == 1) - 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) - image_type = T4_IMAGE_TYPE_GRAY_12BIT; - else if (samples_per_pixel == 3 && bits_per_sample == 8) - image_type = T4_IMAGE_TYPE_COLOUR_8BIT; - else if (samples_per_pixel == 3 && bits_per_sample > 8) - image_type = T4_IMAGE_TYPE_COLOUR_12BIT; - else - image_type = -1; - if (t->image_type != image_type) - return 1; - - parm32 = 0; - TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); - 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; - TIFFGetField(t->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution); - res_unit = RESUNIT_INCH; - TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); - - x_resolution *= 100.0f; - y_resolution *= 100.0f; - if (res_unit == RESUNIT_INCH) - { - x_resolution /= CM_PER_INCH; - y_resolution /= CM_PER_INCH; - } - 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 --------------------------------------------------------*/ - -static int get_tiff_total_pages(t4_tx_state_t *s) -{ - int max; - - /* Each page *should* contain the total number of pages, but can this be - trusted? Some files say 0. Actually searching for the last page is - more reliable. */ - max = 0; - while (TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) max)) - max++; - /* Back to the previous page */ - if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) - return -1; - return max; -} -/*- End of function --------------------------------------------------------*/ - -static int open_tiff_input_file(t4_tx_state_t *s, const char *file) -{ - if ((s->tiff.tiff_file = TIFFOpen(file, "r")) == NULL) - return -1; - return 0; -} -/*- 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; - int i; - int j; - - s = (t4_tx_state_t *) user_data; - 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->tiff.image_length; i++) - { - for (j = 0; j < len; j++) - buf[j] |= s->tiff.image_buffer[s->tiff.row*len + j]; - s->tiff.row++; - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -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); - 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) - 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 --------------------------------------------------------*/ - -#if defined(SPANDSP_SUPPORT_T43) -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 --------------------------------------------------------*/ -#endif - -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 i; - int alter_image; - uint8_t *t; - - if (s->metadata.image_type != s->tiff.image_type || s->metadata.image_width != s->tiff.image_width) - { - /* 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 - { - alter_image = false; - s->metadata.image_length = s->tiff.image_length; - } - s->pack_buf = NULL; - s->pack_ptr = 0; - s->pack_row = 0; - - 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 (alter_image) - { - 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 defined(SPANDSP_SUPPORT_T43) - else if (s->tiff.compression == COMPRESSION_T43) - { - 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; - } - } - s->tiff.row = 0; - return s->metadata.image_length; -} -/*- End of function --------------------------------------------------------*/ - -static void tiff_tx_release(t4_tx_state_t *s) -{ - if (s->tiff.tiff_file) - { - TIFFClose(s->tiff.tiff_file); - s->tiff.tiff_file = NULL; - if (s->tiff.file) - span_free((char *) s->tiff.file); - s->tiff.file = NULL; - } - if (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; - } -} -/*- End of function --------------------------------------------------------*/ - -static int set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data) -{ - switch (s->metadata.compression) - { - 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_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; -} -/*- End of function --------------------------------------------------------*/ - -static int make_header(t4_tx_state_t *s) -{ - time_t now; - struct tm tm; - static const char *months[] = - { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - if (s->header_text == 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 - measure of i18n in the time and date, and even the header_info string, is - entirely possible, although the font area would need some serious work to - properly deal with East Asian script. There is no spec for what the header - should contain, or how much of the page it might occupy. The present format - follows the common practice of a few FAX machines. Nothing more. */ - time(&now); - if (s->tz) - tz_localtime(s->tz, &tm, now); - else - tm = *localtime(&now); - - snprintf(s->header_text, - 132, - " %2d-%s-%d %02d:%02d %-50s %-21s p.%d", - tm.tm_mday, - months[tm.tm_mon], - tm.tm_year + 1900, - tm.tm_hour, - tm.tm_min, - (s->header_info) ? s->header_info : "", - (s->local_ident) ? s->local_ident : "", - s->current_page + 1); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len) -{ - 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.resolution_code) - { - default: - case T4_RESOLUTION_100_100: - y_repeats = 1; - break; - case T4_RESOLUTION_R8_STANDARD: - case T4_RESOLUTION_200_100: - y_repeats = 1; - break; - case T4_RESOLUTION_R8_FINE: - case T4_RESOLUTION_200_200: - y_repeats = 2; - break; - case T4_RESOLUTION_300_300: - y_repeats = 3; - break; - case T4_RESOLUTION_R8_SUPERFINE: - case T4_RESOLUTION_200_400: - y_repeats = 4; - break; - case T4_RESOLUTION_R16_SUPERFINE: - case T4_RESOLUTION_400_400: - y_repeats = 4; - break; - case T4_RESOLUTION_400_800: - y_repeats = 8; - break; - case T4_RESOLUTION_300_600: - y_repeats = 6; - break; - case T4_RESOLUTION_600_600: - y_repeats = 6; - break; - case T4_RESOLUTION_600_1200: - y_repeats = 12; - break; - case T4_RESOLUTION_1200_1200: - y_repeats = 12; - break; - } - switch (s->metadata.width_code) - { - case T4_SUPPORT_WIDTH_215MM: - break; - case T4_SUPPORT_WIDTH_255MM: - break; - case T4_SUPPORT_WIDTH_303MM: - break; - } - if (s->header_overlays_image) - { - /* Read and dump a row of the real image, allowing for the possibility - that the real image might end within the header itself */ - if (len != s->row_handler(s->row_handler_user_data, buf, len)) - { - set_row_read_handler(s, s->row_handler, s->row_handler_user_data); - return len; - } - } - t = s->header_text; - row = s->header_row/y_repeats; - pos = 0; - switch (s->metadata.image_type) - { - 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); - } - s->header_row++; - 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); - } - return len; -} -/*- 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); - if (s->current_page >= s->stop_page) - return -1; - if (s->tiff.file) - { - if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page + 1)) - return -1; - return test_tiff_directory_info(s); - } - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data) -{ - s->row_handler = handler; - s->row_handler_user_data = user_data; - return set_row_read_handler(s, handler, user_data); -} -/*- End of function --------------------------------------------------------*/ - -static int release_encoder(t4_tx_state_t *s) -{ - switch (s->metadata.compression) - { - 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_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; -} -/*- End of function --------------------------------------------------------*/ - -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) -{ - static const struct - { - 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 - { - int resolution; - int squashing_factor; - } fallback[4]; - } squashable[4] = - { - { - T4_RESOLUTION_200_400, - { - {T4_RESOLUTION_200_200, 2}, - {T4_RESOLUTION_R8_FINE, 2}, - {T4_RESOLUTION_200_100, 4}, - {T4_RESOLUTION_R8_STANDARD, 4} - } - }, - { - T4_RESOLUTION_200_200, - { - {T4_RESOLUTION_200_100, 2}, - {T4_RESOLUTION_R8_STANDARD, 2}, - {0, 0}, - {0, 0} - } - }, - { - 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)); - } - } - - 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; - } - } - 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: - release_encoder(s); - 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: - release_encoder(s); - 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: - release_encoder(s); - 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: - release_encoder(s); - 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: - release_encoder(s); - 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->metadata.compression) - { - 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_max_2d_rows_per_1d_row(t4_tx_state_t *s, int max) -{ - 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, max); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_tx_set_local_ident(t4_tx_state_t *s, const char *ident) -{ - s->local_ident = (ident && ident[0]) ? ident : NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_tx_set_header_info(t4_tx_state_t *s, const char *info) -{ - s->header_info = (info && info[0]) ? info : NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_tx_set_header_tz(t4_tx_state_t *s, struct tz_s *tz) -{ - s->tz = tz; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_tx_state_t *s) -{ - int max; - - if (s->tiff.file) - max = get_tiff_total_pages(s); - else - max = 1; - if (max >= 0) - s->tiff.pages_in_file = max; - return max; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_tx_state_t *s) -{ - return s->current_page; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t) -{ - memset(t, 0, sizeof(*t)); - t->pages_transferred = s->current_page - s->start_page; - t->pages_in_file = s->tiff.pages_in_file; - - 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.x_resolution; - t->image_y_resolution = s->tiff.y_resolution; - t->x_resolution = s->metadata.x_resolution; - 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_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); - t->line_image_size = t4_t6_encode_get_compressed_image_size(&s->encoder.t4_t6)/8; - break; - 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); - 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) -{ - if (s->no_encoder.buf_len > 0) - { - 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_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; -} -/*- End of function --------------------------------------------------------*/ - -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) -{ - if (s->no_encoder.buf_len > 0) - { - 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_compression_to_str(s->metadata.compression)); - if (s->current_page > s->stop_page) - return -1; - if (s->tiff.file) - { - if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page)) - return -1; - get_tiff_directory_info(s); - if (read_tiff_image(s) < 0) - return -1; - } - else - { - s->metadata.image_length = UINT32_MAX; - } - - switch (s->metadata.compression) - { - 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_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_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_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->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); - } - else - { - set_row_read_handler(s, s->row_handler, s->row_handler_user_data); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_restart_page(t4_tx_state_t *s) -{ - /* This is currently the same as starting a page, but keep it a separate call, - as the two things might diverge a little in the future. */ - return t4_tx_start_page(s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_end_page(t4_tx_state_t *s) -{ - s->current_page++; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t4_tx_get_logging_state(t4_tx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int start_page, int stop_page) -{ - int allocated; - - allocated = false; - if (s == NULL) - { - if ((s = (t4_tx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - allocated = true; - } - memset(s, 0, sizeof(*s)); -#if defined(SPANDSP_SUPPORT_TIFF_FX) - TIFF_FX_init(); -#endif - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "T.4"); - - span_log(&s->logging, SPAN_LOG_FLOW, "Start tx document\n"); - - s->current_page = - s->start_page = (start_page >= 0) ? start_page : 0; - s->stop_page = (stop_page >= 0) ? stop_page : INT_MAX; - s->metadata.compression = T4_COMPRESSION_NONE; - - s->row_handler = tiff_row_read_handler; - s->row_handler_user_data = (void *) s; - - s->row_squashing_ratio = 1; - - if (file) - { - if (open_tiff_input_file(s, file) < 0) - { - if (allocated) - span_free(s); - return NULL; - } - s->tiff.file = strdup(file); - s->tiff.pages_in_file = -1; - if (!TIFFSetDirectory(s->tiff.tiff_file, (tdir_t) s->current_page) - || - get_tiff_directory_info(s)) - { - tiff_tx_release(s); - if (allocated) - span_free(s); - return NULL; - } - } - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s) -{ - if (s->tiff.file) - tiff_tx_release(s); - if (s->header_text) - { - span_free(s->header_text); - s->header_text = NULL; - } - if (s->colour_map) - { - span_free(s->colour_map); - s->colour_map = NULL; - } - return release_encoder(s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_free(t4_tx_state_t *s) -{ - int ret; - - ret = t4_tx_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t81_t82_arith_coding.c b/libs/spandsp/src/t81_t82_arith_coding.c deleted file mode 100644 index f9c1408c66..0000000000 --- a/libs/spandsp/src/t81_t82_arith_coding.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t81_t82_arith_coding.c - ITU T.81 and T.82 QM-coder arithmetic encoding - * and decoding - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 -#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" - -/* T.82 defines the QM-coder at a level very close to actual code. Therefore - this file closely mirrors the routine names, variable names, and flow - described in T.82. QM-Coder is supposed to be the same in some other image - 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. */ - -/* Code bytes which must trigger stuffing */ -enum -{ - T81_T82_STUFF = 0x00, - T81_T82_ESC = 0xFF -}; - -/* This table is from T.82 table 24 - Probability estimation table */ -static const struct probability_estimation_s -{ - uint16_t lsz; - uint8_t nlps; /* The SWITCH bit is packed into the top of this byte */ - uint8_t nmps; -} prob[113] = -{ - {0x5A1D, 1 + 128, 1}, - {0x2586, 14, 2}, - {0x1114, 16, 3}, - {0x080B, 18, 4}, - {0x03D8, 20, 5}, - {0x01DA, 23, 6}, - {0x00E5, 25, 7}, - {0x006F, 28, 8}, - {0x0036, 30, 9}, - {0x001A, 33, 10}, - {0x000D, 35, 11}, - {0x0006, 9, 12}, - {0x0003, 10, 13}, - {0x0001, 12, 13}, - {0x5A7F, 15 + 128, 15}, - {0x3F25, 36, 16}, - {0x2CF2, 38, 17}, - {0x207C, 39, 18}, - {0x17B9, 40, 19}, - {0x1182, 42, 20}, - {0x0CEF, 43, 21}, - {0x09A1, 45, 22}, - {0x072F, 46, 23}, - {0x055C, 48, 24}, - {0x0406, 49, 25}, - {0x0303, 51, 26}, - {0x0240, 52, 27}, - {0x01B1, 54, 28}, - {0x0144, 56, 29}, - {0x00F5, 57, 30}, - {0x00B7, 59, 31}, - {0x008A, 60, 32}, - {0x0068, 62, 33}, - {0x004E, 63, 34}, - {0x003B, 32, 35}, - {0x002C, 33, 9}, - {0x5AE1, 37 + 128, 37}, - {0x484C, 64, 38}, - {0x3A0D, 65, 39}, - {0x2EF1, 67, 40}, - {0x261F, 68, 41}, - {0x1F33, 69, 42}, - {0x19A8, 70, 43}, - {0x1518, 72, 44}, - {0x1177, 73, 45}, - {0x0E74, 74, 46}, - {0x0BFB, 75, 47}, - {0x09F8, 77, 48}, - {0x0861, 78, 49}, - {0x0706, 79, 50}, - {0x05CD, 48, 51}, - {0x04DE, 50, 52}, - {0x040F, 50, 53}, - {0x0363, 51, 54}, - {0x02D4, 52, 55}, - {0x025C, 53, 56}, - {0x01F8, 54, 57}, - {0x01A4, 55, 58}, - {0x0160, 56, 59}, - {0x0125, 57, 60}, - {0x00F6, 58, 61}, - {0x00CB, 59, 62}, - {0x00AB, 61, 63}, - {0x008F, 61, 32}, - {0x5B12, 65 + 128, 65}, - {0x4D04, 80, 66}, - {0x412C, 81, 67}, - {0x37D8, 82, 68}, - {0x2FE8, 83, 69}, - {0x293C, 84, 70}, - {0x2379, 86, 71}, - {0x1EDF, 87, 72}, - {0x1AA9, 87, 73}, - {0x174E, 72, 74}, - {0x1424, 72, 75}, - {0x119C, 74, 76}, - {0x0F6B, 74, 77}, - {0x0D51, 75, 78}, - {0x0BB6, 77, 79}, - {0x0A40, 77, 48}, - {0x5832, 80 + 128, 81}, - {0x4D1C, 88, 82}, - {0x438E, 89, 83}, - {0x3BDD, 90, 84}, - {0x34EE, 91, 85}, - {0x2EAE, 92, 86}, - {0x299A, 93, 87}, - {0x2516, 86, 71}, - {0x5570, 88 + 128, 89}, - {0x4CA9, 95, 90}, - {0x44D9, 96, 91}, - {0x3E22, 97, 92}, - {0x3824, 99, 93}, - {0x32B4, 99, 94}, - {0x2E17, 93, 86}, - {0x56A8, 95 + 128, 96}, - {0x4F46, 101, 97}, - {0x47E5, 102, 98}, - {0x41CF, 103, 99}, - {0x3C3D, 104, 100}, - {0x375E, 99, 93}, - {0x5231, 105, 102}, - {0x4C0F, 106, 103}, - {0x4639, 107, 104}, - {0x415E, 103, 99}, - {0x5627, 105 + 128, 106}, - {0x50E7, 108, 107}, - {0x4B85, 109, 103}, - {0x5597, 110, 109}, - {0x504F, 111, 107}, - {0x5A10, 110 + 128, 111}, - {0x5522, 112, 109}, - {0x59EB, 112 + 128, 111} -}; - -static __inline__ void output_stuffed_byte(t81_t82_arith_encode_state_t *s, int byte) -{ - s->output_byte_handler(s->user_data, byte); - if (byte == T81_T82_ESC) - s->output_byte_handler(s->user_data, T81_T82_STUFF); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void byteout(t81_t82_arith_encode_state_t *s) -{ - uint32_t temp; - - /* T.30 figure 26 - BYTEOUT */ - temp = s->c >> 19; - if (temp > 0xFF) - { - if (s->buffer >= 0) - output_stuffed_byte(s, s->buffer + 1); - while (s->sc) - { - s->output_byte_handler(s->user_data, 0x00); - s->sc--; - } - s->buffer = temp & 0xFF; - } - else if (temp == 0xFF) - { - s->sc++; - } - else - { - if (s->buffer >= 0) - output_stuffed_byte(s, s->buffer); - while (s->sc) - { - output_stuffed_byte(s, T81_T82_ESC); - s->sc--; - } - s->buffer = temp; - } - s->c &= 0x7FFFF; - s->ct = 8; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void renorme(t81_t82_arith_encode_state_t *s) -{ - /* T.82 figure 25 - RENORME */ - do - { - s->a <<= 1; - s->c <<= 1; - s->ct--; - if (s->ct == 0) - byteout(s); - } - while (s->a < 0x8000); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t81_t82_arith_encode(t81_t82_arith_encode_state_t *s, int cx, int pix) -{ - uint32_t ss; - - /* T.82 figure 22 - ENCODE */ - ss = s->st[cx] & 0x7F; - if (((pix << 7) ^ s->st[cx]) & 0x80) - { - /* T.82 figure 23 - CODELPS */ - s->a -= prob[ss].lsz; - if (s->a >= prob[ss].lsz) - { - s->c += s->a; - s->a = prob[ss].lsz; - } - s->st[cx] = (s->st[cx] & 0x80) ^ prob[ss].nlps; - renorme(s); - } - else - { - /* T.82 figure 24 - CODEMPS */ - s->a -= prob[ss].lsz; - if (s->a < 0x8000) - { - if (s->a < prob[ss].lsz) - { - s->c += s->a; - s->a = prob[ss].lsz; - } - s->st[cx] = (s->st[cx] & 0x80) | prob[ss].nmps; - renorme(s); - } - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t81_t82_arith_encode_flush(t81_t82_arith_encode_state_t *s) -{ - uint32_t temp; - - /* T.82 figure 28 - FLUSH */ - /* T.82 figure 29 - CLEARBITS */ - temp = (s->c + s->a - 1) & 0xFFFF0000; - s->c = (temp < s->c) ? (temp + 0x8000) : temp; - /* T.82 figure 30 - FINALWRITES */ - s->c <<= s->ct; - if ((s->c > 0x7FFFFFF)) - { - if (s->buffer >= 0) - output_stuffed_byte(s, s->buffer + 1); - /* Only output 0x00 bytes if something non-0x00 will follow */ - if ((s->c & 0x7FFF800)) - { - while (s->sc) - { - output_stuffed_byte(s, 0x00); - s->sc--; - } - } - } - else - { - /* The next bit says s->buffer + 1 in T.82, but that makes no sense. It doesn't - agree with how we code things away from the flush condition, and it gives - answers which don't seem to match other JBIG coders. */ - if (s->buffer >= 0) - output_stuffed_byte(s, s->buffer); - while (s->sc) - { - output_stuffed_byte(s, 0xFF); - s->sc--; - } - } - /* Only output final bytes if they are not 0x00 */ - if ((s->c & 0x7FFF800)) - { - output_stuffed_byte(s, (s->c >> 19) & 0xFF); - if ((s->c & 0x7F800)) - output_stuffed_byte(s, (s->c >> 11) & 0xFF); - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_encode_restart(t81_t82_arith_encode_state_t *s, int reuse_st) -{ - /* T.82 figure 27 - INITENC */ - if (!reuse_st) - memset(s->st, 0, sizeof(s->st)); - s->c = 0; - s->a = 0x10000; - s->sc = 0; - s->ct = 11; - s->buffer = -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t81_t82_arith_encode_state_t *) t81_t82_arith_encode_init(t81_t82_arith_encode_state_t *s, - void (*output_byte_handler)(void *, int), - void *user_data) -{ - if (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); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_encode_release(t81_t82_arith_encode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_encode_free(t81_t82_arith_encode_state_t *s) -{ - int ret; - - ret = t81_t82_arith_encode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_decode(t81_t82_arith_decode_state_t *s, int cx) -{ - uint32_t ss; - int pix; - - /* T.82 figure 35 - RENORMD */ - while (s->a < 0x8000 || s->startup) - { - while (s->ct <= 8 && s->ct >= 0) - { - /* First we can move a new byte into s->c */ - if (s->pscd_ptr >= s->pscd_end) - return -1; - if (s->pscd_ptr[0] == T81_T82_ESC) - { - if (s->pscd_ptr + 1 >= s->pscd_end) - return -1; - if (s->pscd_ptr[1] == T81_T82_STUFF) - { - s->c |= (0xFF << (8 - s->ct)); - s->ct += 8; - s->pscd_ptr += 2; - } - else - { - /* Start padding with zero bytes */ - s->ct = -1; - if (s->nopadding) - { - /* Subsequent symbols might depend on zero padding */ - s->nopadding = false; - return -2; - } - } - } - else - { - s->c |= (int32_t) *(s->pscd_ptr++) << (8 - s->ct); - s->ct += 8; - } - } - s->a <<= 1; - s->c <<= 1; - if (s->ct >= 0) - s->ct--; - if (s->a == 0x10000) - s->startup = false; - } - - /* T.82 figure 32 - DECODE */ - ss = s->st[cx] & 0x7F; - if ((s->c >> 16) >= (s->a -= prob[ss].lsz)) - { - /* T.82 figure 33 - LPS_EXCHANGE */ - if (s->a < prob[ss].lsz) - { - s->c -= (s->a << 16); - s->a = prob[ss].lsz; - pix = s->st[cx] >> 7; - s->st[cx] = (s->st[cx] & 0x80) | prob[ss].nmps; - } - else - { - s->c -= (s->a << 16); - s->a = prob[ss].lsz; - pix = 1 - (s->st[cx] >> 7); - s->st[cx] = (s->st[cx]& 0x80) ^ prob[ss].nlps; - } - } - else - { - if (s->a < 0x8000) - { - /* T.82 figure 34 - MPS_EXCHANGE */ - if (s->a < prob[ss].lsz) - { - pix = 1 - (s->st[cx] >> 7); - s->st[cx] = (s->st[cx] & 0x80) ^ prob[ss].nlps; - } - else - { - pix = s->st[cx] >> 7; - s->st[cx] = (s->st[cx] & 0x80) | prob[ss].nmps; - } - } - else - { - pix = s->st[cx] >> 7; - } - } - - return pix; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_decode_restart(t81_t82_arith_decode_state_t *s, int reuse_st) -{ - if (!reuse_st) - memset(s->st, 0, sizeof(s->st)); - s->c = 0; - s->a = 1; - s->ct = 0; - s->startup = true; - s->nopadding = false; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t81_t82_arith_decode_state_t *) t81_t82_arith_decode_init(t81_t82_arith_decode_state_t *s) -{ - if (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); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_decode_release(t81_t82_arith_decode_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t81_t82_arith_decode_free(t81_t82_arith_decode_state_t *s) -{ - int ret; - - ret = t81_t82_arith_decode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t85_decode.c b/libs/spandsp/src/t85_decode.c deleted file mode 100644 index 2bc32e7212..0000000000 --- a/libs/spandsp/src/t85_decode.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t85_decode.c - ITU T.85 JBIG for FAX image decompression - * - * Written by Steve Underwood - * - * Copyright (C) 2009, 2010 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_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" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/t81_t82_arith_coding.h" -#include "spandsp/private/t85.h" - -static __inline__ int32_t pack_32(const uint8_t *s) -{ - int32_t value; - - value = (((int32_t) s[0] << 24) | ((int32_t) s[1] << 16) | ((int32_t) s[2] << 8) | (int32_t) s[3]); - return value; -} -/*- End of function --------------------------------------------------------*/ - -/* Decode some PSCD bytes, output the decoded rows as they are completed. Return - the number of bytes which have actually been read. This will be less than len - if a marker segment was part of the data or if the final byte was 0xFF, meaning - that this code can not determine whether we have a marker segment. */ -static size_t decode_pscd(t85_decode_state_t *s, const uint8_t data[], size_t len) -{ - uint8_t *hp[3]; - int32_t o; - int cx; - int i; - int pix; - int slntp; - int buffered_rows; - - buffered_rows = (s->options & T85_LRLTWO) ? 2 : 3; - /* Forward data to the arithmetic decoder */ - 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++) - { - /* Point to the current image bytes */ - for (i = 0; i < 3; i++) - hp[i] = s->row_buf + s->p[i]*s->bytes_per_row + (s->x >> 3); - - /* Adaptive template changes */ - if (s->x == 0 && s->pseudo) - { - for (i = 0; i < s->at_moves; i++) - { - if (s->at_row[i] == s->i) - s->tx = s->at_tx[i]; - } - } - - /* Typical prediction */ - if ((s->options & T85_TPBON) && s->pseudo) - { - slntp = t81_t82_arith_decode(&s->s, (s->options & T85_LRLTWO) ? TPB2CX : TPB3CX); - if (slntp < 0) - return s->s.pscd_ptr - data; - s->lntp = !(slntp ^ s->lntp); - if (!s->lntp) - { - /* This row is 'typical' (i.e. identical to the previous one) */ - if (s->p[1] < 0) - { - /* First row of page or (following SDRST) of stripe */ - for (i = 0; i < s->bytes_per_row; i++) - hp[0][i] = 0; - s->interrupt = s->row_write_handler(s->row_write_user_data, hp[0], s->bytes_per_row); - /* Rotate the ring buffer that holds the last few rows */ - s->p[2] = s->p[1]; - s->p[1] = s->p[0]; - if (++(s->p[0]) >= buffered_rows) - s->p[0] = 0; - } - else - { - s->interrupt = s->row_write_handler(s->row_write_user_data, hp[1], s->bytes_per_row); - /* Duplicate the last row in the ring buffer */ - s->p[2] = s->p[1]; - } - continue; - } - /* This row is 'not typical' and has to be coded completely */ - } - s->pseudo = false; - - if (s->x == 0) - { - s->row_h[0] = 0; - s->row_h[1] = (s->p[1] >= 0) ? ((int32_t) hp[1][0] << 8) : 0; - s->row_h[2] = (s->p[2] >= 0) ? ((int32_t) hp[2][0] << 8) : 0; - } - - /* Decode row */ - while (s->x < s->xd) - { - if ((s->x & 7) == 0) - { - if (s->x < (s->bytes_per_row - 1)*8 && s->p[1] >= 0) - { - s->row_h[1] |= hp[1][1]; - if (s->p[2] >= 0) - s->row_h[2] |= hp[2][1]; - } - } - if ((s->options & T85_LRLTWO)) - { - /* Two row template */ - do - { - cx = (s->row_h[0] & 0x00F); - if (s->tx) - { - cx |= ((s->row_h[1] >> 9) & 0x3E0); - if (s->x >= (uint32_t) s->tx) - { - if (s->tx < 8) - { - cx |= ((s->row_h[0] >> (s->tx - 5)) & 0x010); - } - else - { - o = (s->x - s->tx) - (s->x & ~7); - cx |= (((hp[0][o >> 3] >> (7 - (o & 7))) & 1) << 4); - } - } - } - else - { - cx |= ((s->row_h[1] >> 9) & 0x3F0); - } - pix = t81_t82_arith_decode(&s->s, cx); - if (pix < 0) - return s->s.pscd_ptr - data; - s->row_h[0] = (s->row_h[0] << 1) | pix; - s->row_h[1] <<= 1; - } - while ((++s->x & 7) && s->x < s->xd); - } - else - { - /* Three row template */ - do - { - cx = ((s->row_h[2] >> 7) & 0x380) | (s->row_h[0] & 0x003); - if (s->tx) - { - cx |= ((s->row_h[1] >> 11) & 0x078); - if (s->x >= (uint32_t) s->tx) - { - if (s->tx < 8) - { - cx |= ((s->row_h[0] >> (s->tx - 3)) & 0x004); - } - else - { - o = (s->x - s->tx) - (s->x & ~7); - cx |= (((hp[0][o >> 3] >> (7 - (o & 7))) & 1) << 2); - } - } - } - else - { - cx |= ((s->row_h[1] >> 11) & 0x07C); - } - pix = t81_t82_arith_decode(&s->s, cx); - if (pix < 0) - return s->s.pscd_ptr - data; - s->row_h[0] = (s->row_h[0] << 1) | pix; - s->row_h[1] <<= 1; - s->row_h[2] <<= 1; - } - while ((++s->x & 7) && s->x < s->xd); - } - *hp[0]++ = s->row_h[0]; - hp[1]++; - hp[2]++; - } - *(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; - /* Shuffle the row buffers */ - s->p[2] = s->p[1]; - s->p[1] = s->p[0]; - if (++(s->p[0]) >= buffered_rows) - s->p[0] = 0; - } - return s->s.pscd_ptr - data; -} -/*- End of function --------------------------------------------------------*/ - -static int finish_sde(t85_decode_state_t *s) -{ - /* Decode final pixels based on trailing zero bytes */ - s->s.nopadding = false; - if (decode_pscd(s, s->buffer, 2) != 2 && s->interrupt) - return 1; - - /* Prepare decoder for next SDE */ - t81_t82_arith_decode_restart(&s->s, s->buffer[1] == T82_SDNORM); - s->s.nopadding = s->options & T85_VLENGTH; - - s->x = 0; - s->i = 0; - s->pseudo = true; - s->at_moves = 0; - if (s->buffer[1] == T82_SDRST) - { - s->tx = 0; - s->lntp = true; - s->p[0] = 0; - s->p[1] = -1; - s->p[2] = -1; - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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 */ - /* DL - Initial layer to be transmitted */ - /* D - Number of differential layers */ - /* Unspecified byte */ - /* MY - Maximum vertical offset allowed for AT pixel */ - /* Order byte */ - if (s->buffer[0] != 0 - || - s->buffer[1] != 0 - || - s->buffer[3] != 0 - || - s->buffer[17] != 0 - || -#if T85_STRICT_ORDER_BITS - s->buffer[18] != 0) -#else - (s->buffer[18] & 0xF0) != 0) -#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 */ - 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; - } - 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; - } - 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; - } - 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; - } - 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); - return T4_DECODE_OK; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t85_decode_rx_status(t85_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, NULL, 0); - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected rx status - %d!\n", status); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], size_t len) -{ - int ret; - uint32_t y; - uint8_t *buf; - size_t bytes_per_row; - size_t min_len; - size_t chunk; - size_t cnt; - int i; - - if (len == 0) - { - 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; - } - - s->compressed_image_size += len; - cnt = 0; - - if (s->bie_len < 20) - { - /* Read in the 20-byte BIH */ - i = (s->bie_len + len > 20) ? (20 - s->bie_len) : len; - memcpy(&s->buffer[s->bie_len], data, i); - s->bie_len += i; - cnt = i; - if (s->bie_len < 20) - return T4_DECODE_MORE_DATA; - if ((ret = extract_bih(s)) != T4_DECODE_OK) - return ret; - /* Set up the two/three row buffer */ - bytes_per_row = (s->xd + 7) >> 3; - min_len = ((s->options & T85_LRLTWO) ? 2 : 3)*bytes_per_row; - if (min_len > s->row_buf_len) - { - /* We need to expand the 3 row buffer */ - 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; - } - - t81_t82_arith_decode_init(&s->s); - s->s.nopadding = s->options & T85_VLENGTH; - if (s->comment) - { - span_free(s->comment); - s->comment = NULL; - } - s->comment_len = 0; - s->comment_progress = 0; - s->buf_len = 0; - s->buf_needed = 2; - s->x = 0; - s->y = 0; - s->i = 0; - s->pseudo = true; - s->at_moves = 0; - s->tx = 0; - s->lntp = true; - s->bytes_per_row = bytes_per_row; - s->p[0] = 0; - s->p[1] = -1; - s->p[2] = -1; - } - - /* BID processing loop */ - while (cnt < len || s->end_of_data == 1) - { - if (s->end_of_data == 1) - { - s->buf_needed = 2; - s->options &= ~T85_VLENGTH; - s->end_of_data = 2; - } - if (s->comment_len) - { - /* We are in a COMMENT. Absorb its contents */ - chunk = len - cnt; - if ((s->comment_progress + chunk) >= s->comment_len) - { - /* Finished */ - chunk = s->comment_len - s->comment_progress; - /* If the comment was too long to be passed to the handler, we still - call the handler with the buffer set to NULL, so it knows a large - comment has occurred. */ - if (s->comment) - memcpy(&s->comment[s->comment_progress], &data[cnt], chunk); - if (s->comment_handler) - s->interrupt = s->comment_handler(s->comment_user_data, s->comment, s->comment_len); - if (s->comment) - { - span_free(s->comment); - s->comment = NULL; - } - s->comment_len = 0; - s->comment_progress = 0; - } - else - { - if (s->comment) - memcpy(&s->comment[s->comment_progress], &data[cnt], chunk); - s->comment_progress += chunk; - } - cnt += chunk; - continue; - } - - /* Load marker segments into s->buffer for processing */ - if (s->buf_len > 0) - { - /* We are in a marker of some kind. Load the first 2 bytes of - the marker, so we can determine its type, and hence its full - length. */ - while (s->buf_len < s->buf_needed && cnt < len) - s->buffer[s->buf_len++] = data[cnt++]; - /* Check we have enough bytes to see the message type */ - if (s->buf_len < s->buf_needed) - continue; - switch (s->buffer[1]) - { - case T82_STUFF: - /* Forward stuffed 0xFF to arithmetic decoder. This is likely to be - 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; - case T82_ABORT: - s->buf_len = 0; - return T4_DECODE_ABORTED; - case T82_COMMENT: - s->buf_needed = 6; - if (s->buf_len < 6) - continue; - s->buf_needed = 2; - s->buf_len = 0; - - 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 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 = span_alloc(s->comment_len); - s->comment_progress = 0; - continue; - case T82_ATMOVE: - s->buf_needed = 8; - if (s->buf_len < 8) - 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 - || - (s->at_tx[s->at_moves] > 0 && s->at_tx[s->at_moves] < ((s->options & T85_LRLTWO) ? 5 : 3)) - || - s->buffer[7] != 0) - { - s->end_of_data = 2; - return T4_DECODE_INVALID_DATA; - } - s->at_moves++; - break; - case T82_NEWLEN: - s->buf_needed = 6; - if (s->buf_len < 6) - 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: - case T82_SDRST: - if (!(s->options & T85_VLENGTH)) - { - /* A plain SDNORM or SDRST with no peek ahead required */ - s->buf_len = 0; - if (finish_sde(s)) - return T4_DECODE_INTERRUPT; - /* Check whether this was the last SDE */ - if (s->y >= s->yd) - { - s->compressed_image_size -= (len - cnt); - return T4_DECODE_OK; - } - break; - } - /* This is the messy case. We need to peek ahead, as this element - might be immediately followed by a T82_NEWLEN which affects the - limit of what we decode here. */ - if (s->buf_needed < 3) - s->buf_needed = 3; - if (s->buf_len < 3) - continue; - /* Peek ahead to see whether a NEWLEN marker segment follows */ - if (s->buffer[2] != T82_ESC) - { - /* This is not an escape sequence, so push the single peek-ahead - byte back into the buffer. We should always have just grabbed - at least one byte, so this should be safe. */ - s->buf_needed = 2; - s->buf_len = 0; - cnt--; - /* Process the T82_SDNORM or T82_SDRST */ - if (finish_sde(s)) - return T4_DECODE_INTERRUPT; - /* Check whether this was the last SDE */ - if (s->y >= s->yd) - { - s->compressed_image_size -= (len - cnt); - return T4_DECODE_OK; - } - break; - } - if (s->buf_needed < 4) - s->buf_needed = 4; - if (s->buf_len < 4) - continue; - if (s->buffer[3] != T82_NEWLEN) - { - s->buf_needed = 2; - - /* Process the T82_SDNORM or T82_SDRST */ - if (finish_sde(s)) - return T4_DECODE_INTERRUPT; - /* Check whether this was the last SDE */ - if (s->y >= s->yd) - { - s->compressed_image_size -= (len - cnt); - return T4_DECODE_OK; - } - /* Recycle the two peek-ahead marker sequence bytes to - be processed later. */ - s->buffer[0] = s->buffer[2]; - s->buffer[1] = s->buffer[3]; - s->buf_len = 2; - break; - } - if (s->buf_needed < 8) - s->buf_needed = 8; - if (s->buf_len < 8) - continue; - s->buf_needed = 2; - s->buf_len = 0; - /* We must have a complete T82_NEWLEN to be here, which we need - to process immediately. */ - s->options &= ~T85_VLENGTH; - 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 */ - if (finish_sde(s)) - return T4_DECODE_INTERRUPT; - /* We might be at the end of the image now, but even if we are - there should still be a final training T82_SDNORM or T82_SDRST - that we should pick up. When we do, we won't wait for further - T82_NEWLEN entries, so we should stop crisply on the last byte - of the image. */ - break; - default: - s->buf_len = 0; - s->end_of_data = 2; - return T4_DECODE_INVALID_DATA; - } - } - else if (cnt < len && data[cnt] == T82_ESC) - { - s->buffer[s->buf_len++] = data[cnt++]; - } - else - { - /* We have found PSCD bytes */ - 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 */ - 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 --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_set_row_write_handler(t85_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; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_set_comment_handler(t85_decode_state_t *s, - uint32_t max_comment_len, - t4_row_write_handler_t handler, - void *user_data) -{ - s->max_comment_len = max_comment_len; - s->comment_handler = handler; - s->comment_user_data = user_data; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_set_image_size_constraints(t85_decode_state_t *s, - uint32_t max_xd, - uint32_t max_yd) -{ - s->max_xd = max_xd; - s->max_yd = max_yd; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t85_decode_get_image_width(t85_decode_state_t *s) -{ - return s->xd; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t85_decode_get_image_length(t85_decode_state_t *s) -{ - return s->yd; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_get_compressed_image_size(t85_decode_state_t *s) -{ - return s->compressed_image_size*8; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_new_plane(t85_decode_state_t *s) -{ - if (s->current_bit_plane >= s->bit_planes - 1) - return -1; - - s->current_bit_plane++; - s->tx = 0; - memset(s->buffer, 0, sizeof(s->buffer)); - s->buf_len = 0; - s->buf_needed = 0; - s->at_moves = 0; - 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->end_of_data = 0; - if (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); - s->s.nopadding = s->options & T85_VLENGTH; - - s->buf_len = 0; - s->buf_needed = 2; - s->x = 0; - s->y = 0; - s->i = 0; - s->pseudo = true; - s->at_moves = 0; - s->tx = 0; - s->lntp = true; - s->p[0] = 0; - s->p[1] = -1; - s->p[2] = -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) t85_decode_get_logging_state(t85_decode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_restart(t85_decode_state_t *s) -{ - s->xd = 0; - s->yd = 0; - s->l0 = 0; - s->mx = 0; - s->bytes_per_row = 0; - s->tx = 0; - s->bie_len = 0; - memset(s->buffer, 0, sizeof(s->buffer)); - s->buf_len = 0; - s->buf_needed = 0; - s->at_moves = 0; - 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->end_of_data = 0; - if (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); - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t85_decode_state_t *) t85_decode_init(t85_decode_state_t *s, - t4_row_write_handler_t handler, - void *user_data) -{ - if (s == NULL) - { - if ((s = (t85_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.85"); - - s->row_write_handler = handler; - s->row_write_user_data = user_data; - - s->min_bit_planes = 1; - s->max_bit_planes = 1; - - s->max_xd = 0; - s->max_yd = 0; - - t81_t82_arith_decode_init(&s->s); - t85_decode_restart(s); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_release(t85_decode_state_t *s) -{ - if (s->row_buf) - { - span_free(s->row_buf); - s->row_buf = NULL; - } - if (s->comment) - { - span_free(s->comment); - s->comment = NULL; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_decode_free(t85_decode_state_t *s) -{ - int ret; - - ret = t85_decode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t85_encode.c b/libs/spandsp/src/t85_encode.c deleted file mode 100644 index 8c35c5465b..0000000000 --- a/libs/spandsp/src/t85_encode.c +++ /dev/null @@ -1,753 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t85_encode.c - ITU T.85 JBIG for FAX image compression - * - * Written by Steve Underwood - * - * Copyright (C) 2009, 2010 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_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" -#include "spandsp/t4_rx.h" -#include "spandsp/t4_tx.h" -#include "spandsp/t81_t82_arith_coding.h" -#include "spandsp/t85.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/t81_t82_arith_coding.h" -#include "spandsp/private/t85.h" - -/* Image length update status */ -enum -{ - NEWLEN_NONE = 0, - NEWLEN_PENDING = 1, - NEWLEN_HANDLED = 2 -}; - -static __inline__ void unpack_32(uint8_t *s, int32_t value) -{ - s[3] = value & 0xFF; - value >>= 8; - s[2] = value & 0xFF; - value >>= 8; - s[1] = value & 0xFF; - value >>= 8; - s[0] = value & 0xFF; -} -/*- End of function --------------------------------------------------------*/ - -static void put_stuff(t85_encode_state_t *s, const uint8_t buf[], int len) -{ - uint8_t *new_buf; - uint32_t bytes_per_row; - - if (s->bitstream_iptr + len >= s->bitstream_len) - { - /* TODO: Handle memory allocation errors properly */ - /* 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 = span_realloc(s->bitstream, s->bitstream_len + len + bytes_per_row)) == NULL) - return; - s->bitstream = new_buf; - s->bitstream_len += (len + bytes_per_row); - } - memcpy(&s->bitstream[s->bitstream_iptr], buf, len); - s->bitstream_iptr += len; - s->compressed_image_size += len; -} -/*- End of function --------------------------------------------------------*/ - -/* Callback function for the arithmetic encoder */ -static void output_byte(void *user_data, int byte) -{ - t85_encode_state_t *s; - uint8_t c = byte; - - s = (t85_encode_state_t *) user_data; - c = (uint8_t) byte; - put_stuff(s, &c, 1); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void output_esc_code(t85_encode_state_t *s, int code) -{ - uint8_t buf[2]; - - buf[0] = T82_ESC; - buf[1] = code; - put_stuff(s, buf, 2); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void output_newlen(t85_encode_state_t *s) -{ - uint8_t buf[6]; - - if (s->newlen == NEWLEN_PENDING) - { - buf[0] = T82_ESC; - buf[1] = T82_NEWLEN; - unpack_32(&buf[2], s->yd); - put_stuff(s, buf, 6); - if (s->y == s->yd) - { - /* See T.82/6.2.6.2 */ - output_esc_code(s, T82_SDNORM); - } - s->newlen = NEWLEN_HANDLED; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void output_comment(t85_encode_state_t *s) -{ - uint8_t buf[6]; - - if (s->comment) - { - buf[0] = T82_ESC; - buf[1] = T82_COMMENT; - unpack_32(&buf[2], s->comment_len); - put_stuff(s, buf, 6); - put_stuff(s, s->comment, s->comment_len); - s->comment = NULL; - s->comment_len = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void output_atmove(t85_encode_state_t *s) -{ - uint8_t buf[8]; - - if (s->new_tx >= 0 && s->new_tx != s->tx) - { - s->tx = s->new_tx; - buf[0] = T82_ESC; - buf[1] = T82_ATMOVE; - unpack_32(&buf[2], 0); - buf[6] = s->tx; - buf[7] = 0; - put_stuff(s, buf, 8); - } -} -/*- End of function --------------------------------------------------------*/ - -static void generate_bih(t85_encode_state_t *s, uint8_t *buf) -{ - /* DL - Initial layer to be transmitted */ - buf[0] = 0; - /* D - Number of differential layers */ - buf[1] = 0; - /* P - Number of bit planes */ - buf[2] = s->bit_planes; - /* Unspecified */ - buf[3] = 0; - /* XD - Horizontal image size at layer D */ - unpack_32(&buf[4], s->xd); - /* YD - Vertical image size at layer D */ - unpack_32(&buf[8], s->yd); - /* L0 - Rows per stripe, at the lowest resolution */ - unpack_32(&buf[12], s->l0); - /* MX - Maximum horizontal offset allowed for AT pixel */ - buf[16] = s->mx; - /* MY - Maximum vertical offset allowed for AT pixel */ - buf[17] = 0; - /* Order byte: */ - /* 4 unused bits */ - /* HITOLO - transmission order of differential layers */ - /* SEQ - indication of progressive-compatible sequential coding */ - /* ILEAVE - interleaved transmission order of multiple bit plane */ - /* SMID - transmission order of stripes */ - /* Note that none of these are relevant to T.85 */ - buf[18] = 0; - /* Options byte: */ - /* 1 unused bit */ - /* LRLTWO - number of reference rows */ - /* VLENGTH - indication of possible use of NEWLEN marker segment */ - /* TPDON - use of TP for Typical Prediction for differential layers */ - /* TPBON - use of TP for base layer */ - /* DPON - use of Deterministic Prediction */ - /* DPPRIV - use of private DP table */ - /* DPLAST - use of last DP table */ - /* Note that only T85_TPBON, T85_VLENGTH, and T85_LRLTWO are relevant to T.85 */ - buf[19] = s->options; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t85_encode_set_options(t85_encode_state_t *s, - uint32_t l0, - int mx, - int options) -{ - if (s->y > 0) - return; - - /* Its still OK to change things */ - if (l0 >= 1 && l0 <= s->yd) - s->l0 = l0; - if (mx >= 0 && mx <= 127) - s->mx = mx; - if (options >= 0) - s->options = options & (T85_TPBON | T85_VLENGTH | T85_LRLTWO); -} -/*- End of function --------------------------------------------------------*/ - -static int get_next_row(t85_encode_state_t *s) -{ - uint8_t buf[20]; - uint32_t bytes_per_row; - const uint8_t *hp[3]; - uint8_t *z; - uint32_t row_h[3]; - uint32_t j; - int32_t o; - uint32_t a; - uint32_t p; - uint32_t t; - uint32_t c_min; - uint32_t c_max; - uint32_t cl_min; - uint32_t cl_max; - int ltp; - int cx; - int t_max; - int i; - - if (s->y >= s->yd) - { - /* We have already finished pumping out the image */ - return -1; - } - - s->bitstream_iptr = 0; - s->bitstream_optr = 0; - bytes_per_row = (s->xd + 7) >> 3; - /* Rotate the three rows which we buffer */ - z = s->prev_row[2]; - s->prev_row[2] = s->prev_row[1]; - s->prev_row[1] = s->prev_row[0]; - s->prev_row[0] = z; - - /* Copy the new row to our buffer, and ensure the last byte of the row is - zero padded. The need to tweak this is actually the only reason for - storing a third row. We do not want to tamper with the source buffer. */ - if (s->fill_with_white) - { - memset(s->prev_row[0], 0, bytes_per_row); - } - else - { - if (s->row_read_handler(s->row_read_user_data, s->prev_row[0], bytes_per_row) <= 0) - { - /* The source has stopped feeding us rows early. Try to clip the image - to the current size. */ - if (t85_encode_set_image_length(s, 1) == 0) - 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; - memset(s->prev_row[0], 0, bytes_per_row); - } - } - if ((s->xd & 7)) - s->prev_row[0][bytes_per_row - 1] &= ~((1 << (8 - (s->xd & 7))) - 1); - - if (s->current_bit_plane == 0 && s->y == 0) - { - /* Things that need to be done before the first row is encoded */ - generate_bih(s, buf); - put_stuff(s, buf, 20); - } - - if (s->i == 0) - { - /* Things that need to be done before the next SDE is encoded */ - output_newlen(s); - output_comment(s); - output_atmove(s); - if (s->mx == 0) - { - /* Disable ATMOVE analysis */ - s->new_tx = 0; - } - else - { - /* Enable ATMOVE analysis */ - s->new_tx = -1; - s->c_all = 0; - for (i = 0; i <= s->mx; i++) - s->c[i] = 0; - } - t81_t82_arith_encode_restart(&s->s, true); - } - - /* Typical prediction */ - ltp = false; - if ((s->options & T85_TPBON)) - { - /* Look for a match between the rows */ - ltp = (memcmp(s->prev_row[0], s->prev_row[1], bytes_per_row) == 0); - t81_t82_arith_encode(&s->s, - (s->options & T85_LRLTWO) ? TPB2CX : TPB3CX, - (ltp == s->prev_ltp)); - s->prev_ltp = ltp; - } - - if (!ltp) - { - /* Pointer to the first image byte in each the three rows of interest */ - hp[0] = s->prev_row[0]; - hp[1] = s->prev_row[1]; - hp[2] = s->prev_row[2]; - - row_h[0] = 0; - row_h[1] = (uint32_t) hp[1][0] << 8; - row_h[2] = (uint32_t) hp[2][0] << 8; - - /* Encode row */ - for (j = 0; j < s->xd; ) - { - row_h[0] |= hp[0][0]; - if (j < (bytes_per_row - 1)*8) - { - row_h[1] |= hp[1][1]; - row_h[2] |= hp[2][1]; - } - if ((s->options & T85_LRLTWO)) - { - /* Two row template */ - do - { - row_h[0] <<= 1; - row_h[1] <<= 1; - row_h[2] <<= 1; - cx = (row_h[0] >> 9) & 0x00F; - if (s->tx) - { - cx |= ((row_h[1] >> 10) & 0x3E0); - if (j >= (uint32_t) s->tx) - { - o = (j - s->tx) - (j & ~7); - cx |= (((hp[0][o >> 3] >> (7 - (o & 7))) & 1) << 4); - } - } - else - { - cx |= ((row_h[1] >> 10) & 0x3F0); - } - p = (row_h[0] >> 8) & 1; - t81_t82_arith_encode(&s->s, cx, p); - - /* Update the statistics for adaptive template changes, - if this analysis is in progress. */ - if (s->new_tx < 0 && j >= s->mx && j < s->xd - 2) - { - if (p == ((row_h[1] >> 14) & 1)) - s->c[0]++; - for (t = 5; t <= s->mx && t <= j; t++) - { - o = (j - t) - (j & ~7); - a = (hp[0][o >> 3] >> (7 - (o & 7))) & 1; - if (a == p) - s->c[t]++; - } - if (p == 0) - { - for ( ; t <= s->mx; t++) - s->c[t]++; - } - ++s->c_all; - } - } - while ((++j & 7) && j < s->xd); - } - else - { - /* Three row template */ - do - { - row_h[0] <<= 1; - row_h[1] <<= 1; - row_h[2] <<= 1; - cx = ((row_h[2] >> 8) & 0x380) | ((row_h[0] >> 9) & 0x003); - if (s->tx) - { - cx |= ((row_h[1] >> 12) & 0x078); - if (j >= (uint32_t) s->tx) - { - o = (j - s->tx) - (j & ~7); - cx |= (((hp[0][o >> 3] >> (7 - (o & 7))) & 1) << 2); - } - } - else - { - cx |= ((row_h[1] >> 12) & 0x07C); - } - p = (row_h[0] >> 8) & 1; - t81_t82_arith_encode(&s->s, cx, p); - - /* Update the statistics for adaptive template changes, - if this analysis is in progress. */ - if (s->new_tx < 0 && j >= s->mx && j < s->xd - 2) - { - if (p == ((row_h[1] >> 14) & 1)) - s->c[0]++; - for (t = 3; t <= s->mx && t <= j; t++) - { - o = (j - t) - (j & ~7); - a = (hp[0][o >> 3] >> (7 - (o & 7))) & 1; - if (a == p) - s->c[t]++; - } - if (p == 0) - { - for ( ; t <= s->mx; t++) - s->c[t]++; - } - ++s->c_all; - } - } - while ((++j & 7) && j < s->xd); - } - hp[0]++; - hp[1]++; - hp[2]++; - } - } - - s->i++; - s->y++; - if (s->i == s->l0 || s->y == s->yd) - { - /* We are at the end of the stripe */ - t81_t82_arith_encode_flush(&s->s); - output_esc_code(s, T82_SDNORM); - s->i = 0; - output_newlen(s); - } - - /* T.82/Annex C - is it time for an adaptive template change? */ - if (s->new_tx < 0 && s->c_all > 2048) - { - c_min = - cl_min = UINT32_MAX; - c_max = - cl_max = 0; - t_max = 0; - for (i = (s->options & T85_LRLTWO) ? 5 : 3; i <= s->mx; i++) - { - if (s->c[i] > c_max) - c_max = s->c[i]; - if (s->c[i] < c_min) - c_min = s->c[i]; - if (s->c[i] > s->c[t_max]) - t_max = i; - } - cl_min = (s->c[0] < c_min) ? s->c[0] : c_min; - cl_max = (s->c[0] > c_max) ? s->c[0] : c_max; - /* This test is straight from T.82/Figure C.2 */ - if ((s->c_all - c_max) < (s->c_all >> 3) - && - (c_max - s->c[s->tx]) > (s->c_all - c_max) - && - (c_max - s->c[s->tx]) > (s->c_all >> 4) - && - (c_max - (s->c_all - s->c[s->tx])) > (s->c_all - c_max) - && - (c_max - (s->c_all - s->c[s->tx])) > (s->c_all >> 4) - && - (c_max - c_min) > (s->c_all >> 2) - && - (s->tx || (cl_max - cl_min) > (s->c_all >> 3))) - { - /* It is time to perform an ATMOVE */ - s->new_tx = t_max; - } - else - { - /* Disable further analysis */ - s->new_tx = s->tx; - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_set_image_width(t85_encode_state_t *s, uint32_t image_width) -{ - int bytes_per_row; - uint8_t *t; - - if (s->xd == image_width) - return 0; - /* Are we too late to change the width for this page? */ - if (s->y > 0) - return -1; - s->xd = image_width; - bytes_per_row = (s->xd + 7) >> 3; - 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); - s->prev_row[0] = s->row_buf; - s->prev_row[1] = s->row_buf + bytes_per_row; - s->prev_row[2] = s->row_buf + 2*bytes_per_row; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_set_image_length(t85_encode_state_t *s, uint32_t image_length) -{ - /* We must have variable length enabled. - We do not allow the length to be changed multiple times. - We only allow an image to be shrunk, and not stretched. - We do not allow the length to become zero. */ - if (!(s->options & T85_VLENGTH) || s->newlen == NEWLEN_HANDLED || image_length >= s->yd || image_length < 1) - { - /* Invalid parameter */ - return -1; - } - if (s->y > 0) - { - /* TODO: If we are already beyond the new length, we scale back the new length silently. - Is there any downside to this? */ - if (image_length < s->y) - image_length = s->y; - if (s->yd != image_length) - s->newlen = NEWLEN_PENDING; - } - s->yd = image_length; - if (s->y == s->yd) - { - /* We are already at the end of the image, so finish it off. */ - if (s->i > 0) - { - t81_t82_arith_encode_flush(&s->s); - output_esc_code(s, T82_SDNORM); - s->i = 0; - } - output_newlen(s); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t85_encode_abort(t85_encode_state_t *s) -{ - output_esc_code(s, T82_ABORT); - /* Make the image appear to be complete, so the encoder stops outputting. - Take care, as this means s->y is now telling lies. */ - s->y = s->yd; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t85_encode_comment(t85_encode_state_t *s, const uint8_t comment[], size_t len) -{ - s->comment = comment; - s->comment_len = len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_image_complete(t85_encode_state_t *s) -{ - if (s->y >= s->yd) - return SIG_STATUS_END_OF_DATA; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_get(t85_encode_state_t *s, uint8_t buf[], size_t max_len) -{ - int len; - int n; - - for (len = 0; len < max_len; len += n) - { - if (s->bitstream_optr >= s->bitstream_iptr) - { - if (get_next_row(s) < 0) - return len; - } - n = s->bitstream_iptr - s->bitstream_optr; - if (n > max_len - len) - n = max_len - len; - memcpy(&buf[len], &s->bitstream[s->bitstream_optr], n); - s->bitstream_optr += n; - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t85_encode_get_image_width(t85_encode_state_t *s) -{ - return s->xd; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(uint32_t) t85_encode_get_image_length(t85_encode_state_t *s) -{ - return s->yd; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_get_compressed_image_size(t85_encode_state_t *s) -{ - return s->compressed_image_size*8; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_set_row_read_handler(t85_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 *) t85_encode_get_logging_state(t85_encode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_restart(t85_encode_state_t *s, uint32_t image_width, uint32_t image_length) -{ - int bytes_per_row; - - /* Allow the image width to be anything, although only a few values are actually - permitted by the T.85 and T.4 specs. Higher levels in the stack need to impose - these restrictions. */ - t85_encode_set_image_width(s, image_width); - bytes_per_row = (s->xd + 7) >> 3; - memset(s->row_buf, 0, 3*bytes_per_row); - s->yd = image_length; - - s->comment = NULL; - s->comment_len = 0; - s->y = 0; - s->i = 0; - s->newlen = NEWLEN_NONE; - s->new_tx = -1; - s->tx = 0; - s->prev_ltp = false; - s->bitstream_iptr = 0; - s->bitstream_optr = 0; - if (s->bitstream) - { - span_free(s->bitstream); - s->bitstream = NULL; - } - s->bitstream_len = 0; - s->fill_with_white = false; - s->compressed_image_size = 0; - - t81_t82_arith_encode_init(&s->s, output_byte, s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(t85_encode_state_t *) t85_encode_init(t85_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 = (t85_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.85"); - - s->row_read_handler = handler; - s->row_read_user_data = user_data; - - /* T.85 BASIC setting for L0. In T.85 this may only be changed if T.30 negotiation permits. */ - s->l0 = 128; - /* No ATMOVE pending */ - s->mx = 127; - /* Default options */ - s->options = T85_TPBON | T85_VLENGTH; - - s->bitstream = NULL; - s->bitstream_len = 0; - - s->bit_planes = 1; - s->current_bit_plane = 0; - - t85_encode_restart(s, image_width, image_length); - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_release(t85_encode_state_t *s) -{ - if (s->row_buf) - { - span_free(s->row_buf); - s->row_buf = NULL; - } - if (s->bitstream) - { - span_free(s->bitstream); - s->bitstream = NULL; - s->bitstream_len = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t85_encode_free(t85_encode_state_t *s) -{ - int ret; - - ret = t85_encode_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/testcpuid.c b/libs/spandsp/src/testcpuid.c deleted file mode 100644 index ccf24d1d78..0000000000 --- a/libs/spandsp/src/testcpuid.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * testcpuid.c - Check the CPU type, to identify special features, like SSE. - * - * Written by Steve Underwood - * Stitched together from bits of testing code found here and there - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include - -/* Make this file just disappear if we are not on an x86 machine */ -#if defined(__i386__) // || defined(__x86_64__) - -enum -{ - X86_EFLAGS_CF = 0x00000001, /* Carry Flag */ - X86_EFLAGS_PF = 0x00000004, /* Parity Flag */ - X86_EFLAGS_AF = 0x00000010, /* Auxillary carry Flag */ - X86_EFLAGS_ZF = 0x00000040, /* Zero Flag */ - X86_EFLAGS_SF = 0x00000080, /* Sign Flag */ - X86_EFLAGS_TF = 0x00000100, /* Trap Flag */ - X86_EFLAGS_IF = 0x00000200, /* Interrupt Flag */ - X86_EFLAGS_DF = 0x00000400, /* Direction Flag */ - X86_EFLAGS_OF = 0x00000800, /* Overflow Flag */ - X86_EFLAGS_IOPL = 0x00003000, /* IOPL mask */ - X86_EFLAGS_NT = 0x00004000, /* Nested Task */ - X86_EFLAGS_RF = 0x00010000, /* Resume Flag */ - X86_EFLAGS_VM = 0x00020000, /* Virtual Mode */ - X86_EFLAGS_AC = 0x00040000, /* Alignment Check */ - X86_EFLAGS_VIF = 0x00080000, /* Virtual Interrupt Flag */ - X86_EFLAGS_VIP = 0x00100000, /* Virtual Interrupt Pending */ - X86_EFLAGS_ID = 0x00200000 /* CPUID detection flag */ -}; - -/* Standard macro to see if a specific flag is changeable */ -static __inline__ int flag_is_changeable_p(uint32_t flag) -{ - uint32_t f1; - uint32_t f2; - - __asm__ __volatile__( - " pushfl\n" - " pushfl\n" - " popl %0\n" - " movl %0,%1\n" - " xorl %2,%0\n" - " pushl %0\n" - " popfl\n" - " pushfl\n" - " popl %0\n" - " popfl\n" - : "=&r" (f1), "=&r" (f2) - : "ir" (flag)); - return ((f1^f2) & flag) != 0; -} -/*- End of function --------------------------------------------------------*/ - -/* Probe for the CPUID instruction */ -static int have_cpuid_p(void) -{ - return flag_is_changeable_p(X86_EFLAGS_ID); -} -/*- End of function --------------------------------------------------------*/ - -int has_MMX(void) -{ - int result; - - if (!have_cpuid_p()) - return 0; - /*endif*/ - __asm__ __volatile__( - " push %%ebx;\n" - " mov $1,%%eax;\n" - " cpuid;\n" - " xor %%eax,%%eax;\n" - " test $0x800000,%%edx;\n" - " jz 1f;\n" /* no MMX support */ - " inc %%eax;\n" /* MMX support */ - "1:\n" - " pop %%ebx;\n" - : "=a" (result) - : - : "ecx", "edx"); - return result; -} -/*- End of function --------------------------------------------------------*/ - -int has_SIMD(void) -{ - int result; - - if (!have_cpuid_p()) - return 0; - /*endif*/ - __asm__ __volatile__( - " push %%ebx;\n" - " mov $1,%%eax;\n" - " cpuid;\n" - " xor %%eax,%%eax;\n" - " test $0x02000000,%%edx;\n" - " jz 1f;\n" /* no SIMD support */ - " inc %%eax;\n" /* SIMD support */ - "1:\n" - " pop %%ebx;\n" - : "=a" (result) - : - : "ecx", "edx"); - return result; -} -/*- End of function --------------------------------------------------------*/ - -int has_SIMD2(void) -{ - int result; - - if (!have_cpuid_p()) - return 0; - /*endif*/ - __asm__ __volatile__( - " push %%ebx;\n" - " mov $1,%%eax;\n" - " cpuid;\n" - " xor %%eax,%%eax;\n" - " test $0x04000000,%%edx;\n" - " jz 1f;\n" /* no SIMD2 support */ - " inc %%eax;\n" /* SIMD2 support */ - "1:\n" - " pop %%ebx;\n" - : "=a" (result) - : - : "ecx", "edx"); - return result; -} -/*- End of function --------------------------------------------------------*/ - -int has_3DNow(void) -{ - int result; - - if (!have_cpuid_p()) - return 0; - /*endif*/ - __asm__ __volatile__( - " push %%ebx;\n" - " mov $0x80000000,%%eax;\n" - " cpuid;\n" - " xor %%ecx,%%ecx;\n" - " cmp $0x80000000,%%eax;\n" - " jbe 1f;\n" /* no extended MSR(1), so no 3DNow! */ - " mov $0x80000001,%%eax;\n" - " cpuid;\n" - " xor %%ecx,%%ecx;\n" - " test $0x80000000,%%edx;\n" - " jz 1f;\n" /* no 3DNow! support */ - " inc %%ecx;\n" /* 3DNow! support */ - "1:\n" - " pop %%ebx;\n" - : "=c" (result) - : - : "eax", "edx"); - return result; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(TESTBED) -int main(int argc, char *argv[]) -{ - int result; - - result = has_MMX(); - printf("MMX is %x\n", result); - result = has_SIMD(); - printf("SIMD is %x\n", result); - result = has_SIMD2(); - printf("SIMD2 is %x\n", result); - result = has_3DNow(); - printf("3DNow is %x\n", result); - return 0; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/time_scale.c b/libs/spandsp/src/time_scale.c deleted file mode 100644 index a21e34cc7d..0000000000 --- a/libs/spandsp/src/time_scale.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * time_scale.c - Time scaling for linear speech data - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/vector_int.h" -#include "spandsp/saturated.h" -#include "spandsp/time_scale.h" - -#include "spandsp/private/time_scale.h" - -/* - Time scaling for speech, based on the Pointer Interval Controlled - OverLap and Add (PICOLA) method, developed by Morita Naotaka. - */ - -static __inline__ int amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len) -{ - int i; - int j; - int acc; - int min_acc; - int pitch; - - pitch = min_pitch; - min_acc = INT_MAX; - for (i = max_pitch; i <= min_pitch; i++) - { - acc = 0; - for (j = 0; j < len; j++) - acc += abs(amp[i + j] - amp[j]); - /*endfor*/ - if (acc < min_acc) - { - min_acc = acc; - pitch = i; - } - /*endif*/ - } - /*endfor*/ - return pitch; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void overlap_add(int16_t amp1[], int16_t amp2[], int len) -{ - int i; - float weight; - float step; - - step = 1.0f/len; - weight = 0.0f; - for (i = 0; i < len; i++) - { - /* TODO: saturate */ - amp1[i] = (int16_t) ((float) amp2[i]*(1.0f - weight) + (float) amp1[i]*weight); - weight += step; - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) time_scale_rate(time_scale_state_t *s, float playout_rate) -{ - if (playout_rate <= 0.0f) - return -1; - /*endif*/ - if (playout_rate >= 0.99f && playout_rate <= 1.01f) - { - /* Treat rate close to normal speed as exactly normal speed, and - avoid divide by zero, and other numerical problems. */ - playout_rate = 1.0f; - } - else if (playout_rate < 1.0f) - { - s->rcomp = playout_rate/(1.0f - playout_rate); - } - else - { - s->rcomp = 1.0f/(playout_rate - 1.0f); - } - /*endif*/ - s->playout_rate = playout_rate; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], int len) -{ - double lcpf; - int pitch; - int out_len; - int in_len; - int k; - - out_len = 0; - in_len = 0; - - if (s->playout_rate == 1.0f) - { - vec_copyi16(out, in, len); - return len; - } - /*endif*/ - - /* Top up the buffer */ - if (s->fill + len < s->buf_len) - { - /* Cannot continue without more samples */ - /* Save the residual signal for next time. */ - vec_copyi16(&s->buf[s->fill], in, len); - s->fill += len; - return 0; - } - /*endif*/ - k = s->buf_len - s->fill; - vec_copyi16(&s->buf[s->fill], in, k); - in_len += k; - s->fill = s->buf_len; - while (s->fill == s->buf_len) - { - while (s->lcp >= s->buf_len) - { - vec_copyi16(&out[out_len], s->buf, s->buf_len); - out_len += s->buf_len; - if (len - in_len < s->buf_len) - { - /* Cannot continue without more samples */ - /* Save the residual signal for next time. */ - vec_copyi16(s->buf, &in[in_len], len - in_len); - s->fill = len - in_len; - s->lcp -= s->buf_len; - return out_len; - } - /*endif*/ - vec_copyi16(s->buf, &in[in_len], s->buf_len); - in_len += s->buf_len; - s->lcp -= s->buf_len; - } - /*endwhile*/ - if (s->lcp > 0) - { - vec_copyi16(&out[out_len], s->buf, s->lcp); - out_len += s->lcp; - vec_movei16(s->buf, &s->buf[s->lcp], s->buf_len - s->lcp); - if (len - in_len < s->lcp) - { - /* Cannot continue without more samples */ - /* Save the residual signal for next time. */ - vec_copyi16(&s->buf[s->buf_len - s->lcp], &in[in_len], len - in_len); - s->fill = s->buf_len - s->lcp + len - in_len; - s->lcp = 0; - return out_len; - } - /*endif*/ - vec_copyi16(&s->buf[s->buf_len - s->lcp], &in[in_len], s->lcp); - in_len += s->lcp; - s->lcp = 0; - } - /*endif*/ - pitch = amdf_pitch(s->min_pitch, s->max_pitch, s->buf, s->min_pitch); - lcpf = (double) pitch*s->rcomp; - /* Nudge around to compensate for fractional samples */ - s->lcp = (int) lcpf; - /* Note that s->lcp and lcpf are not the same, as lcpf has a fractional part, and s->lcp doesn't */ - s->rate_nudge += s->lcp - lcpf; - if (s->rate_nudge >= 0.5f) - { - s->lcp--; - s->rate_nudge -= 1.0f; - } - else if (s->rate_nudge <= -0.5f) - { - s->lcp++; - s->rate_nudge += 1.0f; - } - /*endif*/ - if (s->playout_rate < 1.0f) - { - /* Speed up - drop a pitch period of signal */ - overlap_add(&s->buf[pitch], s->buf, pitch); - vec_copyi16(&s->buf[pitch], &s->buf[2*pitch], s->buf_len - 2*pitch); - if (len - in_len < pitch) - { - /* Cannot continue without more samples */ - /* Save the residual signal for next time. */ - vec_copyi16(&s->buf[s->buf_len - pitch], &in[in_len], len - in_len); - s->fill += (len - in_len - pitch); - return out_len; - } - /*endif*/ - vec_copyi16(&s->buf[s->buf_len - pitch], &in[in_len], pitch); - in_len += pitch; - } - else - { - /* Slow down - insert a pitch period of signal */ - vec_copyi16(&out[out_len], s->buf, pitch); - out_len += pitch; - overlap_add(s->buf, &s->buf[pitch], pitch); - } - /*endif*/ - } - /*endwhile*/ - return out_len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) time_scale_flush(time_scale_state_t *s, int16_t out[]) -{ - int len; - int pad; - - if (s->playout_rate < 1.0f) - return 0; - /*endif*/ - vec_copyi16(out, s->buf, s->fill); - len = s->fill; - if (s->playout_rate > 1.0f) - { - pad = s->fill*(s->playout_rate - 1.0f); - vec_zeroi16(&out[len], pad); - len += pad; - } - /*endif*/ - s->fill = 0; - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) time_scale_max_output_len(time_scale_state_t *s, int input_len) -{ - return (int) (input_len*s->playout_rate + s->min_pitch + 1); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(time_scale_state_t *) time_scale_init(time_scale_state_t *s, int sample_rate, float playout_rate) -{ - bool alloced; - - if (sample_rate > TIME_SCALE_MAX_SAMPLE_RATE) - return NULL; - /*endif*/ - alloced = false; - if (s == NULL) - { - if ((s = (time_scale_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - alloced = true; - } - /*endif*/ - s->sample_rate = sample_rate; - s->min_pitch = sample_rate/TIME_SCALE_MIN_PITCH; - s->max_pitch = sample_rate/TIME_SCALE_MAX_PITCH; - s->buf_len = 2*sample_rate/TIME_SCALE_MIN_PITCH; - if (time_scale_rate(s, playout_rate)) - { - if (alloced) - span_free(s); - /*endif*/ - return NULL; - } - /*endif*/ - s->rate_nudge = 0.0f; - s->fill = 0; - s->lcp = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) time_scale_release(time_scale_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) time_scale_free(time_scale_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/timezone.c b/libs/spandsp/src/timezone.c deleted file mode 100644 index 83e1ab766d..0000000000 --- a/libs/spandsp/src/timezone.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * timezone.c - Timezone handling for time interpretation - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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 */ - -/* Timezone processing might not seem like a DSP activity, but getting the headers - right on FAXes demands it. We need to handle multiple time zones within a process, - for FAXes related to different parts of the globe, so the system timezone handling - is not adequate. */ - -/* This timezone handling is derived from public domain software by Arthur David Olson - which you may download from ftp://elsie.nci.nih.gov/pub - at the time of writing. */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#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" - -#define SECS_PER_MIN 60 -#define MINS_PER_HOUR 60 -#define HOURS_PER_DAY 24 -#define DAYS_PER_WEEK 7 -#define DAYS_PER_NON_LEAP_YEAR 365 -#define DAYS_PER_LEAP_YEAR 366 -#define SECS_PER_HOUR (SECS_PER_MIN*MINS_PER_HOUR) -#define SECS_PER_DAY ((long int) SECS_PER_HOUR*HOURS_PER_DAY) -#define MONTHS_PER_YEAR 12 - -#define TM_YEAR_BASE 1900 - -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY TM_THURSDAY - -#define isleap(y) (((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0)) - -#define isleap_sum(a, b) isleap((a)%400 + (b)%400) - -/* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ -#define is_digit(c) ((unsigned int) (c) - '0' <= 9) - -#define TZ_DEF_RULE_STRING ",M4.1.0,M10.5.0" - -#define JULIAN_DAY 0 /* Jn - Julian day */ -#define DAY_OF_YEAR 1 /* n - day of year */ -#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ - -static const char wildabbr[] = " "; - -static const char gmt[] = "GMT"; - -struct tz_rule_s -{ - int r_type; /* Type of rule--see below */ - int r_day; /* Day number of rule */ - int r_week; /* Week number of rule */ - int r_mon; /* Month number of rule */ - long int r_time; /* Transition time of rule */ -}; - -static const int mon_lengths[2][MONTHS_PER_YEAR] = -{ - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -}; - -static const int year_lengths[2] = -{ - DAYS_PER_NON_LEAP_YEAR, - DAYS_PER_LEAP_YEAR -}; - -static int add_with_overflow_detection(int *number, int delta) -{ - /* This needs to be considered volatile, or clever optimisation destroys - the effect of the the rollover detection logic */ - volatile int last_number; - - last_number = *number; - *number += delta; - return (*number < last_number) != (delta < 0); -} -/*- End of function --------------------------------------------------------*/ - -static void set_tzname(tz_t *tz) -{ - struct tz_state_s *sp; - const struct tz_ttinfo_s *ttisp; - int i; - - sp = &tz->state; - tz->tzname[0] = wildabbr; - tz->tzname[1] = wildabbr; - for (i = 0; i < sp->typecnt; i++) - { - ttisp = &sp->ttis[i]; - tz->tzname[ttisp->isdst] = &sp->chars[ttisp->abbrind]; - } - for (i = 0; i < sp->timecnt; i++) - { - ttisp = &sp->ttis[sp->types[i]]; - tz->tzname[ttisp->isdst] = &sp->chars[ttisp->abbrind]; - } -} -/*- End of function --------------------------------------------------------*/ - -/* Return the number of leap years through the end of the given year - where, to make the math easy, the answer for year zero is defined as zero. */ -static int leaps_thru_end_of(const int y) -{ - return (y >= 0) ? (y/4 - y/100 + y/400) : -(leaps_thru_end_of(-(y + 1)) + 1); -} -/*- End of function --------------------------------------------------------*/ - -static struct tm *time_sub(const time_t * const timep, const long int offset, const struct tz_state_s * const sp, struct tm * const tmp) -{ - const struct tz_lsinfo_s *lp; - time_t tdays; - const int *ip; - int32_t corr; - int32_t seconds; - int32_t rem; - int idays; - int y; - int hit; - int i; - int newy; - time_t tdelta; - int idelta; - int leapdays; - - corr = 0; - hit = 0; - i = sp->leapcnt; - while (--i >= 0) - { - lp = &sp->lsis[i]; - if (*timep >= lp->trans) - { - if (*timep == lp->trans) - { - hit = ((i == 0 && lp->corr > 0) || lp->corr > sp->lsis[i - 1].corr); - if (hit) - { - while (i > 0 - && - sp->lsis[i].trans == sp->lsis[i - 1].trans + 1 - && - sp->lsis[i].corr == sp->lsis[i - 1].corr + 1) - { - hit++; - --i; - } - } - } - corr = lp->corr; - break; - } - } - y = EPOCH_YEAR; - tdays = *timep/SECS_PER_DAY; - rem = *timep - tdays*SECS_PER_DAY; - while (tdays < 0 || tdays >= year_lengths[isleap(y)]) - { - tdelta = tdays / DAYS_PER_LEAP_YEAR; - idelta = tdelta; - if (tdelta - idelta >= 1 || idelta - tdelta >= 1) - return NULL; - if (idelta == 0) - idelta = (tdays < 0) ? -1 : 1; - newy = y; - if (add_with_overflow_detection(&newy, idelta)) - return NULL; - leapdays = leaps_thru_end_of(newy - 1) - leaps_thru_end_of(y - 1); - tdays -= ((time_t) newy - y)*DAYS_PER_NON_LEAP_YEAR; - tdays -= leapdays; - y = newy; - } - seconds = tdays*SECS_PER_DAY; - tdays = seconds/SECS_PER_DAY; - rem += seconds - tdays*SECS_PER_DAY; - /* Given the range, we can now fearlessly cast... */ - idays = tdays; - rem += (offset - corr); - while (rem < 0) - { - rem += SECS_PER_DAY; - idays--; - } - while (rem >= SECS_PER_DAY) - { - rem -= SECS_PER_DAY; - idays++; - } - while (idays < 0) - { - if (add_with_overflow_detection(&y, -1)) - return NULL; - idays += year_lengths[isleap(y)]; - } - while (idays >= year_lengths[isleap(y)]) - { - idays -= year_lengths[isleap(y)]; - if (add_with_overflow_detection(&y, 1)) - return NULL; - } - tmp->tm_year = y; - if (add_with_overflow_detection(&tmp->tm_year, -TM_YEAR_BASE)) - return NULL; - tmp->tm_yday = idays; - /* The "extra" mods below avoid overflow problems. */ - tmp->tm_wday = EPOCH_WDAY - + ((y - EPOCH_YEAR) % DAYS_PER_WEEK)*(DAYS_PER_NON_LEAP_YEAR % DAYS_PER_WEEK) - + leaps_thru_end_of(y - 1) - - leaps_thru_end_of(EPOCH_YEAR - 1) - + idays; - tmp->tm_wday %= DAYS_PER_WEEK; - if (tmp->tm_wday < 0) - tmp->tm_wday += DAYS_PER_WEEK; - tmp->tm_hour = (int) (rem/SECS_PER_HOUR); - rem %= SECS_PER_HOUR; - tmp->tm_min = (int) (rem/SECS_PER_MIN); - /* A positive leap second requires a special - * representation. This uses "... ??:59:60" et seq. */ - tmp->tm_sec = (int) (rem%SECS_PER_MIN) + hit; - ip = mon_lengths[isleap(y)]; - for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; (tmp->tm_mon)++) - idays -= ip[tmp->tm_mon]; - tmp->tm_mday = (int) (idays + 1); - tmp->tm_isdst = 0; - return tmp; -} -/*- End of function --------------------------------------------------------*/ - -/* Given a pointer into a time zone string, scan until a character that is not - * a valid character in a zone name is found. Return a pointer to that - * character. */ -static const char *get_tzname(const char *strp) -{ - char c; - - while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') - strp++; - return strp; -} -/*- End of function --------------------------------------------------------*/ - -/* Given a pointer into a time zone string, extract a number from that string. - * Check that the number is within a specified range; if it is not, return - * NULL. - * Otherwise, return a pointer to the first character not part of the number. */ -static const char *get_num(const char *strp, int * const nump, const int min, const int max) -{ - char c; - int num; - - if (strp == NULL || !is_digit(c = *strp)) - return NULL; - num = 0; - do - { - num = num*10 + (c - '0'); - if (num > max) - return NULL; /* Illegal value */ - c = *++strp; - } - while (is_digit(c)); - if (num < min) - return NULL; /* Illegal value */ - *nump = num; - return strp; -} -/*- End of function --------------------------------------------------------*/ - -/* Given a pointer into a time zone string, extract a number of seconds, - * in hh[:mm[:ss]] form, from the string. - * If any error occurs, return NULL. - * Otherwise, return a pointer to the first character not part of the number - * of seconds. */ -static const char *get_secs(const char *strp, long int * const secsp) -{ - int num; - - /* HOURS_PER_DAY*DAYS_PER_WEEK - 1 allows quasi-Posix rules like - * "M10.4.6/26", which does not conform to Posix, - * but which specifies the equivalent of - * "02:00 on the first Sunday on or after 23 Oct". */ - strp = get_num(strp, &num, 0, HOURS_PER_DAY*DAYS_PER_WEEK - 1); - if (strp == NULL) - return NULL; - *secsp = num*(long int) SECS_PER_HOUR; - if (*strp == ':') - { - strp = get_num(strp + 1, &num, 0, MINS_PER_HOUR - 1); - if (strp == NULL) - return NULL; - *secsp += num*SECS_PER_MIN; - if (*strp == ':') - { - /* SECS_PER_MIN allows for leap seconds. */ - strp = get_num(strp + 1, &num, 0, SECS_PER_MIN); - if (strp == NULL) - return NULL; - *secsp += num; - } - } - return strp; -} -/*- End of function --------------------------------------------------------*/ - -/* Given a pointer into a time zone string, extract an offset, in - * [+-]hh[:mm[:ss]] form, from the string. - * If any error occurs, return NULL. - * Otherwise, return a pointer to the first character not part of the time. */ -static const char *get_offset(const char *strp, long int * const offsetp) -{ - int neg = 0; - - if (*strp == '-') - { - neg = 1; - strp++; - } - else if (*strp == '+') - { - strp++; - } - strp = get_secs(strp, offsetp); - if (strp == NULL) - return NULL; /* Illegal time */ - if (neg) - *offsetp = -*offsetp; - return strp; -} -/*- End of function --------------------------------------------------------*/ - -/* Given a pointer into a time zone string, extract a rule in the form - * date[/time]. See POSIX section 8 for the format of "date" and "time". - * If a valid rule is not found, return NULL. - * Otherwise, return a pointer to the first character not part of the rule. */ -static const char *get_rule(const char *strp, struct tz_rule_s * const rulep) -{ - if (*strp == 'J') - { - /* Julian day. */ - rulep->r_type = JULIAN_DAY; - strp = get_num(strp + 1, &rulep->r_day, 1, DAYS_PER_NON_LEAP_YEAR); - } - else if (*strp == 'M') - { - /* Month, week, day. */ - rulep->r_type = MONTH_NTH_DAY_OF_WEEK; - strp = get_num(strp + 1, &rulep->r_mon, 1, MONTHS_PER_YEAR); - if (strp == NULL || *strp++ != '.') - return NULL; - strp = get_num(strp, &rulep->r_week, 1, 5); - if (strp == NULL || *strp++ != '.') - return NULL; - strp = get_num(strp, &rulep->r_day, 0, DAYS_PER_WEEK - 1); - } - else if (is_digit(*strp)) - { - /* Day of the year. */ - rulep->r_type = DAY_OF_YEAR; - strp = get_num(strp, &rulep->r_day, 0, DAYS_PER_LEAP_YEAR - 1); - } - else - { - /* Invalid format */ - return NULL; - } - if (strp == NULL) - return NULL; - if (*strp == '/') - { - /* Time specified. */ - strp = get_secs(strp + 1, &rulep->r_time); - } - else - { - /* Default = 2:00:00 */ - rulep->r_time = 2*SECS_PER_HOUR; - } - return strp; -} -/*- End of function --------------------------------------------------------*/ - -/* Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the - * year, a rule, and the offset from UTC at the time that rule takes effect, - * calculate the Epoch-relative time that rule takes effect. */ -static time_t trans_time(const time_t janfirst, const int year, const struct tz_rule_s * const rulep, const long int offset) -{ - int leapyear; - time_t value; - int i; - int d; - int m1; - int yy0; - int yy1; - int yy2; - int dow; - - value = 0; - leapyear = isleap(year); - switch (rulep->r_type) - { - case JULIAN_DAY: - /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap - * years. - * In non-leap years, or if the day number is 59 or less, just - * add SECS_PER_DAY times the day number-1 to the time of - * January 1, midnight, to get the day. */ - value = janfirst + (rulep->r_day - 1)*SECS_PER_DAY; - if (leapyear && rulep->r_day >= 60) - value += SECS_PER_DAY; - break; - case DAY_OF_YEAR: - /* n - day of year. - * Just add SECS_PER_DAY times the day number to the time of - * January 1, midnight, to get the day. */ - value = janfirst + rulep->r_day * SECS_PER_DAY; - break; - case MONTH_NTH_DAY_OF_WEEK: - /* Mm.n.d - nth "dth day" of month m. */ - value = janfirst; - for (i = 0; i < rulep->r_mon - 1; i++) - value += mon_lengths[leapyear][i]*SECS_PER_DAY; - - /* Use Zeller's Congruence to get day-of-week of first day of month. */ - m1 = (rulep->r_mon + 9)%12 + 1; - yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; - yy1 = yy0/100; - yy2 = yy0%100; - dow = ((26*m1 - 2)/10 + 1 + yy2 + yy2/4 + yy1/4 - 2*yy1)%7; - if (dow < 0) - dow += DAYS_PER_WEEK; - - /* "dow" is the day-of-week of the first day of the month. Get - * the day-of-month (zero-origin) of the first "dow" day of the - * month. */ - d = rulep->r_day - dow; - if (d < 0) - d += DAYS_PER_WEEK; - for (i = 1; i < rulep->r_week; i++) - { - if (d + DAYS_PER_WEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) - break; - d += DAYS_PER_WEEK; - } - - /* "d" is the day-of-month (zero-origin) of the day we want. */ - value += d*SECS_PER_DAY; - break; - } - - /* "value" is the Epoch-relative time of 00:00:00 UTC on the day in - * question. To get the Epoch-relative time of the specified local - * time on that day, add the transition time and the current offset - * from UTC. */ - return value + rulep->r_time + offset; -} -/*- End of function --------------------------------------------------------*/ - -/* Given a POSIX section 8-style TZ string, fill in the rule tables as - appropriate. */ -static int tzparse(const char *name, struct tz_state_s * const sp, const int lastditch) -{ - const char *stdname; - const char *dstname; - size_t stdlen; - size_t dstlen; - long int stdoffset; - long int dstoffset; - long int theirstdoffset; - long int theirdstoffset; - long int theiroffset; - unsigned char *typep; - char *cp; - int load_result; - int isdst; - int i; - int j; - int year; - struct tz_rule_s start; - struct tz_rule_s end; - time_t *atp; - time_t janfirst; - time_t starttime; - time_t endtime; - - dstname = NULL; - stdname = name; - if (lastditch) - { - stdlen = strlen(name); /* Length of standard zone name */ - name += stdlen; - if (stdlen >= sizeof(sp->chars)) - stdlen = sizeof(sp->chars) - 1; - stdoffset = 0; - } - else - { - name = get_tzname(name); - stdlen = name - stdname; - if (stdlen < 3) - return -1; - if (*name == '\0') - return -1; - name = get_offset(name, &stdoffset); - if (name == NULL) - return -1; - } - load_result = -1; - if (load_result != 0) - sp->leapcnt = 0; /* So, we're off a little */ - if (*name != '\0') - { - dstname = name; - name = get_tzname(name); - dstlen = name - dstname; /* Length of DST zone name */ - if (dstlen < 3) - return -1; - if (*name != '\0' && *name != ',' && *name != ';') - { - if ((name = get_offset(name, &dstoffset)) == NULL) - return -1; - } - else - { - dstoffset = stdoffset - SECS_PER_HOUR; - } - if (*name == '\0' && load_result != 0) - name = TZ_DEF_RULE_STRING; - if (*name == ',' || *name == ';') - { - if ((name = get_rule(name + 1, &start)) == NULL) - return -1; - if (*name++ != ',') - return -1; - if ((name = get_rule(name, &end)) == NULL) - return -1; - if (*name != '\0') - return -1; - sp->typecnt = 2; /* Standard time and DST */ - /* Two transitions per year, from EPOCH_YEAR to 2037. */ - sp->timecnt = 2*(2037 - EPOCH_YEAR + 1); - if (sp->timecnt > TZ_MAX_TIMES) - return -1; - sp->ttis[0].gmtoff = -dstoffset; - sp->ttis[0].isdst = 1; - sp->ttis[0].abbrind = stdlen + 1; - sp->ttis[1].gmtoff = -stdoffset; - sp->ttis[1].isdst = 0; - sp->ttis[1].abbrind = 0; - atp = sp->ats; - typep = sp->types; - janfirst = 0; - for (year = EPOCH_YEAR; year <= 2037; year++) - { - starttime = trans_time(janfirst, year, &start, stdoffset); - endtime = trans_time(janfirst, year, &end, dstoffset); - if (starttime > endtime) - { - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - } - else - { - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - } - janfirst += year_lengths[isleap(year)]*SECS_PER_DAY; - } - } - else - { - if (*name != '\0') - return -1; - /* Initial values of theirstdoffset and theirdstoffset. */ - theirstdoffset = 0; - for (i = 0; i < sp->timecnt; i++) - { - j = sp->types[i]; - if (!sp->ttis[j].isdst) - { - theirstdoffset = -sp->ttis[j].gmtoff; - break; - } - } - theirdstoffset = 0; - for (i = 0; i < sp->timecnt; i++) - { - j = sp->types[i]; - if (sp->ttis[j].isdst) - { - theirdstoffset = -sp->ttis[j].gmtoff; - break; - } - } - /* Initially we're assumed to be in standard time. */ - isdst = false; - /* Now juggle transition times and types tracking offsets as you do. */ - for (i = 0; i < sp->timecnt; i++) - { - j = sp->types[i]; - sp->types[i] = sp->ttis[j].isdst; - if (sp->ttis[j].ttisgmt) - { - /* No adjustment to transition time */ - } - else - { - /* If summer time is in effect, and the - * transition time was not specified as - * standard time, add the summer time - * offset to the transition time; - * otherwise, add the standard time - * offset to the transition time. */ - /* Transitions from DST to DDST - * will effectively disappear since - * POSIX provides for only one DST - * offset. */ - if (isdst && !sp->ttis[j].ttisstd) - sp->ats[i] += (dstoffset - theirdstoffset); - else - sp->ats[i] += (stdoffset - theirstdoffset); - } - theiroffset = -sp->ttis[j].gmtoff; - if (sp->ttis[j].isdst) - theirdstoffset = theiroffset; - else - theirstdoffset = theiroffset; - } - /* Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */ - sp->ttis[0].gmtoff = -stdoffset; - sp->ttis[0].isdst = false; - sp->ttis[0].abbrind = 0; - sp->ttis[1].gmtoff = -dstoffset; - sp->ttis[1].isdst = true; - sp->ttis[1].abbrind = stdlen + 1; - sp->typecnt = 2; - } - } - else - { - dstlen = 0; - sp->typecnt = 1; /* Only standard time */ - sp->timecnt = 0; - sp->ttis[0].gmtoff = -stdoffset; - sp->ttis[0].isdst = 0; - sp->ttis[0].abbrind = 0; - } - sp->charcnt = stdlen + 1; - if (dstlen != 0) - sp->charcnt += dstlen + 1; - if ((size_t) sp->charcnt > sizeof(sp->chars)) - return -1; - cp = sp->chars; - strncpy(cp, stdname, stdlen); - cp += stdlen; - *cp++ = '\0'; - if (dstlen != 0) - { - strncpy(cp, dstname, dstlen); - cp[dstlen] = '\0'; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void tz_set(tz_t *tz, const char *tzstring) -{ - const char *name = ""; - struct tz_state_s *lclptr = &tz->state; - - if (tzstring) - name = tzstring; - - /* See if we are already set OK */ - if (tz->lcl_is_set > 0 && strcmp(tz->lcl_tzname, name) == 0) - return; - tz->lcl_is_set = strlen(name) < sizeof(tz->lcl_tzname); - if (tz->lcl_is_set) - strcpy(tz->lcl_tzname, name); - - if (name[0] == '\0') - { - /* User wants it fast rather than right, so, we're off a little. */ - lclptr->leapcnt = 0; - lclptr->timecnt = 0; - lclptr->typecnt = 0; - lclptr->ttis[0].isdst = 0; - lclptr->ttis[0].gmtoff = 0; - lclptr->ttis[0].abbrind = 0; - strcpy(lclptr->chars, gmt); - } - else if (name[0] == ':' || tzparse(name, lclptr, false) != 0) - { - tzparse(gmt, lclptr, true); - } - set_tzname(tz); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) tz_localtime(tz_t *tz, struct tm *tmp, time_t t) -{ - struct tz_state_s *sp; - const struct tz_ttinfo_s *ttisp; - int i; - - sp = &tz->state; - - if (sp->timecnt == 0 || t < sp->ats[0]) - { - i = 0; - while (sp->ttis[i].isdst) - { - if (++i >= sp->typecnt) - { - i = 0; - break; - } - } - } - else - { - for (i = 1; i < sp->timecnt; i++) - { - if (t < sp->ats[i]) - break; - } - i = (int) sp->types[i - 1]; - } - ttisp = &sp->ttis[i]; - time_sub(&t, ttisp->gmtoff, sp, tmp); - tmp->tm_isdst = ttisp->isdst; - tz->tzname[tmp->tm_isdst] = &sp->chars[ttisp->abbrind]; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) tz_tzname(tz_t *tz, int isdst) -{ - return tz->tzname[(!isdst) ? 0 : 1]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring) -{ - if (tz == NULL) - { - if ((tz = (tz_t *) span_alloc(sizeof(*tz))) == NULL) - return NULL; - } - memset(tz, 0, sizeof(*tz)); - tz->tzname[0] = - tz->tzname[1] = wildabbr; - tz_set(tz, tzstring); - return tz; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) tz_release(tz_t *tz) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) tz_free(tz_t *tz) -{ - if (tz) - span_free(tz); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/tone_detect.c b/libs/spandsp/src/tone_detect.c deleted file mode 100644 index 2865ba40d8..0000000000 --- a/libs/spandsp/src/tone_detect.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tone_detect.c - General telephony tone detection. - * - * Written by Steve Underwood - * - * Copyright (C) 2001-2003, 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. - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/complex.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" - -#include "spandsp/private/tone_detect.h" - -#if !defined(M_PI) -/* C99 systems may not define M_PI */ -#define M_PI 3.14159265358979323846264338327 -#endif - -SPAN_DECLARE(void) make_goertzel_descriptor(goertzel_descriptor_t *t, float freq, int samples) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - t->fac = 16383.0f*2.0f*cosf(2.0f*M_PI*(freq/(float) SAMPLE_RATE)); -#else - t->fac = 2.0f*cosf(2.0f*M_PI*(freq/(float) SAMPLE_RATE)); -#endif - t->samples = samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(goertzel_state_t *) goertzel_init(goertzel_state_t *s, - goertzel_descriptor_t *t) -{ - if (s == NULL) - { - if ((s = (goertzel_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } -#if defined(SPANDSP_USE_FIXED_POINT) - s->v2 = - s->v3 = 0; -#else - s->v2 = - s->v3 = 0.0f; -#endif - s->fac = t->fac; - s->samples = t->samples; - s->current_sample = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) goertzel_release(goertzel_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) goertzel_free(goertzel_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) goertzel_reset(goertzel_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - s->v2 = - s->v3 = 0; -#else - s->v2 = - s->v3 = 0.0f; -#endif - s->current_sample = 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) goertzel_update(goertzel_state_t *s, - const int16_t amp[], - int samples) -{ - int i; -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t x; - int16_t v1; -#else - float v1; -#endif - - if (samples > s->samples - s->current_sample) - samples = s->samples - s->current_sample; - for (i = 0; i < samples; i++) - { - v1 = s->v2; - s->v2 = s->v3; -#if defined(SPANDSP_USE_FIXED_POINT) - x = (((int32_t) s->fac*s->v2) >> 14); - /* Scale down the input signal to avoid overflows. 9 bits is enough to - monitor the signals of interest with adequate dynamic range and - resolution. In telephony we generally only start with 13 or 14 bits, - anyway. */ - s->v3 = x - v1 + (amp[i] >> 7); -#else - s->v3 = s->fac*s->v2 - v1 + amp[i]; -#endif - } - s->current_sample += samples; - return samples; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int32_t) goertzel_result(goertzel_state_t *s) -#else -SPAN_DECLARE(float) goertzel_result(goertzel_state_t *s) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t v1; - int32_t x; - int32_t y; -#else - float v1; -#endif - - /* Push a zero through the process to finish things off. */ - v1 = s->v2; - s->v2 = s->v3; -#if defined(SPANDSP_USE_FIXED_POINT) - x = (((int32_t) s->fac*s->v2) >> 14); - s->v3 = x - v1; -#else - s->v3 = s->fac*s->v2 - v1; -#endif - /* Now calculate the non-recursive side of the filter. */ - /* The result here is not scaled down to allow for the magnification - effect of the filter (the usual DFT magnification effect). */ -#if defined(SPANDSP_USE_FIXED_POINT) - x = (int32_t) s->v3*s->v3; - y = (int32_t) s->v2*s->v2; - x += y; - y = ((int32_t) s->v3*s->fac) >> 14; - y *= s->v2; - x -= y; - x <<= 1; - goertzel_reset(s); - /* The number returned in a floating point build will be 16384^2 times - as big as for a fixed point build, due to the 14 bit shifts - (or the square of the 7 bit shifts, depending how you look at it). */ - return x; -#else - v1 = s->v3*s->v3 + s->v2*s->v2 - s->v2*s->v3*s->fac; - v1 *= 2.0; - goertzel_reset(s); - return v1; -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) periodogram(const complexf_t coeffs[], const complexf_t amp[], int len) -{ - complexf_t sum; - complexf_t diff; - complexf_t x; - int i; - - x = complex_setf(0.0f, 0.0f); - for (i = 0; i < len/2; i++) - { - sum = complex_addf(&[i], &[len - 1 - i]); - diff = complex_subf(&[i], &[len - 1 - i]); - x.re += (coeffs[i].re*sum.re - coeffs[i].im*diff.im); - x.im += (coeffs[i].re*sum.im + coeffs[i].im*diff.re); - } - return x; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) periodogram_prepare(complexf_t sum[], complexf_t diff[], const complexf_t amp[], int len) -{ - int i; - - for (i = 0; i < len/2; i++) - { - sum[i] = complex_addf(&[i], &[len - 1 - i]); - diff[i] = complex_subf(&[i], &[len - 1 - i]); - } - return len/2; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(complexf_t) periodogram_apply(const complexf_t coeffs[], const complexf_t sum[], const complexf_t diff[], int len) -{ - complexf_t x; - int i; - - x = complex_setf(0.0f, 0.0f); - for (i = 0; i < len/2; i++) - { - x.re += (coeffs[i].re*sum[i].re - coeffs[i].im*diff[i].im); - x.im += (coeffs[i].re*sum[i].im + coeffs[i].im*diff[i].re); - } - return x; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) periodogram_generate_coeffs(complexf_t coeffs[], float freq, int sample_rate, int window_len) -{ - float window; - float sum; - float x; - int i; - - sum = 0.0f; - for (i = 0; i < window_len/2; i++) - { - /* Apply a Hamming window as we go */ - window = 0.53836f - 0.46164f*cosf(2.0f*3.1415926535f*i/(window_len - 1.0f)); - x = (i - window_len/2.0f + 0.5f)*freq*2.0f*3.1415926535f/sample_rate; - coeffs[i].re = cosf(x)*window; - coeffs[i].im = -sinf(x)*window; - sum += window; - } - /* Rescale for unity gain in the periodogram. The 2.0 factor is to allow for the full window, - rather than just the half over which we have summed the coefficients. */ - sum = 1.0f/(2.0f*sum); - for (i = 0; i < window_len/2; i++) - { - coeffs[i].re *= sum; - coeffs[i].im *= sum; - } - return window_len/2; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) periodogram_generate_phase_offset(complexf_t *offset, float freq, int sample_rate, int interval) -{ - float x; - - /* The phase offset is how far the phase rotates in one frame */ - x = 2.0f*3.1415926535f*(float) interval/(float) sample_rate; - offset->re = cosf(freq*x); - offset->im = sinf(freq*x); - return 1.0f/x; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) periodogram_freq_error(const complexf_t *phase_offset, float scale, const complexf_t *last_result, const complexf_t *result) -{ - complexf_t prediction; - - /* Rotate the last result by the expected phasor offset to the current result. Then - find the difference between that predicted position, and the actual one. When - scaled by the current signal level, this gives us the frequency error. */ - prediction = complex_mulf(last_result, phase_offset); - return scale*(result->im*prediction.re - result->re*prediction.im)/(result->re*result->re + result->im*result->im); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/tone_generate.c b/libs/spandsp/src/tone_generate.c deleted file mode 100644 index c01c970674..0000000000 --- a/libs/spandsp/src/tone_generate.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tone_generate.c - General telephony tone generation. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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 -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#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" -#include "spandsp/tone_generate.h" - -#include "spandsp/private/tone_generate.h" - -#if !defined(M_PI) -/* C99 systems may not define M_PI */ -#define M_PI 3.14159265358979323846264338327 -#endif - -SPAN_DECLARE(tone_gen_descriptor_t *) tone_gen_descriptor_init(tone_gen_descriptor_t *s, - int f1, - int l1, - int f2, - int l2, - int d1, - int d2, - int d3, - int d4, - int repeat) -{ - if (s == NULL) - { - if ((s = (tone_gen_descriptor_t *) span_alloc(sizeof(*s))) == NULL) - { - return NULL; - } - } - memset(s, 0, sizeof(*s)); - - if (f1) - { -#if defined(SPANDSP_USE_FIXED_POINT) - s->tone[0].phase_rate = dds_phase_rate((float) f1); - if (f2 < 0) - s->tone[0].phase_rate = -s->tone[0].phase_rate; - s->tone[0].gain = dds_scaling_dbm0((float) l1); -#else - s->tone[0].phase_rate = dds_phase_ratef((float) f1); - if (f2 < 0) - s->tone[0].phase_rate = -s->tone[0].phase_rate; - s->tone[0].gain = dds_scaling_dbm0f((float) l1); -#endif - } - if (f2) - { -#if defined(SPANDSP_USE_FIXED_POINT) - s->tone[1].phase_rate = dds_phase_rate((float) abs(f2)); - s->tone[1].gain = (f2 < 0) ? (float) 32767.0f*l2/100.0f : dds_scaling_dbm0((float) l2); -#else - s->tone[1].phase_rate = dds_phase_ratef((float) abs(f2)); - s->tone[1].gain = (f2 < 0) ? (float) l2/100.0f : dds_scaling_dbm0f((float) l2); -#endif - } - - s->duration[0] = d1*SAMPLE_RATE/1000; - s->duration[1] = d2*SAMPLE_RATE/1000; - s->duration[2] = d3*SAMPLE_RATE/1000; - s->duration[3] = d4*SAMPLE_RATE/1000; - - s->repeat = repeat; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s) -{ - span_free(s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples) -{ - int samples; - int limit; -#if defined(SPANDSP_USE_FIXED_POINT) - int16_t xamp; -#else - float xamp; -#endif - int i; - - if (s->current_section < 0) - return 0; - - for (samples = 0; samples < max_samples; ) - { - limit = samples + s->duration[s->current_section] - s->current_position; - if (limit > max_samples) - limit = max_samples; - - s->current_position += (limit - samples); - if (s->current_section & 1) - { - /* A silent section */ - for ( ; samples < limit; samples++) - amp[samples] = 0; - } - else - { - if (s->tone[0].phase_rate < 0) - { - /* Modulated tone */ - for ( ; samples < limit; samples++) - { - /* There must be two, and only two, tones */ -#if defined(SPANDSP_USE_FIXED_POINT) - xamp = ((int32_t) dds_mod(&s->phase[0], -s->tone[0].phase_rate, s->tone[0].gain, 0) - *(32767 + (int32_t) dds_mod(&s->phase[1], s->tone[1].phase_rate, s->tone[1].gain, 0))) >> 15; - amp[samples] = xamp; -#else - xamp = dds_modf(&s->phase[0], -s->tone[0].phase_rate, s->tone[0].gain, 0) - *(1.0f + dds_modf(&s->phase[1], s->tone[1].phase_rate, s->tone[1].gain, 0)); - amp[samples] = (int16_t) lfastrintf(xamp); -#endif - } - } - else - { - for ( ; samples < limit; samples++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - xamp = 0; -#else - xamp = 0.0f; -#endif - for (i = 0; i < 4; i++) - { - if (s->tone[i].phase_rate == 0) - break; -#if defined(SPANDSP_USE_FIXED_POINT) - xamp += dds_mod(&s->phase[i], s->tone[i].phase_rate, s->tone[i].gain, 0); -#else - xamp += dds_modf(&s->phase[i], s->tone[i].phase_rate, s->tone[i].gain, 0); -#endif - } - /* Saturation of the answer is the right thing at this point. - However, we are normally generating well controlled tones, - that cannot clip. So, the overhead of doing saturation is - a waste of valuable time. */ -#if defined(SPANDSP_USE_FIXED_POINT) - amp[samples] = xamp; -#else - amp[samples] = (int16_t) lfastrintf(xamp); -#endif - } - } - } - if (s->current_position >= s->duration[s->current_section]) - { - s->current_position = 0; - if (++s->current_section > 3 || s->duration[s->current_section] == 0) - { - if (!s->repeat) - { - /* Force a quick exit */ - s->current_section = -1; - break; - } - s->current_section = 0; - } - } - } - return samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(tone_gen_state_t *) tone_gen_init(tone_gen_state_t *s, tone_gen_descriptor_t *t) -{ - int i; - - if (s == NULL) - { - if ((s = (tone_gen_state_t *) span_alloc(sizeof(*s))) == NULL) - { - return NULL; - } - } - memset(s, 0, sizeof(*s)); - - for (i = 0; i < 4; i++) - { - s->tone[i] = t->tone[i]; - s->phase[i] = 0; - } - - for (i = 0; i < 4; i++) - s->duration[i] = t->duration[i]; - s->repeat = t->repeat; - - s->current_section = 0; - s->current_position = 0; - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) tone_gen_release(tone_gen_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) tone_gen_free(tone_gen_state_t *s) -{ - if (s) - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17_v32bis_rx_constellation_maps.h b/libs/spandsp/src/v17_v32bis_rx_constellation_maps.h deleted file mode 100644 index ad9b1fa499..0000000000 --- a/libs/spandsp/src/v17_v32bis_rx_constellation_maps.h +++ /dev/null @@ -1,6887 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v17rx_v32bis_constellation_maps.h - ITU V.17 and V.32bis modems - * receive part. - * Constellation mapping. - * - * 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. - */ - -/* The following table maps the 8 soft-decisions associated with every possible point in the - constellation space. If you look at the constellations carefully, all 4 can be accurately - mapped at 0.5 unit resolution. */ -static const uint8_t constel_maps[4][36][36][8] = -{ - { /* 14,400bps map */ - { - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x05, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x66, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x05, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x0d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x0d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x4c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x66, 0x7f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x66, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x76, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x56, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x63, 0x4c, 0x15, 0x66, 0x5f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x66, 0x7f}, - {0x00, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x66, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x76, 0x7f}, - {0x08, 0x49, 0x7a, 0x73, 0x4c, 0x15, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x7a, 0x73, 0x4c, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x73, 0x44, 0x1d, 0x76, 0x7f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x76, 0x6f}, - {0x08, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x44, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x49, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x7a, 0x63, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x7a, 0x63, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x66, 0x7f}, - {0x10, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x66, 0x7f}, - {0x18, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x41, 0x7a, 0x73, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x7a, 0x73, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x6a, 0x73, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x6a, 0x73, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x76, 0x6f}, - {0x18, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x76, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x63, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x5a, 0x63, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x7a, 0x63, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x7a, 0x63, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x66, 0x7f}, - {0x10, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x66, 0x7f}, - {0x18, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x49, 0x7a, 0x73, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x41, 0x7a, 0x73, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x7a, 0x73, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x6a, 0x73, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x6a, 0x73, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x76, 0x6f}, - {0x18, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x76, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x41, 0x6a, 0x53, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x53, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x50, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x29, 0x5a, 0x23, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x5a, 0x23, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x7a, 0x23, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x7a, 0x23, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x66, 0x7f}, - {0x10, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x66, 0x7f}, - {0x18, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x21, 0x7a, 0x33, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x7a, 0x33, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x6a, 0x33, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x6a, 0x33, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x76, 0x6f}, - {0x18, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x76, 0x6f}, - {0x58, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x69, 0x5a, 0x23, 0x6c, 0x55, 0x66, 0x5f}, - {0x10, 0x29, 0x5a, 0x23, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x5a, 0x23, 0x6c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x7a, 0x23, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x7a, 0x23, 0x2c, 0x15, 0x66, 0x5f}, - {0x10, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x66, 0x7f}, - {0x10, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x66, 0x7f}, - {0x18, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x29, 0x7a, 0x33, 0x2c, 0x15, 0x76, 0x7f}, - {0x18, 0x21, 0x7a, 0x33, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x7a, 0x33, 0x2c, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x6a, 0x33, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x6a, 0x33, 0x24, 0x1d, 0x76, 0x7f}, - {0x18, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x76, 0x6f}, - {0x18, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x76, 0x6f}, - {0x58, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x21, 0x6a, 0x13, 0x24, 0x1d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x24, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x6a, 0x13, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x56, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x46, 0x5f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x26, 0x5f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x26, 0x5f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x26, 0x7f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x26, 0x7f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x36, 0x7f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x36, 0x7f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x36, 0x6f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x36, 0x6f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x16, 0x6f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x16, 0x6f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x55, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x46, 0x5f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x46, 0x5f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x26, 0x5f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x55, 0x26, 0x5f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x15, 0x26, 0x5f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x26, 0x7f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x26, 0x7f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x36, 0x7f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x15, 0x36, 0x7f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x1d, 0x36, 0x7f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x36, 0x6f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x36, 0x6f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x16, 0x6f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x1d, 0x16, 0x6f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x16, 0x6f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x16, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x5d, 0x06, 0x4f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x46, 0x1f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x46, 0x1f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x26, 0x1f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x26, 0x1f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x26, 0x3f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x26, 0x3f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x36, 0x3f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x36, 0x3f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x36, 0x2f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x36, 0x2f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x16, 0x2f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x16, 0x2f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x16, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x16, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f} - }, - { - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x0a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x43, 0x6c, 0x75, 0x46, 0x0f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x46, 0x1f}, - {0x50, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x46, 0x1f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x26, 0x1f}, - {0x10, 0x69, 0x1a, 0x23, 0x6c, 0x75, 0x26, 0x1f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x1a, 0x23, 0x6c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x3a, 0x23, 0x2c, 0x35, 0x26, 0x1f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x26, 0x3f}, - {0x10, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x26, 0x3f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x36, 0x3f}, - {0x18, 0x29, 0x3a, 0x33, 0x2c, 0x35, 0x36, 0x3f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x3a, 0x33, 0x2c, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x2a, 0x33, 0x24, 0x3d, 0x36, 0x3f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x36, 0x2f}, - {0x18, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x36, 0x2f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x16, 0x2f}, - {0x58, 0x21, 0x2a, 0x13, 0x24, 0x3d, 0x16, 0x2f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x2a, 0x13, 0x24, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x4a, 0x13, 0x64, 0x7d, 0x16, 0x2f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x16, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x16, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f}, - {0x58, 0x61, 0x4a, 0x03, 0x64, 0x7d, 0x06, 0x4f} - }, - { - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x1a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x1a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x46, 0x1f}, - {0x70, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x46, 0x1f}, - {0x30, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x29, 0x1a, 0x23, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x1a, 0x23, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x3a, 0x23, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x3a, 0x23, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x26, 0x3f}, - {0x30, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x26, 0x3f}, - {0x38, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x21, 0x3a, 0x33, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x3a, 0x33, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x2a, 0x33, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x2a, 0x33, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x36, 0x2f}, - {0x38, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x36, 0x2f}, - {0x78, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x61, 0x2a, 0x13, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x2a, 0x13, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x4a, 0x13, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x4a, 0x13, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f} - }, - { - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x0a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x1a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x1a, 0x43, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x46, 0x1f}, - {0x70, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x46, 0x1f}, - {0x30, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x69, 0x1a, 0x23, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x29, 0x1a, 0x23, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x1a, 0x23, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x3a, 0x23, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x3a, 0x23, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x26, 0x3f}, - {0x30, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x26, 0x3f}, - {0x38, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x29, 0x3a, 0x33, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x21, 0x3a, 0x33, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x3a, 0x33, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x2a, 0x33, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x2a, 0x33, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x36, 0x2f}, - {0x38, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x36, 0x2f}, - {0x78, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x21, 0x2a, 0x13, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x61, 0x2a, 0x13, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x2a, 0x13, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x4a, 0x13, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x4a, 0x13, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x61, 0x4a, 0x03, 0x74, 0x7d, 0x06, 0x4f} - }, - { - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x1a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x1a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x46, 0x1f}, - {0x70, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x46, 0x1f}, - {0x30, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x39, 0x1a, 0x2b, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x1a, 0x2b, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x3a, 0x2b, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x3a, 0x2b, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x26, 0x3f}, - {0x30, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x26, 0x3f}, - {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x31, 0x3a, 0x3b, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x3a, 0x3b, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x2a, 0x3b, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x2a, 0x3b, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x36, 0x2f}, - {0x38, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x36, 0x2f}, - {0x78, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x71, 0x2a, 0x1b, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x2a, 0x1b, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x4a, 0x1b, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x4a, 0x1b, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f} - }, - { - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x0a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x1a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x1a, 0x4b, 0x7c, 0x75, 0x46, 0x0f}, - {0x70, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x46, 0x1f}, - {0x70, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x46, 0x1f}, - {0x30, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x79, 0x1a, 0x2b, 0x7c, 0x75, 0x26, 0x1f}, - {0x30, 0x39, 0x1a, 0x2b, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x1a, 0x2b, 0x7c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x3a, 0x2b, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x3a, 0x2b, 0x3c, 0x35, 0x26, 0x1f}, - {0x30, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x26, 0x3f}, - {0x30, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x26, 0x3f}, - {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x35, 0x36, 0x3f}, - {0x38, 0x31, 0x3a, 0x3b, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x3a, 0x3b, 0x3c, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x2a, 0x3b, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x2a, 0x3b, 0x34, 0x3d, 0x36, 0x3f}, - {0x38, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x36, 0x2f}, - {0x38, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x36, 0x2f}, - {0x78, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x31, 0x2a, 0x1b, 0x34, 0x3d, 0x16, 0x2f}, - {0x78, 0x71, 0x2a, 0x1b, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x2a, 0x1b, 0x34, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x4a, 0x1b, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x4a, 0x1b, 0x74, 0x7d, 0x16, 0x2f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x16, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f}, - {0x78, 0x71, 0x4a, 0x0b, 0x74, 0x7d, 0x06, 0x4f} - }, - { - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x4e, 0x1f}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x4e, 0x1f}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x2e, 0x1f}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x2e, 0x1f}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x2e, 0x3f}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x2e, 0x3f}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x3e, 0x3f}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x3e, 0x3f}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x3e, 0x2f}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x3e, 0x2f}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x1e, 0x2f}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x1e, 0x2f}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x1e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x1e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f} - }, - { - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x75, 0x4e, 0x0f}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x4e, 0x1f}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x4e, 0x1f}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x2e, 0x1f}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x75, 0x2e, 0x1f}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x35, 0x2e, 0x1f}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x2e, 0x3f}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x2e, 0x3f}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x3e, 0x3f}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x35, 0x3e, 0x3f}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x3d, 0x3e, 0x3f}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x3e, 0x2f}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x3e, 0x2f}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x1e, 0x2f}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x3d, 0x1e, 0x2f}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x7d, 0x1e, 0x2f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x1e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x1e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x7d, 0x0e, 0x4f} - }, - { - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x4e, 0x17}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x4e, 0x17}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x2e, 0x17}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x2e, 0x17}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x2e, 0x37}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x2e, 0x37}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x3e, 0x37}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x3e, 0x37}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x3e, 0x27}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x3e, 0x27}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x1e, 0x27}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x1e, 0x27}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x1e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x1e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47} - }, - { - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x02, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x12, 0x4b, 0x7c, 0x65, 0x4e, 0x07}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x4e, 0x17}, - {0x70, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x4e, 0x17}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x2e, 0x17}, - {0x30, 0x79, 0x12, 0x2b, 0x7c, 0x65, 0x2e, 0x17}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x12, 0x2b, 0x7c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x32, 0x2b, 0x3c, 0x25, 0x2e, 0x17}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x2e, 0x37}, - {0x30, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x2e, 0x37}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x3e, 0x37}, - {0x38, 0x39, 0x32, 0x3b, 0x3c, 0x25, 0x3e, 0x37}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x32, 0x3b, 0x3c, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x22, 0x3b, 0x34, 0x2d, 0x3e, 0x37}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x3e, 0x27}, - {0x38, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x3e, 0x27}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x1e, 0x27}, - {0x78, 0x31, 0x22, 0x1b, 0x34, 0x2d, 0x1e, 0x27}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x22, 0x1b, 0x34, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x42, 0x1b, 0x74, 0x6d, 0x1e, 0x27}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x1e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x1e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47}, - {0x78, 0x71, 0x42, 0x0b, 0x74, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x4e, 0x17}, - {0x60, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x4e, 0x17}, - {0x20, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x39, 0x12, 0x2b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x12, 0x2b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x32, 0x2b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x32, 0x2b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x2e, 0x37}, - {0x20, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x2e, 0x37}, - {0x28, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x31, 0x32, 0x3b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x32, 0x3b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x22, 0x3b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x22, 0x3b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x3e, 0x27}, - {0x28, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x3e, 0x27}, - {0x68, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x71, 0x22, 0x1b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x22, 0x1b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x42, 0x1b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x42, 0x1b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x4e, 0x17}, - {0x60, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x4e, 0x17}, - {0x20, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x79, 0x12, 0x2b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x39, 0x12, 0x2b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x12, 0x2b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x32, 0x2b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x32, 0x2b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x2e, 0x37}, - {0x20, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x2e, 0x37}, - {0x28, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x39, 0x32, 0x3b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x31, 0x32, 0x3b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x32, 0x3b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x22, 0x3b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x22, 0x3b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x3e, 0x27}, - {0x28, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x3e, 0x27}, - {0x68, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x31, 0x22, 0x1b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x71, 0x22, 0x1b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x22, 0x1b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x42, 0x1b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x42, 0x1b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x71, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x60, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x20, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x19, 0x12, 0x6b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x12, 0x6b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x32, 0x6b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x32, 0x6b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x2e, 0x37}, - {0x20, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x2e, 0x37}, - {0x28, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x11, 0x32, 0x7b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x32, 0x7b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x22, 0x7b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x22, 0x7b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x3e, 0x27}, - {0x28, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x3e, 0x27}, - {0x68, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x51, 0x22, 0x5b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x22, 0x5b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x12, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x60, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x20, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x59, 0x12, 0x6b, 0x5c, 0x65, 0x2e, 0x17}, - {0x20, 0x19, 0x12, 0x6b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x12, 0x6b, 0x5c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x32, 0x6b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x32, 0x6b, 0x1c, 0x25, 0x2e, 0x17}, - {0x20, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x2e, 0x37}, - {0x20, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x2e, 0x37}, - {0x28, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x19, 0x32, 0x7b, 0x1c, 0x25, 0x3e, 0x37}, - {0x28, 0x11, 0x32, 0x7b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x32, 0x7b, 0x1c, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x22, 0x7b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x22, 0x7b, 0x14, 0x2d, 0x3e, 0x37}, - {0x28, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x3e, 0x27}, - {0x28, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x3e, 0x27}, - {0x68, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x11, 0x22, 0x5b, 0x14, 0x2d, 0x1e, 0x27}, - {0x68, 0x51, 0x22, 0x5b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x22, 0x5b, 0x14, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x1e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x17}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x17}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x6e, 0x37}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x6e, 0x37}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x7e, 0x37}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x7e, 0x37}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x7e, 0x27}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x7e, 0x27}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x5e, 0x27}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x17}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x17}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x17}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x17}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x25, 0x6e, 0x17}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x6e, 0x37}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x6e, 0x37}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x7e, 0x37}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x25, 0x7e, 0x37}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x2d, 0x7e, 0x37}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x7e, 0x27}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x7e, 0x27}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x5e, 0x27}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x2d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x27}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x6e, 0x77}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x6e, 0x77}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x7e, 0x77}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x7e, 0x77}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x7e, 0x67}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x7e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x5e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x02, 0x4b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x20, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x72, 0x6b, 0x1c, 0x45, 0x6e, 0x57}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x6e, 0x77}, - {0x20, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x6e, 0x77}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x7e, 0x77}, - {0x28, 0x19, 0x72, 0x7b, 0x1c, 0x45, 0x7e, 0x77}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x72, 0x7b, 0x1c, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x62, 0x7b, 0x14, 0x4d, 0x7e, 0x77}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x7e, 0x67}, - {0x28, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x7e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x5e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x14, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x14, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x0b, 0x54, 0x6d, 0x0e, 0x47} - }, - { - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x40, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x48, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x11, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47} - }, - { - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x40, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x48, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x19, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x11, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x11, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47} - }, - { - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47} - }, - { - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x4e, 0x07}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x42, 0x5b, 0x54, 0x6d, 0x5e, 0x47} - }, - { - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67} - }, - { - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x60, 0x59, 0x52, 0x6b, 0x5c, 0x65, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x59, 0x52, 0x6b, 0x5c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x52, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x6b, 0x0c, 0x45, 0x6e, 0x57}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x40, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x6e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x09, 0x72, 0x7b, 0x0c, 0x45, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x72, 0x7b, 0x0c, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x7b, 0x04, 0x4d, 0x7e, 0x77}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x7e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x48, 0x01, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x04, 0x4d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67}, - {0x68, 0x51, 0x62, 0x5b, 0x54, 0x6d, 0x5e, 0x67} - } - }, - { /* 12,000bps map */ - { - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27} - }, - { - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27} - }, - { - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27} - }, - { - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27} - }, - { - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x13, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x3d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x1b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x14, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x32, 0x0b, 0x24, 0x3d, 0x16, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x38, 0x01, 0x22, 0x1b, 0x04, 0x2d, 0x0e, 0x27}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x22, 0x3b, 0x0c, 0x35, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x13, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x16, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x3d, 0x0e, 0x37}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x22, 0x0b, 0x04, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x01, 0x22, 0x1b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x1e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x14, 0x35, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x0e, 0x37}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x0e, 0x2f}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x0e, 0x2f}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x38, 0x01, 0x2a, 0x0b, 0x24, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x22, 0x0b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x2b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x2b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x22, 0x3b, 0x0c, 0x2d, 0x0e, 0x27}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x2e, 0x27}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x2e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x3e, 0x27}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x0e, 0x2f}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x0e, 0x2f}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x0e, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x2b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x2b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x2b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x2e, 0x27}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x2e, 0x27}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x2e, 0x27}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x32, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x1d, 0x06, 0x37}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x38, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x0e, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x01, 0x2a, 0x0b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x22, 0x2b, 0x0c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x2d, 0x2e, 0x27}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x30, 0x11, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x0b, 0x24, 0x0d, 0x06, 0x2f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x28, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x2a, 0x2b, 0x2c, 0x2d, 0x0e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x3b, 0x0c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x1d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x2a, 0x03, 0x24, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x0b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x0e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x02, 0x2b, 0x0c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07}, - {0x20, 0x19, 0x02, 0x3b, 0x1c, 0x25, 0x3e, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x2a, 0x03, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x2b, 0x2c, 0x0d, 0x06, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x2e, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x28, 0x09, 0x0a, 0x2b, 0x2c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x02, 0x2b, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07} - }, - { - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x18, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x21, 0x3a, 0x03, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x2a, 0x23, 0x2c, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x0d, 0x26, 0x2f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x28, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x09, 0x0a, 0x2b, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07}, - {0x20, 0x19, 0x02, 0x33, 0x1c, 0x25, 0x36, 0x07} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x29, 0x3a, 0x23, 0x34, 0x0d, 0x06, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x08, 0x29, 0x0a, 0x2b, 0x2c, 0x05, 0x26, 0x0f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x0a, 0x33, 0x3c, 0x25, 0x2e, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x0d, 0x26, 0x3f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x0a, 0x23, 0x2c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x29, 0x0a, 0x2b, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x2e, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x0f}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x0f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x03, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x08, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x29, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x0a, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x0f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x1c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17}, - {0x20, 0x19, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17} - }, - { - {0x10, 0x31, 0x3a, 0x23, 0x34, 0x15, 0x06, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x3f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x10, 0x31, 0x1a, 0x23, 0x34, 0x15, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x31, 0x1a, 0x23, 0x34, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x1a, 0x23, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x26, 0x1f}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x00, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x05, 0x36, 0x17}, - {0x20, 0x39, 0x12, 0x33, 0x3c, 0x25, 0x36, 0x17} - } - }, - { /* 9,600bps map */ - { - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x0e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x01, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x12, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x1c, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x00, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x01, 0x12, 0x13, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x12, 0x13, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x09, 0x02, 0x13, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x09, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x1b, 0x0c, 0x1d, 0x0e, 0x07}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x10, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x0e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x11, 0x12, 0x0b, 0x0c, 0x1d, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x12, 0x0b, 0x0c, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x0b, 0x14, 0x15, 0x1e, 0x0f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f}, - {0x08, 0x19, 0x02, 0x03, 0x14, 0x15, 0x1e, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x1d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x06, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x1d, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x15, 0x16, 0x0f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x15, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x06, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x11, 0x1a, 0x0b, 0x0c, 0x0d, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x1a, 0x0b, 0x0c, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x08, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x07}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x1f} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17} - }, - { - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x10, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x1b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x06, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x11, 0x1a, 0x0b, 0x04, 0x0d, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x1a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x0b, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x04, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17}, - {0x18, 0x19, 0x0a, 0x03, 0x14, 0x05, 0x16, 0x17} - } - }, - { /* 7,200bps map */ - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x03, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x04, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x06, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x03, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x04, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07}, - {0x08, 0x01, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - }, - { - {0x00, 0x09, 0x0a, 0x0b, 0x0c, 0x05, 0x06, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x0f}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x00, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x05, 0x0e, 0x07}, - {0x08, 0x09, 0x02, 0x0b, 0x0c, 0x0d, 0x0e, 0x07} - } - } -}; - -static const uint8_t constel_map_4800[36][36] = -{ /* 4,800bps map - No trellis. V.32/V.32bis only */ - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x00, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01, - 0x01, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x01 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - }, - { - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x02, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03, - 0x03 - } -}; - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17_v32bis_tx_constellation_maps.h b/libs/spandsp/src/v17_v32bis_tx_constellation_maps.h deleted file mode 100644 index 5ce8db44c8..0000000000 --- a/libs/spandsp/src/v17_v32bis_tx_constellation_maps.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v17_v32bis_tx_constellation_maps.h - ITU V.17 and V.32bis modems - * transmit part. Constellation mapping. - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 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 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_USE_FIXED_POINTx) -static const complexi16_t v17_v32bis_14400_constellation[128] = -#else -static const complexf_t v17_v32bis_14400_constellation[128] = -#endif -{ - {FP_CONSTELLATION_SCALE(-8.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x00 */ - {FP_CONSTELLATION_SCALE( 9.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x01 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-9.0f)}, /* 0x02 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 8.0f)}, /* 0x03 */ - {FP_CONSTELLATION_SCALE( 8.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x04 */ - {FP_CONSTELLATION_SCALE(-9.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x05 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 9.0f)}, /* 0x06 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-8.0f)}, /* 0x07 */ - {FP_CONSTELLATION_SCALE(-8.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x08 */ - {FP_CONSTELLATION_SCALE( 9.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x09 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-9.0f)}, /* 0x0A */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 8.0f)}, /* 0x0B */ - {FP_CONSTELLATION_SCALE( 8.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x0C */ - {FP_CONSTELLATION_SCALE(-9.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x0D */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 9.0f)}, /* 0x0E */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-8.0f)}, /* 0x0F */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x10 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x11 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x12 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x13 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x14 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x15 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x16 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x17 */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x18 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x19 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x1A */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x1B */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x1C */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x1D */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x1E */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x1F */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x20 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x21 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x22 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x23 */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x24 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x25 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x26 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x27 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x28 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x29 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x2A */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x2B */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x2C */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x2D */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x2E */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x2F */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x30 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x31 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x32 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x33 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x34 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x35 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x36 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x37 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x38 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x39 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x3A */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x3B */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x3C */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x3D */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x3E */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x3F */ - {FP_CONSTELLATION_SCALE( 8.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x40 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x41 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x42 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-8.0f)}, /* 0x43 */ - {FP_CONSTELLATION_SCALE(-8.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x44 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x45 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x46 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 8.0f)}, /* 0x47 */ - {FP_CONSTELLATION_SCALE( 8.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x48 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x49 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x4A */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-8.0f)}, /* 0x4B */ - {FP_CONSTELLATION_SCALE(-8.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x4C */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x4D */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x4E */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 8.0f)}, /* 0x4F */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x50 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x51 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x52 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x53 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x54 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x55 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x56 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x57 */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x58 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x59 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x5A */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x5B */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x5C */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x5D */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x5E */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x5F */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x60 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x61 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x62 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x63 */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x64 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x65 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x66 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x67 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x68 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x69 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x6A */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x6B */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x6C */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x6D */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x6E */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x6F */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x70 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x71 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x72 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x73 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x74 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x75 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x76 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x77 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x78 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x79 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x7A */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x7B */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x7C */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x7D */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x7E */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 0.0f)} /* 0x7F */ -}; - -#if defined(SPANDSP_USE_FIXED_POINTx) -static const complexi16_t v17_v32bis_12000_constellation[64] = -#else -static const complexf_t v17_v32bis_12000_constellation[64] = -#endif -{ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x00 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x01 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x02 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x03 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x04 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x05 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x06 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x07 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x08 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x09 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x0A */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x0B */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x0C */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x0D */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x0E */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x0F */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x10 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x11 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x12 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x13 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x14 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x15 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x16 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x17 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x18 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x19 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x1A */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x1B */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x1C */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x1D */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x1E */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x1F */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x20 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x21 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x22 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x23 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x24 */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x25 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x26 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x27 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x28 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x29 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x2A */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x2B */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x2C */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 0x2D */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x2E */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 0x2F */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x30 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x31 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x32 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x33 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x34 */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x35 */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x36 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 0x37 */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x38 */ - {FP_CONSTELLATION_SCALE( 7.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x39 */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-7.0f)}, /* 0x3A */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 0x3B */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 0x3C */ - {FP_CONSTELLATION_SCALE(-7.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 0x3D */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 7.0f)}, /* 0x3E */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-5.0f)} /* 0x3F */ -}; - -#if defined(SPANDSP_USE_FIXED_POINTx) -static const complexi16_t v17_v32bis_9600_constellation[32] = -#else -static const complexf_t v17_v32bis_9600_constellation[32] = -#endif -{ - {FP_CONSTELLATION_SCALE(-8.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x00 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x01 */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x02 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 8.0f)}, /* 0x03 */ - {FP_CONSTELLATION_SCALE( 8.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x04 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x05 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x06 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-8.0f)}, /* 0x07 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x08 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x09 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x0A */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x0B */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x0C */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x0D */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x0E */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x0F */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x10 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x11 */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x12 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x13 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x14 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x15 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x16 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0x17 */ - {FP_CONSTELLATION_SCALE( 8.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x18 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 4.0f)}, /* 0x19 */ - {FP_CONSTELLATION_SCALE( 4.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x1A */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-8.0f)}, /* 0x1B */ - {FP_CONSTELLATION_SCALE(-8.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x1C */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-4.0f)}, /* 0x1D */ - {FP_CONSTELLATION_SCALE(-4.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x1E */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 8.0f)} /* 0x1F */ -}; - -#if defined(SPANDSP_USE_FIXED_POINTx) -static const complexi16_t v17_v32bis_7200_constellation[16] = -#else -static const complexf_t v17_v32bis_7200_constellation[16] = -#endif -{ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x00 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x01 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x02 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x03 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x04 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x05 */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x06 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x07 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x08 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x09 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x0A */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x0B */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x0C */ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* 0x0D */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x0E */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE(-2.0f)} /* 0x0F */ -}; - -/* This one does not exist in V.17 as a data constellation. It is only - the equaliser training constellation. In V.32/V.32bis it is a data mode. */ -#if defined(SPANDSP_USE_FIXED_POINTx) -static const complexi16_t v17_v32bis_4800_constellation[4] = -#else -static const complexf_t v17_v32bis_4800_constellation[4] = -#endif -{ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* 0x00 */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 6.0f)}, /* 0x01 */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* 0x02 */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 2.0f)} /* 0x03 */ -}; - -#if defined(SPANDSP_USE_FIXED_POINTx) -static const complexi16_t v17_v32bis_abcd_constellation[4] = -#else -static const complexf_t v17_v32bis_abcd_constellation[4] = -#endif -{ - {FP_CONSTELLATION_SCALE(-6.0f), FP_CONSTELLATION_SCALE(-2.0f)}, /* A */ - {FP_CONSTELLATION_SCALE( 2.0f), FP_CONSTELLATION_SCALE(-6.0f)}, /* B */ - {FP_CONSTELLATION_SCALE( 6.0f), FP_CONSTELLATION_SCALE( 2.0f)}, /* C */ - {FP_CONSTELLATION_SCALE(-2.0f), FP_CONSTELLATION_SCALE( 6.0f)} /* D */ -}; - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c deleted file mode 100644 index 19ae7ccf48..0000000000 --- a/libs/spandsp/src/v17rx.c +++ /dev/null @@ -1,1636 +0,0 @@ -#define IAXMODEM_STUFF -/* - * SpanDSP - a series of DSP components for telephony - * - * v17rx.c - ITU V.17 modem receive part - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 2005, 2006, 2007 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 "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" -#include "spandsp/saturated.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/power_meter.h" -#include "spandsp/arctan2.h" -#include "spandsp/dds.h" -#include "spandsp/complex_filters.h" - -#include "spandsp/v29rx.h" -#include "spandsp/v17tx.h" -#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) -#define FP_SCALE(x) FP_Q6_10(x) -#define FP_FACTOR 1024 -#define FP_SHIFT_FACTOR 12 -#else -#define FP_SCALE(x) (x) -#endif - -#if defined(SPANDSP_USE_FIXED_POINTx) -#define FP_SYNC_SCALE(x) FP_Q6_10(x) -#define FP_SYNC_SCALE_32(x) FP_Q22_10(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" - -/*! The nominal frequency of the carrier, in Hertz */ -#define CARRIER_NOMINAL_FREQ 1800.0f -/*! The nominal baud or symbol rate */ -#define BAUD_RATE 2400 -/*! The adaption rate coefficient for the equalizer during initial training */ -#define EQUALIZER_FAST_ADAPTION_DELTA (0.21f/V17_EQUALIZER_LEN) -/*! The adaption rate coefficient for the equalizer during fine tuning */ -#define EQUALIZER_SLOW_ADAPTION_DELTA (0.1f*EQUALIZER_FAST_ADAPTION_DELTA) - -/* Segments of the training sequence */ -/*! The length of training segment 1, in symbols */ -#define V17_TRAINING_SEG_1_LEN 256 -/*! The length of training segment 2 in long training mode, in symbols */ -#define V17_TRAINING_SEG_2_LEN 2976 -/*! The length of training segment 2 in short training mode, in symbols */ -#define V17_TRAINING_SHORT_SEG_2_LEN 38 -/*! The length of training segment 3, in symbols */ -#define V17_TRAINING_SEG_3_LEN 64 -/*! The length of training segment 4A, in symbols */ -#define V17_TRAINING_SEG_4A_LEN 15 -/*! The length of training segment 4, in symbols */ -#define V17_TRAINING_SEG_4_LEN 48 - -/*! 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, - TRAINING_STAGE_SYMBOL_ACQUISITION, - TRAINING_STAGE_LOG_PHASE, - TRAINING_STAGE_SHORT_WAIT_FOR_CDBA, - TRAINING_STAGE_WAIT_FOR_CDBA, - TRAINING_STAGE_COARSE_TRAIN_ON_CDBA, - TRAINING_STAGE_FINE_TRAIN_ON_CDBA, - TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST, - TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST, - TRAINING_STAGE_BRIDGE, - TRAINING_STAGE_TCM_WINDUP, - TRAINING_STAGE_TEST_ONES, - TRAINING_STAGE_PARKED -}; - -#if defined(SPANDSP_USE_FIXED_POINTx) -static const int16_t constellation_spacing[4] = -#else -static const float constellation_spacing[4] = -#endif -{ - FP_SCALE(1.414f), - FP_SCALE(2.0f), - FP_SCALE(2.828f), - FP_SCALE(4.0f) -}; - -SPAN_DECLARE(float) v17_rx_carrier_frequency(v17_rx_state_t *s) -{ - return dds_frequencyf(s->carrier_phase_rate); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v17_rx_symbol_timing_correction(v17_rx_state_t *s) -{ - return (float) s->total_baud_timing_correction/((float) RX_PULSESHAPER_COEFF_SETS*10.0f/3.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v17_rx_signal_power(v17_rx_state_t *s) -{ - return power_meter_current_dbm0(&s->power) + 3.98f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_rx_signal_cutoff(v17_rx_state_t *s, float cutoff) -{ - /* The 0.4 factor allows for the gain of the DC blocker */ - s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f); - s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f); -} -/*- End of function --------------------------------------------------------*/ - -static void report_status_change(v17_rx_state_t *s, int status) -{ - if (s->status_handler) - s->status_handler(s->status_user_data, status); - else if (s->put_bit) - s->put_bit(s->put_bit_user_data, status); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v17_rx_equalizer_state(v17_rx_state_t *s, complexi16_t **coeffs) -#else -SPAN_DECLARE(int) v17_rx_equalizer_state(v17_rx_state_t *s, complexf_t **coeffs) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - *coeffs = NULL; - return 0; -#else - *coeffs = s->eq_coeff; - return V17_EQUALIZER_LEN; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_save(v17_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINTx) - cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_LEN); -#else - cvec_copyf(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_LEN); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_restore(v17_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINTx) - cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_LEN); - cvec_zeroi16(s->eq_buf, V17_EQUALIZER_LEN); - s->eq_delta = 32768.0f*EQUALIZER_SLOW_ADAPTION_DELTA; -#else - cvec_copyf(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_LEN); - cvec_zerof(s->eq_buf, V17_EQUALIZER_LEN); - s->eq_delta = EQUALIZER_SLOW_ADAPTION_DELTA; -#endif - - s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1; - s->eq_step = 0; - s->eq_skip = 0; -} -/*- End of function --------------------------------------------------------*/ - -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_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_FAST_ADAPTION_DELTA; -#else - 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; - cvec_zerof(s->eq_buf, V17_EQUALIZER_LEN); - s->eq_delta = EQUALIZER_FAST_ADAPTION_DELTA; -#endif - - s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1; - s->eq_step = 0; - s->eq_skip = 0; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINTx) -static __inline__ complexi16_t equalizer_get(v17_rx_state_t *s) -{ - complexi32_t zz; - complexi16_t z; - - /* Get the next equalized value. */ - zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V17_EQUALIZER_LEN, s->eq_step); - z.re = zz.re >> FP_SHIFT_FACTOR; - z.im = zz.im >> FP_SHIFT_FACTOR; - return z; -} -#else -static __inline__ complexf_t equalizer_get(v17_rx_state_t *s) -{ - /* Get the next equalized value. */ - return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V17_EQUALIZER_LEN, s->eq_step); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINTx) -static void tune_equalizer(v17_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) -{ - complexi16_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subi16(target, z); - err.re = ((int32_t) err.re*s->eq_delta) >> 15; - err.im = ((int32_t) err.im*s->eq_delta) >> 15; - cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V17_EQUALIZER_LEN, s->eq_step, &err); -} -#else -static void tune_equalizer(v17_rx_state_t *s, const complexf_t *z, const complexf_t *target) -{ - complexf_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subf(target, z); - //span_log(&s->logging, SPAN_LOG_FLOW, "Equalizer error %f\n", sqrt(err.re*err.re + err.im*err.im)); - err.re *= s->eq_delta; - err.im *= s->eq_delta; - cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V17_EQUALIZER_LEN, s->eq_step, &err); -} -#endif -/*- 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 -static __inline__ void track_carrier(v17_rx_state_t *s, const complexf_t *z, const complexf_t *target) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINTx) - int32_t error; -#else - float error; -#endif - - /* For small errors the imaginary part of the difference between the actual and the target - positions is proportional to the phase error, for any particular target. However, the - different amplitudes of the various target positions scale things. */ -#if defined(SPANDSP_USE_FIXED_POINTx) - error = z->im*(((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 - error = z->im*target->re - z->re*target->im; - s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error); - s->carrier_phase += (int32_t) (s->carrier_track_p*error); - //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate)); -#endif -} -/*- 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); - /*endif*/ - 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) - { - s->put_bit(s->put_bit_user_data, out_bit); - } - else if (s->training_stage == TRAINING_STAGE_TEST_ONES) - { - /* 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. */ - //span_log(&s->logging, SPAN_LOG_FLOW, "A 1 is really %d\n", out_bit); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINTx) -static __inline__ uint32_t dist_sq(const complexi16_t *x, const complexi16_t *y) -{ - 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 -static __inline__ float dist_sq(const complexf_t *x, const complexf_t *y) -{ - return (x->re - y->re)*(x->re - y->re) + (x->im - y->im)*(x->im - y->im); -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(SPANDSP_USE_FIXED_POINTx) -static int decode_baud(v17_rx_state_t *s, complexi16_t *z) -#else -static int decode_baud(v17_rx_state_t *s, complexf_t *z) -#endif -{ - static const uint8_t v32bis_4800_differential_decoder[4][4] = - { - {2, 3, 0, 1}, - {0, 2, 1, 3}, - {3, 1, 2, 0}, - {1, 0, 3, 2} - }; - static const uint8_t v17_differential_decoder[4][4] = - { - {0, 1, 2, 3}, - {3, 0, 1, 2}, - {2, 3, 0, 1}, - {1, 2, 3, 0} - }; - static const uint8_t tcm_paths[8][4] = - { - {0, 6, 2, 4}, - {6, 0, 4, 2}, - {2, 4, 0, 6}, - {4, 2, 6, 0}, - {1, 3, 7, 5}, - {5, 7, 3, 1}, - {7, 5, 1, 3}, - {3, 1, 5, 7} - }; - int nearest; - int i; - int j; - int k; - int re; - int im; - int raw; - int min_index; - int set; - int constellation_state; -#if defined(SPANDSP_USE_FIXED_POINTx) -#define DIST_FACTOR 1024 /* Something less than sqrt(0xFFFFFFFF/10)/10 */ - complexi32_t zi; - uint32_t distances[8]; - uint32_t new_distances[8]; - uint32_t min; - complexi32_t ci; -#else - float distances[8]; - float new_distances[8]; - float min; -#endif - -#if defined(SPANDSP_USE_FIXED_POINTx) - 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 + FP_CONSTELLATION_SCALE(9.0f))*2.0f); - im = (int) ((z->im + FP_CONSTELLATION_SCALE(9.0f))*2.0f); -#endif - if (re > 35) - re = 35; - else if (re < 0) - re = 0; - /*endif*/ - if (im > 35) - im = 35; - else if (im < 0) - im = 0; - /*endif*/ - if (s->bits_per_symbol == 2) - { - /* 4800bps V.32bis mode, without trellis coding */ - constellation_state = constel_map_4800[re][im]; - raw = v32bis_4800_differential_decoder[s->diff][constellation_state]; - s->diff = constellation_state; - put_bit(s, raw); - put_bit(s, raw >> 1); - return constellation_state; - } - /*endif*/ - - /* Find a set of 8 candidate constellation positions, that are the closest - to the target, with different patterns in the last 3 bits. */ -#if defined(SPANDSP_USE_FIXED_POINTx) - min = 0xFFFFFFFF; - zi = complex_seti32(z->re*DIST_FACTOR, z->im*DIST_FACTOR); -#else - min = 9999999.0f; -#endif - min_index = 0; - for (i = 0; i < 8; i++) - { - nearest = constel_maps[s->space_map][re][im][i]; -#if defined(SPANDSP_USE_FIXED_POINTx) - ci = complex_seti32(s->constellation[nearest].re*DIST_FACTOR, - s->constellation[nearest].im*DIST_FACTOR); - distances[i] = dist_sq(&ci, &zi); -#else - distances[i] = dist_sq(&s->constellation[nearest], z); -#endif - if (min > distances[i]) - { - min = distances[i]; - min_index = i; - } - /*endif*/ - } - /*endfor*/ - /* Use the nearest of these soft-decisions as the basis for DFE and carrier - tracking. This is a compromise. It means we will use the correct error - less often, but using the output of the traceback would put more lag - into the feedback path. */ - constellation_state = constel_maps[s->space_map][re][im][min_index]; - track_carrier(s, z, &s->constellation[constellation_state]); - //tune_equalizer(s, z, &s->constellation[constellation_state]); - - /* Now do the trellis decoding */ - - /* TODO: change to processing blocks of stored symbols here, instead of processing - one symbol at a time, to speed up the processing. */ - - /* Update the minimum accumulated distance to each of the 8 states */ - if (++s->trellis_ptr >= V17_TRELLIS_STORAGE_DEPTH) - s->trellis_ptr = 0; - /*endif*/ - for (i = 0; i < 8; i++) - { - set = i >> 2; - min = distances[tcm_paths[i][0]] + s->distances[set]; - min_index = 0; - for (j = 1; j < 4; j++) - { - k = (j << 1) + set; - if (min > distances[tcm_paths[i][j]] + s->distances[k]) - { - min = distances[tcm_paths[i][j]] + s->distances[k]; - min_index = j; - } - /*endif*/ - } - /*endfor*/ - k = (min_index << 1) + set; - /* Use an elementary IIR filter to track the distance to date. */ -#if defined(SPANDSP_USE_FIXED_POINTx) - new_distances[i] = s->distances[k]*9/10 + distances[tcm_paths[i][min_index]]*1/10; -#else - new_distances[i] = s->distances[k]*0.9f + distances[tcm_paths[i][min_index]]*0.1f; -#endif - s->full_path_to_past_state_locations[s->trellis_ptr][i] = constel_maps[s->space_map][re][im][tcm_paths[i][min_index]]; - s->past_state_locations[s->trellis_ptr][i] = k; - } - /*endfor*/ - memcpy(s->distances, new_distances, sizeof(s->distances)); - - /* Find the minimum distance to date. This is the start of the path back to the result. */ - min = s->distances[0]; - min_index = 0; - for (i = 1; i < 8; i++) - { - if (min > s->distances[i]) - { - min = s->distances[i]; - min_index = i; - } - /*endif*/ - } - /*endfor*/ - /* Trace back through every time step, starting with the current one, and find the - state from which the path came one step before. At the end of this search, the - last state found also points to the constellation point at that state. This is the - output of the trellis. */ - k = min_index; - for (i = 0, j = s->trellis_ptr; i < V17_TRELLIS_LOOKBACK_DEPTH - 1; i++) - { - k = s->past_state_locations[j][k]; - if (--j < 0) - j = V17_TRELLIS_STORAGE_DEPTH - 1; - /*endif*/ - } - /*endfor*/ - nearest = s->full_path_to_past_state_locations[j][k] >> 1; - - /* Differentially decode */ - raw = (nearest & 0x3C) | v17_differential_decoder[s->diff][nearest & 0x03]; - s->diff = nearest & 0x03; - for (i = 0; i < s->bits_per_symbol; i++) - { - put_bit(s, raw); - raw >>= 1; - } - /*endfor*/ - return constellation_state; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void symbol_sync(v17_rx_state_t *s) -{ - int i; -#if defined(SPANDSP_USE_FIXED_POINTx) - int32_t v; - int32_t p; -#else - float v; - float p; -#endif - - /* This routine adapts the position of the half baud samples entering the equalizer. */ - - /* This symbol sync scheme is based on the technique first described by Dominique Godard in - Passband Timing Recovery in an All-Digital Modem Receiver - IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */ - - /* This is slightly rearranged from figure 3b of the Godard paper, as this saves a couple of - maths operations */ -#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] >> (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]; - s->symbol_sync_dc_filter[0] = v; - /* A little integration will now filter away much of the HF noise */ - s->baud_phase -= p; - v = labs(s->baud_phase); -#else - /* Cross correlate */ - v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2 - - s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2 - + s->symbol_sync_low[1]*s->symbol_sync_high[1]*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]; - s->symbol_sync_dc_filter[0] = v; - /* A little integration will now filter away much of the HF noise */ - s->baud_phase -= p; - v = fabsf(s->baud_phase); -#endif - if (v > FP_SYNC_SCALE_32(100.0f)) - { - i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 15 : 1; - if (s->baud_phase < FP_SYNC_SCALE_32(0.0f)) - i = -i; - /*endif*/ - //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; - s->total_baud_timing_correction += i; - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINTx) -static void process_half_baud(v17_rx_state_t *s, const complexi16_t *sample) -#else -static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINTx) - static const complexi16_t cdba[4] = -#else - static const complexf_t cdba[4] = -#endif - { - {FP_SCALE( 6.0f), FP_SCALE( 2.0f)}, - {FP_SCALE(-2.0f), FP_SCALE( 6.0f)}, - {FP_SCALE( 2.0f), FP_SCALE(-6.0f)}, - {FP_SCALE(-6.0f), FP_SCALE(-2.0f)} - }; -#if defined(SPANDSP_USE_FIXED_POINTx) - uint16_t ip; - complexi16_t z; - complexi16_t z16; - const complexi16_t *target; - 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 = {FP_SCALE(0.0f), FP_SCALE(0.0f)}; -#endif - int bit; - int i; - int j; - uint32_t phase_step; - int32_t angle; - int32_t ang; - int constellation_state; - - /* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate. */ - - /* Add a sample to the equalizer's circular buffer, but don't calculate anything at this time. */ - s->eq_buf[s->eq_step] = *sample; - if (++s->eq_step >= V17_EQUALIZER_LEN) - s->eq_step = 0; - /*endif*/ - - /* On alternate insertions we have a whole baud and must process it. */ - if ((s->baud_half ^= 1)) - return; - /*endif*/ - - /* Symbol timing synchronisation */ - symbol_sync(s); - - z = equalizer_get(s); - - constellation_state = 0; - switch (s->training_stage) - { - case TRAINING_STAGE_NORMAL_OPERATION: - /* Normal operation. */ - constellation_state = decode_baud(s, &z); - target = &s->constellation[constellation_state]; - break; - case TRAINING_STAGE_SYMBOL_ACQUISITION: - /* Allow time for the symbol synchronisation to settle the symbol timing. */ - target = &zero; - if (++s->training_count >= 100) - { - /* Record the current phase angle */ - s->training_stage = TRAINING_STAGE_LOG_PHASE; - vec_zeroi32(s->diff_angles, 16); - s->last_angles[0] = arctan2(z.im, z.re); - if (s->agc_scaling_save == FP_SCALE(0.0f)) - s->agc_scaling_save = s->agc_scaling; - /*endif*/ - } - /*endif*/ - break; - case TRAINING_STAGE_LOG_PHASE: - /* Record the current alternate phase angle */ - target = &zero; - angle = arctan2(z.im, z.re); - s->training_count = 1; - if (s->short_train) - { - /* We should already know the accurate carrier frequency. All we need to sort - out is the phase. */ - /* Check if we just saw A or B */ - /* atan(1/3) = 18.433 degrees */ - if ((uint32_t) (angle - s->last_angles[0]) < (uint32_t) DDS_PHASE(180.0f)) - { - angle = s->last_angles[0]; - s->last_angles[0] = DDS_PHASE(270.0f + 18.433f); - s->last_angles[1] = DDS_PHASE(180.0f + 18.433f); - } - else - { - s->last_angles[0] = DDS_PHASE(180.0f + 18.433f); - s->last_angles[1] = DDS_PHASE(270.0f + 18.433f); - } - /*endif*/ - /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer - buffer, as well as the carrier phase, for this to play out nicely. */ - /* angle is now the difference between where A is, and where it should be */ - phase_step = angle - DDS_PHASE(180.0f + 18.433f); -#if defined(SPANDSP_USE_FIXED_POINTx) - ip = phase_step >> 16; - span_log(&s->logging, SPAN_LOG_FLOW, "Spin (short) by %d\n", ip); - z16 = complex_seti16(fixed_cos(ip), -fixed_sin(ip)); - for (i = 0; i < V17_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mul_q1_15(&s->eq_buf[i], &z16); - /*endfor*/ - s->carrier_track_p = 500000; -#else - p = dds_phase_to_radians(phase_step); - span_log(&s->logging, SPAN_LOG_FLOW, "Spin (short) by %.5f rads\n", p); - zz = complex_setf(cosf(p), -sinf(p)); - for (i = 0; i < V17_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz); - /*endfor*/ - s->carrier_track_p = 500000.0f; -#endif - s->carrier_phase += phase_step; - s->training_stage = TRAINING_STAGE_SHORT_WAIT_FOR_CDBA; - } - else - { - s->last_angles[1] = angle; - s->training_stage = TRAINING_STAGE_WAIT_FOR_CDBA; - } - /*endif*/ - break; - case TRAINING_STAGE_WAIT_FOR_CDBA: - target = &zero; - angle = arctan2(z.im, z.re); - /* Look for the initial ABAB sequence to display a phase reversal, which will - signal the start of the scrambled CDBA segment */ - i = s->training_count + 1; - ang = angle - s->last_angles[i & 1]; - s->last_angles[i & 1] = angle; - s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4); - if ((ang > DDS_PHASE(90.0f) || ang < DDS_PHASE(-90.0f)) && s->training_count >= 13) - { - span_log(&s->logging, SPAN_LOG_FLOW, "We seem to have a reversal at symbol %d\n", s->training_count); - /* We seem to have a phase reversal */ - /* Slam the carrier frequency into line, based on the total phase drift over the last - section. Use the shift from the odd bits and the shift from the even bits to get - better jitter suppression. */ - /* Step back a few symbols so we don't get ISI distorting things. */ - i = (s->training_count - 8) & ~1; - /* Avoid the possibility of a divide by zero */ - if (i > 1) - { - j = i & 0xF; - ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1); - s->carrier_phase_rate += 3*16*(ang/20); - span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, dist %d\n", s->last_angles[0], s->last_angles[1], i); - } - /*endif*/ - span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count); - /* Check if the carrier frequency is plausible */ - if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f) - || - s->carrier_phase_rate > DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ + 20.0f)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); - /* Park this modem */ - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - break; - } - /*endif*/ - - /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer buffer, - as well as the carrier phase, for this to play out nicely. */ - /* angle is now the difference between where C is, and where it should be */ - phase_step = angle - DDS_PHASE(18.433f); -#if defined(SPANDSP_USE_FIXED_POINTx) - ip = phase_step >> 16; - span_log(&s->logging, SPAN_LOG_FLOW, "Spin (long) by %d\n", ip); - z16 = complex_seti16(fixed_cos(ip), -fixed_sin(ip)); - for (i = 0; i < V17_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mul_q1_15(&s->eq_buf[i], &z16); - /*endfor*/ -#else - p = dds_phase_to_radians(phase_step); - span_log(&s->logging, SPAN_LOG_FLOW, "Spin (long) by %.5f rads\n", p); - zz = complex_setf(cosf(p), -sinf(p)); - for (i = 0; i < V17_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz); - /*endfor*/ -#endif - s->carrier_phase += phase_step; - - /* We have just seen the first symbol of the scrambled sequence, so skip it. */ - bit = descramble(s, 1); - bit = (bit << 1) | descramble(s, 1); - target = &cdba[bit]; - s->training_count = 1; - s->training_stage = TRAINING_STAGE_COARSE_TRAIN_ON_CDBA; - report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS); - break; - } - /*endif*/ - if (++s->training_count > V17_TRAINING_SEG_1_LEN) - { - /* This is bogus. There are not this many bits in this section - 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 */ - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - /*endif*/ - break; - case TRAINING_STAGE_COARSE_TRAIN_ON_CDBA: - /* Train on the scrambled CDBA section. */ - bit = descramble(s, 1); - bit = (bit << 1) | descramble(s, 1); - target = &cdba[bit]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); -#if defined(IAXMODEM_STUFF) -#if defined(SPANDSP_USE_FIXED_POINTx) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error = powerf(&zz); -#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 - { - /* Now the equaliser adaption should be getting somewhere, slow it down, or it will never - tune very well on a noisy signal. */ - s->eq_delta = EQUALIZER_SLOW_ADAPTION_DELTA; -#if defined(SPANDSP_USE_FIXED_POINTx) - s->carrier_track_i = 1000; -#else - s->carrier_track_i = 1000.0f; -#endif - s->training_stage = TRAINING_STAGE_FINE_TRAIN_ON_CDBA; - } - /*endif*/ - break; - case TRAINING_STAGE_FINE_TRAIN_ON_CDBA: - /* Train on the scrambled CDBA section. */ - bit = descramble(s, 1); - bit = (bit << 1) | descramble(s, 1); - target = &cdba[bit]; - /* By this point the training should be comming into focus. */ - track_carrier(s, &z, target); - 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->carrier_track_i = 100; - s->carrier_track_p = 500000; -#else - s->carrier_track_i = 100.0f; - s->carrier_track_p = 500000.0f; -#endif - s->training_stage = TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST; - } - /*endif*/ - break; - case TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST: - /* Continue training on the scrambled CDBA section, but measure the quality of training too. */ - bit = descramble(s, 1); - bit = (bit << 1) | descramble(s, 1); - target = &cdba[bit]; - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d [%15.5f, %15.5f] [%15.5f, %15.5f]\n", s->training_count, z.re, z.im, cdba[bit].re, cdba[bit].im); - /* We ignore the last few symbols because it seems some modems do not end this - part properly, and it throws things off. */ - if (++s->training_count < V17_TRAINING_SEG_2_LEN - 20) - { - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - /* Measure the training error */ -#if defined(SPANDSP_USE_FIXED_POINTx) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error += powerf(&zz); -#endif - } - else if (s->training_count >= V17_TRAINING_SEG_2_LEN) - { -#if defined(SPANDSP_USE_FIXED_POINTx) - span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %d\n", s->training_error); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %f\n", s->training_error); -#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; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n"); - /* Park this modem */ - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - /*endif*/ - } - /*endif*/ - break; - case TRAINING_STAGE_BRIDGE: - descramble(s, V17_BRIDGE_WORD >> ((s->training_count & 0x7) << 1)); - descramble(s, V17_BRIDGE_WORD >> (((s->training_count & 0x7) << 1) + 1)); - target = &z; - if (++s->training_count >= V17_TRAINING_SEG_3_LEN) - { - s->training_error = FP_SCALE(0.0f); - s->training_count = 0; - if (s->bits_per_symbol == 2) - { - /* Restart the differential decoder */ - /* There is no trellis, so go straight to processing decoded data */ - s->diff = (s->short_train) ? 0 : 1; - s->training_stage = TRAINING_STAGE_TEST_ONES; - } - else - { - /* Wait for the trellis to wind up */ - s->training_stage = TRAINING_STAGE_TCM_WINDUP; - } - /*endif*/ - } - /*endif*/ - break; - case TRAINING_STAGE_SHORT_WAIT_FOR_CDBA: - /* Look for the initial ABAB sequence to display a phase reversal, which will - signal the start of the scrambled CDBA segment */ - angle = arctan2(z.im, z.re); - ang = angle - s->last_angles[s->training_count & 1]; - if (ang > DDS_PHASE(90.0f) || ang < DDS_PHASE(-90.0f)) - { - /* We seem to have a phase reversal */ - /* We have just seen the first symbol of the scrambled sequence, so skip it. */ - bit = descramble(s, 1); - bit = (bit << 1) | descramble(s, 1); - target = &cdba[bit]; - s->training_error = FP_SCALE(0.0f); - s->training_count = 1; - s->training_stage = TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST; - } - else - { - target = &cdba[(s->training_count & 1) + 2]; - track_carrier(s, &z, target); - if (++s->training_count > V17_TRAINING_SEG_1_LEN) - { - /* This is bogus. There are not this many bits in this section - 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 */ - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - /*endif*/ - } - /*endif*/ - break; - case TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST: - /* Short retrain on the scrambled CDBA section, but measure the quality of training too. */ - bit = descramble(s, 1); - bit = (bit << 1) | descramble(s, 1); - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d [%15.5f, %15.5f] [%15.5f, %15.5f] %d\n", s->training_count, z.re, z.im, cdba[bit].re, cdba[bit].im, arctan2(z.im, z.re)); - target = &cdba[bit]; - track_carrier(s, &z, target); - //tune_equalizer(s, &z, target); - /* Measure the training error */ - if (s->training_count > 8) - { -#if defined(SPANDSP_USE_FIXED_POINTx) - z16 = complex_subi16(&z, &cdba[bit]); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, &cdba[bit]); - s->training_error += powerf(&zz); -#endif - } - /*endif*/ - if (++s->training_count >= V17_TRAINING_SHORT_SEG_2_LEN) - { -#if defined(SPANDSP_USE_FIXED_POINTx) - span_log(&s->logging, SPAN_LOG_FLOW, "Short training error %d\n", s->training_error); - s->carrier_track_i = 100; - s->carrier_track_p = 500000; -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Short training error %f\n", s->training_error); - s->carrier_track_i = 100.0f; - s->carrier_track_p = 500000.0f; -#endif - /* 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 (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) - { - /* There is no trellis, so go straight to processing decoded data */ - /* Restart the differential decoder */ - s->diff = (s->short_train) ? 0 : 1; - s->training_error = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_TEST_ONES; - } - else - { - /* Wait for the trellis to wind up */ - s->training_stage = TRAINING_STAGE_TCM_WINDUP; - } - /*endif*/ - report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Short training failed (convergence failed)\n"); - /* Park this modem */ - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - /*endif*/ - } - /*endif*/ - break; - case TRAINING_STAGE_TCM_WINDUP: - /* We need to wait 15 bauds while the trellis fills up. */ - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f\n", s->training_count, z.re, z.im); - constellation_state = decode_baud(s, &z); - target = &s->constellation[constellation_state]; - /* Measure the training error */ -#if defined(SPANDSP_USE_FIXED_POINTx) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error += powerf(&zz); -#endif - if (++s->training_count >= V17_TRAINING_SEG_4A_LEN) - { - s->training_error = FP_SCALE(0.0f); - s->training_count = 0; - /* Restart the differential decoder */ - s->diff = (s->short_train) ? 0 : 1; - s->training_stage = TRAINING_STAGE_TEST_ONES; - } - /*endif*/ - break; - case TRAINING_STAGE_TEST_ONES: - /* We are in the test phase, where we check that we can receive reliably. - We should get a run of 1's, 48 symbols long. */ - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f\n", s->training_count, z.re, z.im); - constellation_state = decode_baud(s, &z); - target = &s->constellation[constellation_state]; - /* Measure the training error */ -#if defined(SPANDSP_USE_FIXED_POINTx) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error += powerf(&zz); -#endif - if (++s->training_count >= V17_TRAINING_SEG_4_LEN) - { - 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 - 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 */ - report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); - /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through - the processing. */ - s->signal_present = 60; - equalizer_save(s); - s->carrier_phase_rate_save = s->carrier_phase_rate; - s->short_train = true; - s->training_stage = TRAINING_STAGE_NORMAL_OPERATION; - } - else - { - /* 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); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error); -#endif - if (!s->short_train) - s->agc_scaling_save = FP_SCALE(0.0f); - /*endif*/ - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - /*endif*/ - } - /*endif*/ - break; - case TRAINING_STAGE_PARKED: - default: - /* We failed to train! */ - /* Park here until the carrier drops. */ - target = &zero; - break; - } - /*endswitch*/ - if (s->qam_report) - { -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t zi; - complexi16_t targeti; - - zi.re = z.re*1024.0f; - zi.im = z.im*1024.0f; - targeti.re = target->re*1024.0f; - targeti.im = target->im*1024.0f; - s->qam_report(s->qam_user_data, &zi, &targeti, constellation_state); -#else - s->qam_report(s->qam_user_data, &z, target, constellation_state); -#endif - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp) -{ - int16_t diff; - int16_t x; - int32_t power; - - /* There should be no DC in the signal, but sometimes there is. - We need to measure the power with the DC blocked, but not using - a slow to respond DC blocker. Use the most elementary HPF. */ - x = amp >> 1; - /* There could be overflow here, but it isn't a problem in practice */ - diff = x - s->last_sample; - s->last_sample = x; - power = power_meter_update(&s->power, diff); -#if defined(IAXMODEM_STUFF) - /* Quick power drop fudge */ - diff = abs(diff); - if (10*diff < s->high_sample) - { - if (++s->low_samples > 120) - { - power_meter_init(&s->power, 4); - s->high_sample = 0; - s->low_samples = 0; - } - /*endif*/ - } - else - { - s->low_samples = 0; - if (diff > s->high_sample) - s->high_sample = diff; - /*endif*/ - } - /*endif*/ -#endif - if (s->signal_present > 0) - { - /* Look for power below turn-off threshold to turn the carrier off */ -#if defined(IAXMODEM_STUFF) - if (s->carrier_drop_pending || power < s->carrier_off_power) -#else - if (power < s->carrier_off_power) -#endif - { - if (--s->signal_present <= 0) - { - /* Count down a short delay, to ensure we push the last - few bits through the filters before stopping. */ - v17_rx_restart(s, s->bit_rate, s->short_train); - report_status_change(s, SIG_STATUS_CARRIER_DOWN); - return 0; - } - /*endif*/ -#if defined(IAXMODEM_STUFF) - /* Carrier has dropped, but the put_bit is pending the signal_present delay. */ - s->carrier_drop_pending = true; -#endif - } - /*endif*/ - } - else - { - /* Look for power exceeding turn-on threshold to turn the carrier on */ - if (power < s->carrier_on_power) - return 0; - /*endif*/ - s->signal_present = 1; -#if defined(IAXMODEM_STUFF) - s->carrier_drop_pending = false; -#endif - report_status_change(s, SIG_STATUS_CARRIER_UP); - } - /*endif*/ - return power; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len) -{ - int i; - int step; -#if defined(SPANDSP_USE_FIXED_POINTx) - complexi16_t z; - complexi16_t zz; - complexi16_t sample; - int32_t v; -#else - complexf_t z; - complexf_t zz; - complexf_t sample; - float v; -#endif - int32_t root_power; - int32_t power; - - for (i = 0; i < len; i++) - { - s->rrc_filter[s->rrc_filter_step] = amp[i]; - if (++s->rrc_filter_step >= V17_RX_FILTER_STEPS) - s->rrc_filter_step = 0; - /*endif*/ - - if ((power = signal_detect(s, amp[i])) == 0) - continue; - /*endif*/ - if (s->training_stage == TRAINING_STAGE_PARKED) - continue; - /*endif*/ - /* Only spend effort processing this data if the modem is not - parked, after training failure. */ - s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS; - step = -s->eq_put_step; - if (step < 0) - step += RX_PULSESHAPER_COEFF_SETS; - /*endif*/ - if (step < 0) - step = 0; - else if (step > RX_PULSESHAPER_COEFF_SETS - 1) - step = RX_PULSESHAPER_COEFF_SETS - 1; - /*endif*/ -#if defined(SPANDSP_USE_FIXED_POINTx) - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V17_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - 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) >> 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) >> 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 - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V17_RX_FILTER_STEPS, s->rrc_filter_step); - sample.re = v*s->agc_scaling; - /* Symbol timing synchronisation band edge filters */ - /* Low Nyquist band edge filter */ - v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0 + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1 + sample.re; - s->symbol_sync_low[1] = s->symbol_sync_low[0]; - s->symbol_sync_low[0] = v; - /* High Nyquist band edge filter */ - v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0 + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1 + sample.re; - s->symbol_sync_high[1] = s->symbol_sync_high[0]; - s->symbol_sync_high[0] = v; -#endif - /* Put things into the equalization buffer at T/2 rate. The symbol synchronisation - will fiddle the step to align this with the symbols. */ - if (s->eq_put_step <= 0) - { - /* Only AGC until we have locked down the setting. */ - if (s->agc_scaling_save == FP_SCALE(0.0f)) - { - if ((root_power = fixed_sqrt32(power)) == 0) - root_power = 1; - /*endif*/ -#if defined(SPANDSP_USE_FIXED_POINTx) - s->agc_scaling = saturate16(((int32_t) (FP_SCALE(2.17f)*1024.0f))/root_power); -#else - s->agc_scaling = (FP_SCALE(2.17f)/RX_PULSESHAPER_GAIN)/root_power; -#endif - } - /*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. */ -#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; - z = dds_lookup_complexi16(s->carrier_phase); - zz.re = ((int32_t) sample.re*z.re - (int32_t) sample.im*z.im) >> 15; - zz.im = ((int32_t) -sample.re*z.im - (int32_t) sample.im*z.re) >> 15; -#else - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_im[step], V17_RX_FILTER_STEPS, s->rrc_filter_step); - sample.im = v*s->agc_scaling; - z = dds_lookup_complexf(s->carrier_phase); - zz.re = sample.re*z.re - sample.im*z.im; - zz.im = -sample.re*z.im - sample.im*z.re; -#endif - s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2); - process_half_baud(s, &zz); - } - /*endif*/ -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - } - /*endfor*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len) -{ - int i; - - /* We want to sustain the current state (i.e carrier on<->carrier off), and - try to sustain the carrier phase. We should probably push the filters, as well */ - span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len); - if (s->signal_present <= 0) - return 0; - /*endif*/ - if (s->training_stage == TRAINING_STAGE_PARKED) - return 0; - /*endif*/ - for (i = 0; i < len; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - /* Advance the symbol phase the appropriate amount */ - s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS; - if (s->eq_put_step <= 0) - s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2); - /*endif*/ - /* TODO: Should we rotate any buffers */ - } - /*endfor*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit, void *user_data) -{ - s->put_bit = put_bit; - s->put_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v17_rx_get_logging_state(v17_rx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_train) -{ - int i; - - span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.17, %dbps, %s training\n", bit_rate, (short_train) ? "short" : "long"); - switch (bit_rate) - { - case 14400: - s->constellation = v17_v32bis_14400_constellation; - s->space_map = 0; - s->bits_per_symbol = 6; - break; - case 12000: - s->constellation = v17_v32bis_12000_constellation; - s->space_map = 1; - s->bits_per_symbol = 5; - break; - case 9600: - s->constellation = v17_v32bis_9600_constellation; - s->space_map = 2; - s->bits_per_symbol = 4; - break; - case 7200: - s->constellation = v17_v32bis_7200_constellation; - s->space_map = 3; - s->bits_per_symbol = 3; - break; - case 4800: - /* This does not exist in the V.17 spec as a valid mode of operation. - However, it does exist in V.32bis, so it is here for completeness. */ - s->constellation = v17_v32bis_4800_constellation; - s->space_map = 0; - s->bits_per_symbol = 2; - break; - default: - return -1; - } - /*endswitch*/ - 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])); -#else - vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); -#endif - s->training_error = FP_SCALE(0.0f); - s->rrc_filter_step = 0; - - s->diff = 1; - s->scramble_reg = 0x2ECDD5; - s->training_stage = TRAINING_STAGE_SYMBOL_ACQUISITION; - s->training_count = 0; - s->signal_present = 0; -#if defined(IAXMODEM_STUFF) - s->high_sample = 0; - s->low_samples = 0; - s->carrier_drop_pending = false; -#endif - if (short_train != 2) - s->short_train = short_train; - /*endif*/ - 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++) - s->distances[i] = FP_CONSTELLATION_SCALE(99.0f)*FP_CONSTELLATION_SCALE(1.0f); - /*endfor*/ - 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; - s->trellis_ptr = 14; - - s->carrier_phase = 0; - power_meter_init(&s->power, 4); - - if (s->short_train) - { - s->carrier_phase_rate = s->carrier_phase_rate_save; - equalizer_restore(s); - s->agc_scaling = s->agc_scaling_save; - /* Don't allow any frequency correction at all, until we start to pull the phase in. */ -#if defined(SPANDSP_USE_FIXED_POINTx) - s->carrier_track_i = 0; - s->carrier_track_p = 40000; -#else - s->carrier_track_i = 0.0f; - s->carrier_track_p = 40000.0f; -#endif - } - else - { - 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 = (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 - } - /*endif*/ - s->last_sample = 0; - span_log(&s->logging, SPAN_LOG_FLOW, "Gains %f %f\n", (float) s->agc_scaling_save, (float) s->agc_scaling); - 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 */ - for (i = 0; i < 2; i++) - { - 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); - } - /*endfor*/ - s->baud_phase = FP_SCALE(0.0f); - s->baud_half = 0; - - s->total_baud_timing_correction = 0; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data) -{ - switch (bit_rate) - { - case 14400: - case 12000: - case 9600: - case 7200: - case 4800: - /* 4800 is an extension of V.17, to provide full coverage of the V.32bis modes */ - break; - default: - return NULL; - } - /*endswitch*/ - if (s == NULL) - { - if ((s = (v17_rx_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - 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->scrambler_tap = 18 - 1; - v17_rx_signal_cutoff(s, -45.5f); - s->carrier_phase_rate_save = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ); - v17_rx_restart(s, bit_rate, s->short_train); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_rx_release(v17_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_rx_free(v17_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_rx_set_qam_report_handler(v17_rx_state_t *s, qam_report_handler_t handler, void *user_data) -{ - s->qam_report = handler; - s->qam_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17tx.c b/libs/spandsp/src/v17tx.c deleted file mode 100644 index a57bc9f705..0000000000 --- a/libs/spandsp/src/v17tx.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v17tx.c - ITU V.17 modem transmit part - * - * 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(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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/dds.h" -#include "spandsp/power_meter.h" - -#if defined(SPANDSP_USE_FIXED_POINT) -#define SPANDSP_USE_FIXED_POINTx -#endif - -#include "spandsp/v17tx.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/v17tx.h" - -#if defined(SPANDSP_USE_FIXED_POINT) -#define FP_SCALE(x) ((int16_t) x) -#else -#define FP_SCALE(x) (x) -#endif - -#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x) - -#include "v17_v32bis_tx_constellation_maps.h" -#include "v17_v32bis_tx_rrc.h" - -/*! The nominal frequency of the carrier, in Hertz */ -#define CARRIER_NOMINAL_FREQ 1800.0f - -/* Segments of the training sequence */ -/*! The start of the optional TEP, that may preceed the actual training, in symbols */ -#define V17_TRAINING_SEG_TEP_A 0 -/*! The mid point of the optional TEP, that may preceed the actual training, in symbols */ -#define V17_TRAINING_SEG_TEP_B (V17_TRAINING_SEG_TEP_A + 480) -/*! The start of training segment 1, in symbols */ -#define V17_TRAINING_SEG_1 (V17_TRAINING_SEG_TEP_B + 48) -/*! The start of training segment 2, in symbols */ -#define V17_TRAINING_SEG_2 (V17_TRAINING_SEG_1 + 256) -/*! The start of training segment 3, in symbols */ -#define V17_TRAINING_SEG_3 (V17_TRAINING_SEG_2 + 2976) -/*! The start of training segment 4, in symbols */ -#define V17_TRAINING_SEG_4 (V17_TRAINING_SEG_3 + 64) -/*! The start of training segment 4 in short training mode, in symbols */ -#define V17_TRAINING_SHORT_SEG_4 (V17_TRAINING_SEG_2 + 38) -/*! The end of the training, in symbols */ -#define V17_TRAINING_END (V17_TRAINING_SEG_4 + 48) -#define V17_TRAINING_SHUTDOWN_A (V17_TRAINING_END + 32) -/*! The end of the shutdown sequence, in symbols */ -#define V17_TRAINING_SHUTDOWN_END (V17_TRAINING_SHUTDOWN_A + 48) - -/*! The 16 bit pattern used in the bridge section of the training sequence */ -#define V17_BRIDGE_WORD 0x8880 - -static __inline__ int scramble(v17_tx_state_t *s, int in_bit) -{ - int out_bit; - - /* One of the scrambler taps is a variable, so it can be adjusted for caller or answerer operation - when used for V.32bis. */ - out_bit = (in_bit ^ (s->scramble_reg >> s->scrambler_tap) ^ (s->scramble_reg >> (23 - 1))) & 1; - s->scramble_reg = (s->scramble_reg << 1) | out_bit; - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ complexi16_t training_get(v17_tx_state_t *s) -#else -static __inline__ complexf_t training_get(v17_tx_state_t *s) -#endif -{ - static const int cdba_to_abcd[4] = - { - 2, 3, 1, 0 - }; - static const int dibit_to_step[4] = - { - 1, 0, 2, 3 - }; -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t zero = {0, 0}; -#else - static const complexf_t zero = {0.0f, 0.0f}; -#endif - int bits; - int shift; - - if (++s->training_step <= V17_TRAINING_SEG_3) - { - if (s->training_step <= V17_TRAINING_SEG_2) - { - if (s->training_step <= V17_TRAINING_SEG_TEP_B) - { - /* Optional segment: Unmodulated carrier (talker echo protection) */ - return v17_v32bis_abcd_constellation[0]; - } - if (s->training_step <= V17_TRAINING_SEG_1) - { - /* Optional segment: silence (talker echo protection) */ - return zero; - } - /* Segment 1: ABAB... */ - return v17_v32bis_abcd_constellation[(s->training_step & 1) ^ 1]; - } - /* Segment 2: CDBA... */ - /* Apply the scrambler */ - bits = scramble(s, 1); - bits = (bits << 1) | scramble(s, 1); - s->constellation_state = cdba_to_abcd[bits]; - if (s->short_train && s->training_step == V17_TRAINING_SHORT_SEG_4) - { - /* Go straight to the ones test. */ - s->training_step = V17_TRAINING_SEG_4; - } - return v17_v32bis_abcd_constellation[s->constellation_state]; - } - /* Segment 3: Bridge... */ - shift = ((s->training_step - V17_TRAINING_SEG_3 - 1) & 0x7) << 1; - //span_log(&s->logging, SPAN_LOG_FLOW, "Seg 3 shift %d\n", shift); - bits = scramble(s, V17_BRIDGE_WORD >> shift); - bits = (bits << 1) | scramble(s, V17_BRIDGE_WORD >> (shift + 1)); - s->constellation_state = (s->constellation_state + dibit_to_step[bits]) & 3; - return v17_v32bis_abcd_constellation[s->constellation_state]; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int diff_and_convolutional_encode(v17_tx_state_t *s, int q) -{ - static const uint8_t v32bis_4800_differential_encoder[4][4] = - { - {2, 3, 0, 1}, - {0, 2, 1, 3}, - {3, 1, 2, 0}, - {1, 0, 3, 2} - }; - static const uint8_t v17_differential_encoder[4][4] = - { - {0, 1, 2, 3}, - {1, 2, 3, 0}, - {2, 3, 0, 1}, - {3, 0, 1, 2} - }; - static const uint8_t v17_convolutional_coder[8][4] = - { - {0, 2, 3, 1}, - {4, 7, 5, 6}, - {1, 3, 2, 0}, - {7, 4, 6, 5}, - {2, 0, 1, 3}, - {6, 5, 7, 4}, - {3, 1, 0, 2}, - {5, 6, 4, 7} - }; - - if (s->bits_per_symbol == 2) - { - /* 4800bps mode for V.32bis */ - /* There is no trellis. We just differentially encode. */ - s->diff = v32bis_4800_differential_encoder[s->diff][q & 0x03]; - return s->diff; - } - /* Differentially encode */ - s->diff = v17_differential_encoder[s->diff][q & 0x03]; - - /* Convolutionally encode the redundant bit */ - s->convolution = v17_convolutional_coder[s->convolution][s->diff]; - - /* The final result is the combination of some uncoded bits, 2 differentially - encoded bits, and the convolutionally encoded redundant bit. */ - return ((q << 1) & 0x78) | (s->diff << 1) | ((s->convolution >> 2) & 1); -} -/*- End of function --------------------------------------------------------*/ - -static int fake_get_bit(void *user_data) -{ - return 1; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ complexi16_t getbaud(v17_tx_state_t *s) -#else -static __inline__ complexf_t getbaud(v17_tx_state_t *s) -#endif -{ - int i; - int bit; - int bits; -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t zero = {0, 0}; -#else - static const complexf_t zero = {0.0f, 0.0f}; -#endif - - if (s->in_training) - { - if (s->training_step <= V17_TRAINING_END) - { - /* Send the training sequence */ - if (s->training_step < V17_TRAINING_SEG_4) - return training_get(s); - /* The last step in training is to send some 1's */ - if (++s->training_step > V17_TRAINING_END) - { - /* Training finished - commence normal operation. */ - s->current_get_bit = s->get_bit; - s->in_training = false; - } - } - else - { - if (++s->training_step > V17_TRAINING_SHUTDOWN_A) - { - /* The shutdown sequence is 32 bauds of all 1's, then 48 bauds - of silence */ - return zero; - } - if (s->training_step == V17_TRAINING_SHUTDOWN_END) - { - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE); - } - } - } - bits = 0; - for (i = 0; i < s->bits_per_symbol; i++) - { - if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA) - { - /* End of real data. Switch to the fake get_bit routine, until we - have shut down completely. */ - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); - s->current_get_bit = fake_get_bit; - s->in_training = true; - bit = 1; - } - bits |= (scramble(s, bit) << i); - } - return s->constellation[diff_and_convolutional_encode(s, bits)]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t v; - complexi32_t x; - complexi32_t z; - int16_t iamp; -#else - complexf_t v; - complexf_t x; - complexf_t z; - float famp; -#endif - int sample; - - if (s->training_step >= V17_TRAINING_SHUTDOWN_END) - { - /* Once we have sent the shutdown sequence, we stop sending completely. */ - return 0; - } - for (sample = 0; sample < len; sample++) - { - if ((s->baud_phase += 3) >= 10) - { - s->baud_phase -= 10; - v = getbaud(s); - s->rrc_filter_re[s->rrc_filter_step] = v.re; - s->rrc_filter_im[s->rrc_filter_step] = v.im; - if (++s->rrc_filter_step >= V17_TX_FILTER_STEPS) - s->rrc_filter_step = 0; - } -#if defined(SPANDSP_USE_FIXED_POINT) - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V17_TX_FILTER_STEPS, s->rrc_filter_step) >> 4; - x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V17_TX_FILTER_STEPS, s->rrc_filter_step) >> 4; - /* Now create and modulate the carrier */ - z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate); - iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) (((int32_t) iamp*s->gain) >> 11); -#else - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V17_TX_FILTER_STEPS, s->rrc_filter_step); - x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V17_TX_FILTER_STEPS, s->rrc_filter_step); - /* Now create and modulate the carrier */ - z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate); - famp = x.re*z.re - x.im*z.im; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) lfastrintf(famp*s->gain); -#endif - } - return sample; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_tx_power(v17_tx_state_t *s, float power) -{ - float gain; - - /* The constellation design seems to keep the average power the same, regardless - of which bit rate is in use. */ - gain = 0.223f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN; -#if defined(SPANDSP_USE_FIXED_POINT) - s->gain = (int16_t) gain; -#else - s->gain = gain; -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit, void *user_data) -{ - if (s->get_bit == s->current_get_bit) - s->current_get_bit = get_bit; - s->get_bit = get_bit; - s->get_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v17_tx_get_logging_state(v17_tx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, bool tep, bool short_train) -{ - switch (bit_rate) - { - case 14400: - s->bits_per_symbol = 6; - s->constellation = v17_v32bis_14400_constellation; - break; - case 12000: - s->bits_per_symbol = 5; - s->constellation = v17_v32bis_12000_constellation; - break; - case 9600: - s->bits_per_symbol = 4; - s->constellation = v17_v32bis_9600_constellation; - break; - case 7200: - s->bits_per_symbol = 3; - s->constellation = v17_v32bis_7200_constellation; - break; - case 4800: - /* This does not exist in the V.17 spec as a valid mode of operation. - However, it does exist in V.32bis, so it is here for completeness. */ - s->bits_per_symbol = 2; - s->constellation = v17_v32bis_4800_constellation; - break; - default: - return -1; - } - s->bit_rate = bit_rate; - /* NB: some modems seem to use 3 instead of 1 for long training */ - s->diff = (short_train) ? 0 : 1; -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0])); - vec_zeroi16(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0])); -#else - vec_zerof(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0])); - vec_zerof(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0])); -#endif - s->rrc_filter_step = 0; - s->convolution = 0; - s->scramble_reg = 0x2ECDD5; - 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; - s->baud_phase = 0; - s->constellation_state = 0; - s->current_get_bit = fake_get_bit; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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) - { - case 14400: - case 12000: - case 9600: - case 7200: - case 4800: - /* 4800 is an extension of V.17, to provide full converage of the V.32bis modes */ - break; - default: - return NULL; - } - if (s == NULL) - { - if ((s = (v17_tx_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, "V.17 TX"); - s->get_bit = get_bit; - s->get_bit_user_data = user_data; - 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); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_tx_release(v17_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v17_tx_free(v17_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c deleted file mode 100644 index f3d2a6d8f8..0000000000 --- a/libs/spandsp/src/v18.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v18.c - V.18 text telephony for the deaf. - * - * Written by Steve Underwood - * - * Copyright (C) 2004-2015 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 -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/queue.h" -#include "spandsp/async.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/power_meter.h" -#include "spandsp/fsk.h" -#include "spandsp/dtmf.h" -#include "spandsp/modem_connect_tones.h" -#include "spandsp/v8.h" -#include "spandsp/v18.h" - -#include "spandsp/private/logging.h" -#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" -#include "spandsp/private/v18.h" - -#include - -/* - Ways in which a V.18 call may start - ----------------------------------- - - Originate: - ANS - Silence for 0.5s then send TXP - DTMF - Proceed as Annex B - 1650Hz (V21 ch 2 low) [1650Hz +-12Hz] - Proceed as Annex F in call mode - 1300Hz (Calling tone) [1300Hz +-16Hz] - Proceed as Annex E in call mode - 1400Hz/1800Hz (Weitbrecht) [1400Hz +-5% and 1800Hz +-5%] - Detect rate and proceed as Annex A - 980Hz/1180Hz (V21 ch 1) [980Hz +-12Hz, 1180Hz +-12Hz] - Start timer Tr - 2225Hz (Bell ANS) - Proceed as Annex D call mode - 1270Hz (Bell103 ch 2 high) - Proceed as Annex D answer mode - 390Hz (V23 ch 2 low) - Proceed as Annex E answer mode - - Answer: - ANS - Monitor as caller for 980Hz or 1300Hz - CI/XCI - Respond with ANSam - 1300Hz [1300Hz +-16Hz] - Probe - Timer Ta (3s) - Probe - 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 +-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 +-12Hz] - Proceed as Annex F answer mode - ANSam - Proceed as V.8 caller Annex G -*/ - -/*! The baudot code to shift from alpha to digits and symbols */ -#define BAUDOT_FIGURE_SHIFT 0x1B -/*! The baudot code to shift from digits and symbols to alpha */ -#define BAUDOT_LETTER_SHIFT 0x1F - -struct dtmf_to_ascii_s -{ - const char *dtmf; - char ascii; -}; - -static const struct dtmf_to_ascii_s dtmf_to_ascii[] = -{ - {"###0", '!'}, - {"###1", 'C'}, - {"###2", 'F'}, - {"###3", 'I'}, - {"###4", 'L'}, - {"###5", 'O'}, - {"###6", 'R'}, - {"###7", 'U'}, - {"###8", 'X'}, - {"###9", ';'}, - {"##*1", 'A'}, - {"##*2", 'D'}, - {"##*3", 'G'}, - {"##*4", 'J'}, - {"##*5", 'M'}, - {"##*6", 'P'}, - {"##*7", 'S'}, - {"##*8", 'V'}, - {"##*9", 'Y'}, - {"##1", 'B'}, - {"##2", 'E'}, - {"##3", 'H'}, - {"##4", 'K'}, - {"##5", 'N'}, - {"##6", 'Q'}, - {"##7", 'T'}, - {"##8", 'W'}, - {"##9", 'Z'}, - {"##0", ' '}, -#if defined(WIN32) || (defined(__SVR4) && defined (__sun)) - {"#*1", 'X'}, // (Note 1) 111 1011 - {"#*2", 'X'}, // (Note 1) 111 1100 - {"#*3", 'X'}, // (Note 1) 111 1101 - {"#*4", 'X'}, // (Note 1) 101 1011 - {"#*5", 'X'}, // (Note 1) 101 1100 - {"#*6", 'X'}, // (Note 1) 101 1101 -#else - {"#*1", 0xE6}, // (Note 1) 111 1011 - {"#*2", 0xF8}, // (Note 1) 111 1100 - {"#*3", 0xE5}, // (Note 1) 111 1101 - {"#*4", 0xC6}, // (Note 1) 101 1011 - {"#*5", 0xD8}, // (Note 1) 101 1100 - {"#*6", 0xC5}, // (Note 1) 101 1101 -#endif - {"#0", '?'}, - {"#1", 'c'}, - {"#2", 'f'}, - {"#3", 'i'}, - {"#4", 'l'}, - {"#5", 'o'}, - {"#6", 'r'}, - {"#7", 'u'}, - {"#8", 'x'}, - {"#9", '.'}, - {"*#0", '0'}, - {"*#1", '1'}, - {"*#2", '2'}, - {"*#3", '3'}, - {"*#4", '4'}, - {"*#5", '5'}, - {"*#6", '6'}, - {"*#7", '7'}, - {"*#8", '8'}, - {"*#9", '9'}, - {"**1", '+'}, - {"**2", '-'}, - {"**3", '='}, - {"**4", ':'}, - {"**5", '%'}, - {"**6", '('}, - {"**7", ')'}, - {"**8", ','}, - {"**9", '\n'}, - {"*0", '\b'}, - {"*1", 'a'}, - {"*2", 'd'}, - {"*3", 'g'}, - {"*4", 'j'}, - {"*5", 'm'}, - {"*6", 'p'}, - {"*7", 's'}, - {"*8", 'v'}, - {"*9", 'y'}, - {"0", ' '}, - {"1", 'b'}, - {"2", 'e'}, - {"3", 'h'}, - {"4", 'k'}, - {"5", 'n'}, - {"6", 'q'}, - {"7", 't'}, - {"8", 'w'}, - {"9", 'z'}, - {"", '\0'} -}; - -static const char *ascii_to_dtmf[128] = -{ - "", /* NULL */ - "", /* SOH */ - "", /* STX */ - "", /* ETX */ - "", /* EOT */ - "", /* ENQ */ - "", /* ACK */ - "", /* BEL */ - "*0", /* BACK SPACE */ - "0", /* HT >> SPACE */ - "**9", /* LF */ - "**9", /* VT >> LF */ - "**9", /* FF >> LF */ - "", /* CR */ - "", /* SO */ - "", /* SI */ - "", /* DLE */ - "", /* DC1 */ - "", /* DC2 */ - "", /* DC3 */ - "", /* DC4 */ - "", /* NAK */ - "", /* SYN */ - "", /* ETB */ - "", /* CAN */ - "", /* EM */ - "#0", /* SUB >> ? */ - "", /* ESC */ - "**9", /* IS4 >> LF */ - "**9", /* IS3 >> LF */ - "**9", /* IS2 >> LF */ - "0", /* IS1 >> SPACE */ - "0", /* SPACE */ - "###0", /* ! */ - "", /* " */ - "", /* # */ - "", /* $ */ - "**5", /* % */ - "**1", /* & >> + */ - "", /* 0x92 */ - "**6", /* ( */ - "**7", /* ) */ - "#9", /* _ >> . */ - "**1", /* + */ - "**8", /* , */ - "**2", /* - */ - "#9", /* . */ - "", /* / */ - "*#0", /* 0 */ - "*#1", /* 1 */ - "*#2", /* 2 */ - "*#3", /* 3 */ - "*#4", /* 4 */ - "*#5", /* 5 */ - "*#6", /* 6 */ - "*#7", /* 7 */ - "*#8", /* 8 */ - "*#9", /* 9 */ - "**4", /* : */ - "###9", /* ; */ - "**6", /* < >> ( */ - "**3", /* = */ - "**7", /* > >> ) */ - "#0", /* ? */ - "###8", /* @ >> X */ - "##*1", /* A */ - "##1", /* B */ - "###1", /* C */ - "##*2", /* D */ - "##2", /* E */ - "###2", /* F */ - "##*3", /* G */ - "##3", /* H */ - "###3", /* I */ - "##*4", /* J */ - "##4", /* K */ - "###4", /* L */ - "##*5", /* M */ - "##5", /* N */ - "###5", /* O */ - "##*6", /* P */ - "##6", /* Q */ - "###6", /* R */ - "##*7", /* S */ - "##7", /* T */ - "###7", /* U */ - "##*8", /* V */ - "##8", /* W */ - "###8", /* X */ - "##*9", /* Y */ - "##9", /* Z */ - "#*4", /* 0xC6 (National code) */ - "#*5", /* 0xD8 (National code) */ - "#*6", /* 0xC5 (National code) */ - "", /* ^ */ - "0", /* _ >> SPACE */ - "", /* 0x92 */ - "*1", /* a */ - "1", /* b */ - "#1", /* c */ - "*2", /* d */ - "2", /* e */ - "#2", /* f */ - "*3", /* g */ - "3", /* h */ - "#3", /* i */ - "*4", /* j */ - "4", /* k */ - "#4", /* l */ - "*5", /* m */ - "5", /* n */ - "#5", /* o */ - "*6", /* p */ - "6", /* q */ - "#6", /* r */ - "*7", /* s */ - "7", /* t */ - "#7", /* u */ - "*8", /* v */ - "8", /* w */ - "#8", /* x */ - "*9", /* y */ - "9", /* z */ - "#*1", /* 0xE6 (National code) */ - "#*2", /* 0xF8 (National code) */ - "#*3", /* 0xE5 (National code) */ - "0", /* ~ >> SPACE */ - "*0" /* DEL >> BACK SPACE */ -}; - -#if 0 -static const uint8_t txp[] = "1111111111000101011100001101110000010101"; - -/* XCI is: - 400 ms mark; - XCI marker; - 800 ms mark; - XCI marker; - 800 ms mark; - XCI marker; - 800 ms mark; - XCI marker; - 100 ms mark. */ -static const uint8_t xci[] = "01111111110111111111"; - -/* The entries here must match the order in which the related names are defined in v18.h */ -static const int automoding_sequences[][6] = -{ - { - /* Dummy entry 0 */ - V18_MODE_5BIT_4545, - V18_MODE_BELL103, - V18_MODE_V21TEXTPHONE, - V18_MODE_V23VIDEOTEX, - V18_MODE_EDT, - V18_MODE_DTMF - }, - { - /* 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 - } -}; -#endif - -static uint16_t encode_baudot(v18_state_t *s, uint8_t ch) -{ - static const uint8_t conv[128] = - { - 0xFF, /* NUL */ - 0xFF, /* SOH */ - 0xFF, /* STX */ - 0xFF, /* ETX */ - 0xFF, /* EOT */ - 0xFF, /* ENQ */ - 0xFF, /* ACK */ - 0xFF, /* BEL */ - 0x40, /* BS */ - 0x44, /* HT >> SPACE */ - 0x42, /* LF */ - 0x42, /* VT >> LF */ - 0x42, /* FF >> LF */ - 0x48, /* CR */ - 0xFF, /* SO */ - 0xFF, /* SI */ - 0xFF, /* DLE */ - 0xFF, /* DC1 */ - 0xFF, /* DC2 */ - 0xFF, /* DC3 */ - 0xFF, /* DC4 */ - 0xFF, /* NAK */ - 0xFF, /* SYN */ - 0xFF, /* ETB */ - 0xFF, /* CAN */ - 0xFF, /* EM */ - 0x99, /* SUB >> ? */ - 0xFF, /* ESC */ - 0x42, /* IS4 >> LF */ - 0x42, /* IS3 >> LF */ - 0x42, /* IS2 >> LF */ - 0x44, /* IS1 >> SPACE */ - 0x44, /* */ - 0x8D, /* ! */ - 0x91, /* " */ - 0x89, /* # >> $ */ - 0x89, /* $ */ - 0x9D, /* % >> / */ - 0x9A, /* & >> + */ - 0x8B, /* ' */ - 0x8F, /* ( */ - 0x92, /* ) */ - 0x9C, /* * >> . */ - 0x9A, /* + */ - 0x8C, /* , */ - 0x83, /* - */ - 0x9C, /* . */ - 0x9D, /* / */ - 0x96, /* 0 */ - 0x97, /* 1 */ - 0x93, /* 2 */ - 0x81, /* 3 */ - 0x8A, /* 4 */ - 0x90, /* 5 */ - 0x95, /* 6 */ - 0x87, /* 7 */ - 0x86, /* 8 */ - 0x98, /* 9 */ - 0x8E, /* : */ - 0x9E, /* ; */ - 0x8F, /* < >> )*/ - 0x94, /* = */ - 0x92, /* > >> ( */ - 0x99, /* ? */ - 0x1D, /* @ >> X */ - 0x03, /* A */ - 0x19, /* B */ - 0x0E, /* C */ - 0x09, /* D */ - 0x01, /* E */ - 0x0D, /* F */ - 0x1A, /* G */ - 0x14, /* H */ - 0x06, /* I */ - 0x0B, /* J */ - 0x0F, /* K */ - 0x12, /* L */ - 0x1C, /* M */ - 0x0C, /* N */ - 0x18, /* O */ - 0x16, /* P */ - 0x17, /* Q */ - 0x0A, /* R */ - 0x05, /* S */ - 0x10, /* T */ - 0x07, /* U */ - 0x1E, /* V */ - 0x13, /* W */ - 0x1D, /* X */ - 0x15, /* Y */ - 0x11, /* Z */ - 0x8F, /* [ >> (*/ - 0x9D, /* \ >> / */ - 0x92, /* ] >> ) */ - 0x8B, /* ^ >> ' */ - 0x44, /* _ >> Space */ - 0x8B, /* ` >> ' */ - 0x03, /* a */ - 0x19, /* b */ - 0x0E, /* c */ - 0x09, /* d */ - 0x01, /* e */ - 0x0D, /* f */ - 0x1A, /* g */ - 0x14, /* h */ - 0x06, /* i */ - 0x0B, /* j */ - 0x0F, /* k */ - 0x12, /* l */ - 0x1C, /* m */ - 0x0C, /* n */ - 0x18, /* o */ - 0x16, /* p */ - 0x17, /* q */ - 0x0A, /* r */ - 0x05, /* s */ - 0x10, /* t */ - 0x07, /* u */ - 0x1E, /* v */ - 0x13, /* w */ - 0x1D, /* x */ - 0x15, /* y */ - 0x11, /* z */ - 0x8F, /* { >> ( */ - 0x8D, /* | >> ! */ - 0x92, /* } >> ) */ - 0x44, /* ~ >> Space */ - 0xFF, /* DEL */ - }; - uint16_t shift; - - ch = conv[ch & 0x7F]; - /* Is it a non-existant code? */ - if (ch == 0xFF) - return 0; - /* Is it a code present in both character sets? */ - if ((ch & 0x40)) - return 0x8000 | (ch & 0x1F); - /* Need to allow for a possible character set change. */ - if ((ch & 0x80)) - { - if (!s->repeat_shifts && s->baudot_tx_shift == 1) - return ch & 0x1F; - s->baudot_tx_shift = 1; - shift = BAUDOT_FIGURE_SHIFT; - } - else - { - if (!s->repeat_shifts && s->baudot_tx_shift == 0) - return ch & 0x1F; - s->baudot_tx_shift = 0; - shift = BAUDOT_LETTER_SHIFT; - } - return 0x8000 | (shift << 5) | (ch & 0x1F); -} -/*- End of function --------------------------------------------------------*/ - -static uint8_t decode_baudot(v18_state_t *s, uint8_t ch) -{ - static const uint8_t conv[2][32] = - { - {"\bE\nA SIU\rDRJNFCKTZLWHYPQOBG^MXV^"}, - {"\b3\n- -87\r$4',!:(5\")2=6019?+^./;^"} - }; - - switch (ch) - { - case BAUDOT_FIGURE_SHIFT: - s->baudot_rx_shift = 1; - break; - case BAUDOT_LETTER_SHIFT: - s->baudot_rx_shift = 0; - break; - default: - return conv[s->baudot_rx_shift][ch]; - } - /* Return 0xFF if we did not produce a character */ - return 0xFF; -} -/*- End of function --------------------------------------------------------*/ - -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) - { - 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; - } -} -/*- 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 --------------------------------------------------------*/ - -static void v18_tdd_put_async_byte(void *user_data, int byte) -{ - v18_state_t *s; - uint8_t octet; - - s = (v18_state_t *) user_data; - if (byte < 0) - { - /* Special conditions */ - span_log(&s->logging, SPAN_LOG_FLOW, "V.18 signal status is %s (%d)\n", signal_status_to_str(byte), byte); - switch (byte) - { - case SIG_STATUS_CARRIER_UP: - s->consecutive_ones = 0; - s->bit_pos = 0; - s->in_progress = 0; - s->rx_msg_len = 0; - break; - case SIG_STATUS_CARRIER_DOWN: - if (s->rx_msg_len > 0) - { - /* Whatever we have to date constitutes the message */ - s->rx_msg[s->rx_msg_len] = '\0'; - if (s->put_msg) - s->put_msg(s->user_data, s->rx_msg, s->rx_msg_len); - s->rx_msg_len = 0; - } - break; - default: - span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special put byte value - %d!\n", byte); - break; - } - return; - } - if (s->rx_suppression > 0) - return; - span_log(&s->logging, SPAN_LOG_FLOW, "Rx byte %x\n", byte); - if ((octet = decode_baudot(s, byte)) != 0xFF) - { - s->rx_msg[s->rx_msg_len++] = octet; - 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) - s->put_msg(s->user_data, s->rx_msg, s->rx_msg_len); - s->rx_msg_len = 0; - } -} -/*- 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); - *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 --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len) -{ - int len; - int lenx; - - len = tone_gen(&s->alert_tone_gen, amp, max_len); - if (s->tx_signal_on) - { - switch (s->mode) - { - case V18_MODE_DTMF: - if (len < max_len) - len += dtmf_tx(&s->dtmf_tx, amp, max_len - len); - break; - default: - if (len < max_len) - { - if ((lenx = fsk_tx(&s->fsk_tx, amp + len, max_len - len)) <= 0) - s->tx_signal_on = 0; - len += lenx; - } - break; - } - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_rx(v18_state_t *s, const int16_t amp[], 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(&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(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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len) -{ - int i; - - /* This returns the number of characters that would not fit in the buffer. - The buffer will only be loaded if the whole string of digits will fit, - in which case zero is returned. */ - if (len < 0) - { - if ((len = strlen(msg)) == 0) - return 0; - } - /* 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 & 0xFFF)) - { - case V18_MODE_NONE: - return "None"; - 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: - return "DTMF"; - case V18_MODE_EDT: - return "EDT"; - case V18_MODE_BELL103: - return "Bell 103"; - case V18_MODE_V23VIDEOTEX: - return "Videotex"; - case V18_MODE_V21TEXTPHONE: - return "V.21"; - case V18_MODE_V18TEXTPHONE: - return "V.18 text telephone"; - } - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, - 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 *) span_alloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - s->calling_party = calling_party; - 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_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->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->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: - 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->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->next_byte = (uint8_t) 0xFF; - break; - case V18_MODE_DTMF: - 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->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->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->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->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->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; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_release(v18_state_t *s) -{ - queue_release(&s->queue.queue); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_free(v18_state_t *s) -{ - queue_release(&s->queue.queue); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v22bis_rx.c b/libs/spandsp/src/v22bis_rx.c deleted file mode 100644 index cfb4e1378a..0000000000 --- a/libs/spandsp/src/v22bis_rx.c +++ /dev/null @@ -1,1002 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v22bis_rx.c - ITU V.22bis modem receive part - * - * 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 */ - -/* THIS IS A WORK IN PROGRESS - It is basically functional, but it is not feature - complete, and doesn't reliably sync over the signal and noise level ranges it - should. There are some nasty inefficiencies too! - TODO: - Better noise performance - Retrain is incomplete - Rate change is not implemented - Remote loopback is not implemented */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/logging.h" -#include "spandsp/fast_convert.h" -#include "spandsp/math_fixed.h" -#include "spandsp/saturated.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/power_meter.h" -#include "spandsp/arctan2.h" -#include "spandsp/dds.h" -#include "spandsp/complex_filters.h" - -#include "spandsp/v29rx.h" -#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) -#define FP_SCALE(x) FP_Q6_10(x) -#define FP_SHIFT_FACTOR 10 -#else -#define FP_SCALE(x) (x) -#endif - -#include "v22bis_rx_1200_rrc.h" -#include "v22bis_rx_2400_rrc.h" - -#define ms_to_symbols(t) (((t)*600)/1000) - -/*! The adaption rate coefficient for the equalizer */ -#define EQUALIZER_DELTA 0.25f -/*! The number of phase shifted coefficient set for the pulse shaping/bandpass filter */ -#define PULSESHAPER_COEFF_SETS 12 - -/* -The basic method used by the V.22bis receiver is: - - Put each sample into the pulse-shaping and phase shift filter buffer - - At T/2 rate: - Filter and demodulate the contents of the input filter buffer, producing a sample - in the equalizer filter buffer. - - Tune the symbol timing based on the latest 3 samples in the equalizer buffer. This - updates the decision points for taking the T/2 samples. - - Equalize the contents of the equalizer buffer, producing a demodulated constellation - point. - - Find the nearest constellation point to the received position. This is our received - symbol. - - Tune the local carrier, based on the angular mismatch between the actual signal and - the decision. - - Tune the equalizer, based on the mismatch between the actual signal and the decision. - - Descramble and output the bits represented by the decision. -*/ - -static const uint8_t space_map_v22bis[6][6] = -{ - {11, 9, 9, 6, 6, 7}, - {10, 8, 8, 4, 4, 5}, - {10, 8, 8, 4, 4, 5}, - {13, 12, 12, 0, 0, 2}, - {13, 12, 12, 0, 0, 2}, - {15, 14, 14, 1, 1, 3} -}; - -static const uint8_t phase_steps[4] = -{ - 1, 0, 2, 3 -}; - -SPAN_DECLARE(float) v22bis_rx_carrier_frequency(v22bis_state_t *s) -{ - return dds_frequencyf(s->rx.carrier_phase_rate); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v22bis_rx_symbol_timing_correction(v22bis_state_t *s) -{ - return (float) s->rx.total_baud_timing_correction/((float) PULSESHAPER_COEFF_SETS*40.0f/(3.0f*2.0f)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v22bis_rx_signal_power(v22bis_state_t *s) -{ - return power_meter_current_dbm0(&s->rx.rx_power) + 6.34f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v22bis_rx_signal_cutoff(v22bis_state_t *s, float cutoff) -{ - s->rx.carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.232f); - s->rx.carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.232f); -} -/*- End of function --------------------------------------------------------*/ - -void v22bis_report_status_change(v22bis_state_t *s, int status) -{ - if (s->status_handler) - s->status_handler(s->status_user_data, status); - else if (s->put_bit) - s->put_bit(s->put_bit_user_data, status); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexi16_t **coeffs) -#else -SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexf_t **coeffs) -#endif -{ - *coeffs = s->rx.eq_coeff; - return V22BIS_EQUALIZER_LEN; -} -/*- End of function --------------------------------------------------------*/ - -void v22bis_equalizer_coefficient_reset(v22bis_state_t *s) -{ - /* Start with an equalizer based on everything being perfect */ -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t x = {FP_Q6_10(3.0f), FP_Q6_10(0.0f)}; - - cvec_zeroi16(s->rx.eq_coeff, V22BIS_EQUALIZER_LEN); - s->rx.eq_coeff[V22BIS_EQUALIZER_PRE_LEN] = x; - s->rx.eq_delta = 32.0f*EQUALIZER_DELTA/V22BIS_EQUALIZER_LEN; -#else - static const complexf_t x = {3.0f, 0.0f}; - - cvec_zerof(s->rx.eq_coeff, V22BIS_EQUALIZER_LEN); - s->rx.eq_coeff[V22BIS_EQUALIZER_PRE_LEN] = x; - s->rx.eq_delta = EQUALIZER_DELTA/V22BIS_EQUALIZER_LEN; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_reset(v22bis_state_t *s) -{ - v22bis_equalizer_coefficient_reset(s); -#if defined(SPANDSP_USE_FIXED_POINT) - cvec_zeroi16(s->rx.eq_buf, V22BIS_EQUALIZER_LEN); -#else - cvec_zerof(s->rx.eq_buf, V22BIS_EQUALIZER_LEN); -#endif - s->rx.eq_put_step = 20 - 1; - s->rx.eq_step = 0; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ complexi16_t equalizer_get(v22bis_state_t *s) -{ - complexi32_t zz; - complexi16_t z; - - /* Get the next equalized value. */ - zz = cvec_circular_dot_prodi16(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step); - z.re = zz.re >> FP_SHIFT_FACTOR; - z.im = zz.im >> FP_SHIFT_FACTOR; - return z; -} -#else -static __inline__ complexf_t equalizer_get(v22bis_state_t *s) -{ - /* Get the next equalized value. */ - return cvec_circular_dot_prodf(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void tune_equalizer(v22bis_state_t *s, const complexi16_t *z, const complexi16_t *target) -{ - complexi16_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subi16(target, z); - err.re = ((int32_t) err.re*s->rx.eq_delta) >> 5; - err.im = ((int32_t) err.im*s->rx.eq_delta) >> 5; - //cvec_circular_lmsi16(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step, &err); -} -#else -static void tune_equalizer(v22bis_state_t *s, const complexf_t *z, const complexf_t *target) -{ - complexf_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subf(target, z); - err.re *= s->rx.eq_delta; - err.im *= s->rx.eq_delta; - cvec_circular_lmsf(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step, &err); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ void track_carrier(v22bis_state_t *s, const complexi16_t *z, const complexi16_t *target) -#else -static __inline__ void track_carrier(v22bis_state_t *s, const complexf_t *z, const complexf_t *target) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t error; -#else - float error; -#endif - - /* For small errors the imaginary part of the difference between the actual and the target - positions is proportional to the phase error, for any particular target. However, the - different amplitudes of the various target positions scale things. */ -#if defined(SPANDSP_USE_FIXED_POINT) - error = ((int32_t) z->im*target->re - (int32_t) z->re*target->im) >> FP_SHIFT_FACTOR; - s->rx.carrier_phase_rate += (s->rx.carrier_track_i*error); - s->rx.carrier_phase += (s->rx.carrier_track_p*error); - //span_log(&s->logging, - // SPAN_LOG_FLOW, - // "CARR: Im = %15.5f f = %15.5f - %10d %10d\n", - // error/1024.0f, - // dds_frequency(s->rx.carrier_phase_rate), - // (s->rx.carrier_track_i*error), - // (s->rx.carrier_track_p*error)); -#else - error = z->im*target->re - z->re*target->im; - s->rx.carrier_phase_rate += (int32_t) (s->rx.carrier_track_i*error); - s->rx.carrier_phase += (int32_t) (s->rx.carrier_track_p*error); - //span_log(&s->logging, - // SPAN_LOG_FLOW, - // "CARR: Im = %15.5f f = %15.5f - %10d %10d\n", - // error, - // dds_frequencyf(s->rx.carrier_phase_rate), - // (int32_t) (s->rx.carrier_track_i*error), - // (int32_t) (s->rx.carrier_track_p*error)); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int descramble(v22bis_state_t *s, int bit) -{ - int out_bit; - - /* Descramble the bit */ - bit &= 1; - out_bit = (bit ^ (s->rx.scramble_reg >> 13) ^ (s->rx.scramble_reg >> 16)) & 1; - s->rx.scramble_reg = (s->rx.scramble_reg << 1) | bit; - - if (s->rx.scrambler_pattern_count >= 64) - { - out_bit ^= 1; - s->rx.scrambler_pattern_count = 0; - } - if (bit) - s->rx.scrambler_pattern_count++; - else - s->rx.scrambler_pattern_count = 0; - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void put_bit(v22bis_state_t *s, int bit) -{ - int out_bit; - - /* Descramble the bit */ - out_bit = descramble(s, bit); - s->put_bit(s->put_bit_user_data, out_bit); -} -/*- End of function --------------------------------------------------------*/ - -static void decode_baud(v22bis_state_t *s, int nearest) -{ - int raw_bits; - - raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3]; - s->rx.constellation_state = nearest; - /* The first two bits are the quadrant */ - put_bit(s, raw_bits >> 1); - put_bit(s, raw_bits); - if (s->rx.sixteen_way_decisions) - { - /* The other two bits are the position within the quadrant */ - put_bit(s, nearest >> 1); - put_bit(s, nearest); - } -} -/*- End of function --------------------------------------------------------*/ - -static int decode_baudx(v22bis_state_t *s, int nearest) -{ - int raw_bits; - int out_bits; - - raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3]; - s->rx.constellation_state = nearest; - /* The first two bits are the quadrant */ - out_bits = descramble(s, raw_bits >> 1); - out_bits = (out_bits << 1) | descramble(s, raw_bits); - if (s->rx.sixteen_way_decisions) - { - /* The other two bits are the position within the quadrant */ - out_bits = (out_bits << 1) | descramble(s, nearest >> 1); - out_bits = (out_bits << 1) | descramble(s, nearest); - } - return out_bits; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void symbol_sync(v22bis_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t p; - int32_t q; - complexi16_t a; - complexi16_t b; - complexi16_t c; - static const complexi16_t x = {FP_Q1_15(0.894427f), FP_Q1_15(0.44721f)}; -#else - float p; - float q; - complexf_t a; - complexf_t b; - complexf_t c; - static const complexf_t x = {0.894427f, 0.44721f}; -#endif - int aa[3]; - int i; - int j; - - /* This routine adapts the position of the half baud samples entering the equalizer. */ - - /* Perform a Gardner test for baud alignment on the three most recent samples. */ - for (i = 0, j = s->rx.eq_step; i < 3; i++) - { - if (--j < 0) - j = V22BIS_EQUALIZER_LEN - 1; - aa[i] = j; - } - if (s->rx.sixteen_way_decisions) - { - p = s->rx.eq_buf[aa[2]].re - s->rx.eq_buf[aa[0]].re; - p *= s->rx.eq_buf[aa[1]].re; - - q = s->rx.eq_buf[aa[2]].im - s->rx.eq_buf[aa[0]].im; - q *= s->rx.eq_buf[aa[1]].im; - } - else - { - /* Rotate the points to the 45 degree positions, to maximise the effectiveness of - the Gardner algorithm. This is particularly significant at the start of operation - to pull things in quickly. */ -#if defined(SPANDSP_USE_FIXED_POINT) - a = complex_mul_q1_15(&s->rx.eq_buf[aa[2]], &x); - b = complex_mul_q1_15(&s->rx.eq_buf[aa[1]], &x); - c = complex_mul_q1_15(&s->rx.eq_buf[aa[0]], &x); -#else - a = complex_mulf(&s->rx.eq_buf[aa[2]], &x); - b = complex_mulf(&s->rx.eq_buf[aa[1]], &x); - c = complex_mulf(&s->rx.eq_buf[aa[0]], &x); -#endif - p = (a.re - c.re)*b.re; - q = (a.im - c.im)*b.im; - } - - s->rx.gardner_integrate += (p + q > 0) ? s->rx.gardner_step : -s->rx.gardner_step; - - if (abs(s->rx.gardner_integrate) >= 16) - { - /* This integrate and dump approach avoids rapid changes of the equalizer put step. - Rapid changes, without hysteresis, are bad. They degrade the equalizer performance - when the true symbol boundary is close to a sample boundary. */ - s->rx.eq_put_step += (s->rx.gardner_integrate/16); - s->rx.total_baud_timing_correction += (s->rx.gardner_integrate/16); - //span_log(&s->logging, SPAN_LOG_FLOW, "Gardner kick %d [total %d]\n", s->rx.gardner_integrate, s->rx.total_baud_timing_correction); - if (s->rx.qam_report) - s->rx.qam_report(s->rx.qam_user_data, NULL, NULL, s->rx.gardner_integrate); - s->rx.gardner_integrate = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ void process_half_baud(v22bis_state_t *s, const complexi16_t *sample) -#else -static __inline__ void process_half_baud(v22bis_state_t *s, const complexf_t *sample) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t z; - complexi16_t zz; - const complexi16_t *target; - static const complexi16_t x = {FP_Q1_15(0.894427f), FP_Q1_15(0.44721f)}; -#else - complexf_t z; - complexf_t zz; - const complexf_t *target; - static const complexf_t x = {0.894427f, 0.44721f}; -#endif - int re; - int im; - int nearest; - int bitstream; - int raw_bits; - - z.re = sample->re; - z.im = sample->im; - - /* Add a sample to the equalizer's circular buffer, but don't calculate anything - at this time. */ - s->rx.eq_buf[s->rx.eq_step] = z; - if (++s->rx.eq_step >= V22BIS_EQUALIZER_LEN) - s->rx.eq_step = 0; - - /* On alternate insertions we have a whole baud and must process it. */ - if ((s->rx.baud_phase ^= 1)) - return; - - symbol_sync(s); - - z = equalizer_get(s); - - /* Find the constellation point */ - if (s->rx.sixteen_way_decisions) - { -#if defined(SPANDSP_USE_FIXED_POINT) - re = (z.re + FP_Q6_10(3.0f)) >> FP_SHIFT_FACTOR; - im = (z.im + FP_Q6_10(3.0f)) >> FP_SHIFT_FACTOR; -#else - re = (int) (z.re + 3.0f); - im = (int) (z.im + 3.0f); -#endif - if (re > 5) - re = 5; - else if (re < 0) - re = 0; - if (im > 5) - im = 5; - else if (im < 0) - im = 0; - nearest = space_map_v22bis[re][im]; - } - else - { - /* Rotate to 45 degrees, to make the slicing trivial. */ -#if defined(SPANDSP_USE_FIXED_POINT) - zz = complex_mul_q1_15(&z, &x); -#else - zz = complex_mulf(&z, &x); -#endif - nearest = 0x01; - if (zz.re < 0) - nearest |= 0x04; - if (zz.im < 0) - { - nearest ^= 0x04; - nearest |= 0x08; - } - } - raw_bits = 0; - - switch (s->rx.training) - { - case V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION: - /* Normal operation. */ - target = &v22bis_constellation[nearest]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3]; - /* TODO: detect unscrambled ones indicating a loopback request */ - - /* Search for the S1 signal that might be requesting a retrain */ - if ((s->rx.last_raw_bits ^ raw_bits) == 0x3) - { - s->rx.pattern_repeats++; - } - else - { - if (s->rx.pattern_repeats >= 50 && (s->rx.last_raw_bits == 0x3 || s->rx.last_raw_bits == 0x0)) - { - /* We should get a full run of 00 11 (about 60 bauds) at either modem. */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats); - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Accepting a retrain request\n"); - s->rx.pattern_repeats = 0; - s->rx.training_count = 0; - s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200; - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011; - v22bis_equalizer_coefficient_reset(s); - v22bis_report_status_change(s, SIG_STATUS_MODEM_RETRAIN_OCCURRED); - } - s->rx.pattern_repeats = 0; - } - decode_baud(s, nearest); - break; - case V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION: - /* Allow time for the Gardner algorithm to settle the symbol timing. */ - target = &z; - if (++s->rx.training_count >= 40) - { - /* QAM and Gardner only play nicely with heavy damping, so we need to change to - a slow rate of symbol timing adaption. However, it must not be so slow that it - cannot track the worst case timing error specified in V.22bis. This should be 0.01%, - but since we might be off in the opposite direction from the source, the total - error could be higher. */ - s->rx.gardner_step = 4; - s->rx.pattern_repeats = 0; - s->rx.training = (s->calling_party) ? V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES : V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200; - /* Be pessimistic and see what the handshake brings */ - s->negotiated_bit_rate = 1200; - break; - } - /* Once we have pulled in the symbol timing in a coarse way, use finer - steps to fine tune the timing. */ - if (s->rx.training_count == 30) - s->rx.gardner_step = 32; - break; - case V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES: - /* Calling modem only. */ - /* The calling modem should initially receive unscrambled ones at 1200bps */ - target = &v22bis_constellation[nearest]; - track_carrier(s, &z, target); - raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3]; - s->rx.constellation_state = nearest; - if (raw_bits != s->rx.last_raw_bits) - s->rx.pattern_repeats = 0; - else - s->rx.pattern_repeats++; - if (++s->rx.training_count == ms_to_symbols(155 + 456)) - { - /* After the first 155ms things should have been steady, so check if the last 456ms was - steady at 11 or 00. */ - if (raw_bits == s->rx.last_raw_bits - && - (raw_bits == 0x3 || raw_bits == 0x0) - && - s->rx.pattern_repeats >= ms_to_symbols(456)) - { - /* It looks like the answering machine is sending us a clean unscrambled 11 or 00 */ - if (s->bit_rate == 2400) - { - /* Try to establish at 2400bps. */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Caller)\n"); - s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011; - s->tx.training_count = 0; - } - else - { - /* Only try to establish at 1200bps. */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 (1200) (Caller)\n"); - s->tx.training = V22BIS_TX_TRAINING_STAGE_S11; - s->tx.training_count = 0; - } - } - s->rx.pattern_repeats = 0; - s->rx.training_count = 0; - s->rx.training = V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING; - } - break; - case V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING: - /* Calling modem only. */ - /* Wait for the end of the unscrambled ones at 1200bps. */ - target = &v22bis_constellation[nearest]; - track_carrier(s, &z, target); - raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3]; - s->rx.constellation_state = nearest; - if (raw_bits != s->rx.last_raw_bits) - { - /* This looks like the end of the sustained initial unscrambled 11 or 00. */ - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11; - s->rx.training_count = 0; - s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200; - s->rx.pattern_repeats = 0; - } - break; - case V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200: - target = &v22bis_constellation[nearest]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3]; - bitstream = decode_baudx(s, nearest); - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx 0x%x\n", bitstream); - s->rx.training_count++; -//span_log(&s->logging, SPAN_LOG_FLOW, "S11 0x%02x 0x%02x 0x%X %d %d %d %d %d\n", raw_bits, nearest, bitstream, s->rx.scrambled_ones_to_date, 0, 0, 0, s->rx.training_count); - if (s->negotiated_bit_rate == 1200) - { - /* Search for the S1 signal */ - if ((s->rx.last_raw_bits ^ raw_bits) == 0x3) - { - s->rx.pattern_repeats++; - } - else - { - if (s->rx.pattern_repeats >= 15 && (s->rx.last_raw_bits == 0x3 || s->rx.last_raw_bits == 0x0)) - { - /* We should get a full run of 00 11 (about 60 bauds) at the calling modem, but only about 20 - at the answering modem, as the first 40 are TED settling time. */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats); - if (s->bit_rate == 2400) - { - if (!s->calling_party) - { - /* Accept establishment at 2400bps */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Answerer)\n"); - s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011; - s->tx.training_count = 0; - } - s->negotiated_bit_rate = 2400; - } - } - s->rx.pattern_repeats = 0; - } - if (s->rx.training_count >= ms_to_symbols(270)) - { - /* If we haven't seen the S1 signal by now, we are committed to be in 1200bps mode. */ - if (s->calling_party) - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n"); - /* The transmit side needs to sustain the scrambled ones for a timed period. */ - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11; - /* Normal reception starts immediately. */ - s->rx.training = V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION; -#if defined(SPANDSP_USE_FIXED_POINT) - s->rx.carrier_track_i = 8; -#else - s->rx.carrier_track_i = 8000.0f; -#endif - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 (1200) (Answerer)\n"); - /* The transmit side needs to sustain the scrambled ones for a timed period. */ - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11; - /* The receive side needs to wait a timed period, receiving scrambled ones, - before entering normal operation. */ - s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING; - } - } - } - else - { - if (s->calling_party) - { - 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.training = V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400; - s->rx.pattern_repeats = 0; -#if defined(SPANDSP_USE_FIXED_POINT) - s->rx.carrier_track_i = 8; -#else - s->rx.carrier_track_i = 8000.0f; -#endif - } - } - else - { - 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.training = V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400; - s->rx.pattern_repeats = 0; - } - } - } - break; - case V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING: - target = &v22bis_constellation[nearest]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - bitstream = decode_baudx(s, nearest); - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx 0x%x\n", bitstream); - if (++s->rx.training_count > ms_to_symbols(270 + 765)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n"); - s->rx.training = V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION; - } - break; - case V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400: - target = &v22bis_constellation[nearest]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - bitstream = decode_baudx(s, nearest); - /* We need 32 sustained 1's to switch into normal operation. */ - if (bitstream == 0xF) - { - if (++s->rx.pattern_repeats >= 9) - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (2400)\n"); - s->rx.training = V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION; - } - } - else - { - s->rx.pattern_repeats = 0; - } - break; - case V22BIS_RX_TRAINING_STAGE_PARKED: - default: - /* We failed to train! */ - /* Park here until the carrier drops. */ - target = &z; - break; - } - s->rx.last_raw_bits = raw_bits; - if (s->rx.qam_report) - s->rx.qam_report(s->rx.qam_user_data, &z, target, s->rx.constellation_state); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len) -{ - int i; - int step; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t z; - complexi16_t zz; - complexi16_t sample; - int32_t ii; - int32_t qq; -#else - complexf_t z; - complexf_t zz; - complexf_t sample; - float ii; - float qq; -#endif - int32_t root_power; - int32_t power; - - for (i = 0; i < len; i++) - { - /* Complex bandpass filter the signal, using a pair of FIRs, and RRC coeffs shifted - to centre at 1200Hz or 2400Hz. The filters support 12 fractional phase shifts, to - permit signal extraction very close to the middle of a symbol. */ - s->rx.rrc_filter[s->rx.rrc_filter_step] = amp[i]; - if (++s->rx.rrc_filter_step >= V22BIS_RX_FILTER_STEPS) - s->rx.rrc_filter_step = 0; - - /* Calculate the I filter, with an arbitrary phase step, just so we can calculate - the signal power of the required carrier, with any guard tone or spillback of our - own transmitted signal suppressed. */ - if (s->calling_party) - { -#if defined(SPANDSP_USE_FIXED_POINT) - ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15; -#else - ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_2400_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step); -#endif - } - else - { -#if defined(SPANDSP_USE_FIXED_POINT) - ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15; -#else - ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_1200_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step); -#endif - } - power = power_meter_update(&s->rx.rx_power, (int16_t) ii); - if (s->rx.signal_present) - { - /* Look for power below the carrier off point */ - if (power < s->rx.carrier_off_power) - { - v22bis_restart(s, s->bit_rate); - v22bis_report_status_change(s, SIG_STATUS_CARRIER_DOWN); - continue; - } - } - else - { - /* Look for power exceeding the carrier on point */ - if (power < s->rx.carrier_on_power) - continue; - 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 - a training failure. */ - if (s->rx.training == V22BIS_RX_TRAINING_STAGE_PARKED) - continue; - - /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm - will fiddle the step to align this with the symbols. */ - if ((s->rx.eq_put_step -= PULSESHAPER_COEFF_SETS) <= 0) - { - if (s->rx.training == V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION) - { - /* Only AGC during the initial symbol acquisition, and then lock the gain. */ - if ((root_power = fixed_sqrt32(power)) == 0) - root_power = 1; -#if defined(SPANDSP_USE_FIXED_POINT) - s->rx.agc_scaling = saturate16(((int32_t) (FP_SCALE(0.18f)*FP_SCALE(3.60f)))/root_power); -#else - s->rx.agc_scaling = FP_SCALE(0.18f)*FP_SCALE(3.60f)/root_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 bandband by complex mixing. - No further filtering, to remove mixer harmonics, is needed. */ - step = -s->rx.eq_put_step; - if (step > PULSESHAPER_COEFF_SETS - 1) - step = PULSESHAPER_COEFF_SETS - 1; - if (s->calling_party) - { -#if defined(SPANDSP_USE_FIXED_POINT) - ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15; - qq = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15; -#else - ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_2400_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step); - qq = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_2400_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step); -#endif - } - else - { -#if defined(SPANDSP_USE_FIXED_POINT) - ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15; - qq = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15; -#else - ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_1200_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step); - qq = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_1200_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step); -#endif - } - /* Shift to baseband - since this is done in a full complex form, the - result is clean, and requires no further filtering apart from the - equalizer. */ -#if defined(SPANDSP_USE_FIXED_POINT) - sample.re = (ii*s->rx.agc_scaling) >> FP_SHIFT_FACTOR; - sample.im = (qq*s->rx.agc_scaling) >> FP_SHIFT_FACTOR; - z = dds_lookup_complexi16(s->rx.carrier_phase); - zz.re = ((int32_t) sample.re*z.re - (int32_t) sample.im*z.im) >> 15; - zz.im = ((int32_t) -sample.re*z.im - (int32_t) sample.im*z.re) >> 15; -#else - sample.re = ii*s->rx.agc_scaling; - sample.im = qq*s->rx.agc_scaling; - z = dds_lookup_complexf(s->rx.carrier_phase); - zz.re = sample.re*z.re - sample.im*z.im; - zz.im = -sample.re*z.im - sample.im*z.re; -#endif - s->rx.eq_put_step += PULSESHAPER_COEFF_SETS*40/(3*2); - process_half_baud(s, &zz); - } -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->rx.carrier_phase, s->rx.carrier_phase_rate); -#else - dds_advancef(&s->rx.carrier_phase, s->rx.carrier_phase_rate); -#endif - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len) -{ - int i; - - /* We want to sustain the current state (i.e carrier on<->carrier off), and - try to sustain the carrier phase. We should probably push the filters, as well */ - span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len); - if (!s->rx.signal_present) - return 0; - for (i = 0; i < len; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->rx.carrier_phase, s->rx.carrier_phase_rate); -#else - dds_advancef(&s->rx.carrier_phase, s->rx.carrier_phase_rate); -#endif - } - /* TODO: Advance the symbol phase the appropriate amount */ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int v22bis_rx_restart(v22bis_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->rx.rrc_filter, sizeof(s->rx.rrc_filter)/sizeof(s->rx.rrc_filter[0])); - s->rx.training_error = 0; -#else - vec_zerof(s->rx.rrc_filter, sizeof(s->rx.rrc_filter)/sizeof(s->rx.rrc_filter[0])); - s->rx.training_error = 0.0f; -#endif - s->rx.rrc_filter_step = 0; - s->rx.scramble_reg = 0; - 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.carrier_phase_rate = (s->calling_party) ? DDS_PHASE_RATE(2400.0f) : DDS_PHASE_RATE(1200.0f); - s->rx.carrier_phase = 0; - power_meter_init(&s->rx.rx_power, 5); - v22bis_rx_signal_cutoff(s, -45.5f); -#if defined(SPANDSP_USE_FIXED_POINT) - s->rx.agc_scaling = (float) (1024.0f*1024.0f)*0.0005f*0.025f; -#else - s->rx.agc_scaling = 0.0005f*0.025f; -#endif - - s->rx.constellation_state = 0; - s->rx.sixteen_way_decisions = false; - - equalizer_reset(s); - - s->rx.pattern_repeats = 0; - s->rx.last_raw_bits = 0; - s->rx.gardner_integrate = 0; - s->rx.gardner_step = 256; - s->rx.baud_phase = 0; - s->rx.total_baud_timing_correction = 0; - /* We want the carrier to pull in faster on the answerer side, as it has very little time to adapt. */ -#if defined(SPANDSP_USE_FIXED_POINT) - s->rx.carrier_track_i = (s->calling_party) ? 8 : 40; - s->rx.carrier_track_p = 8000; -#else - s->rx.carrier_track_i = (s->calling_party) ? 8000.0f : 40000.0f; - s->rx.carrier_track_p = 8000000.0f; -#endif - - s->negotiated_bit_rate = 1200; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v22bis_rx_set_qam_report_handler(v22bis_state_t *s, qam_report_handler_t handler, void *user_data) -{ - s->rx.qam_report = handler; - s->rx.qam_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c deleted file mode 100644 index 41afff55c7..0000000000 --- a/libs/spandsp/src/v22bis_tx.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v22bis_tx.c - ITU V.22bis modem transmit part - * - * 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 */ - -/* THIS IS A WORK IN PROGRESS - It is basically functional, but it is not feature - complete, and doesn't reliably sync over the signal and noise level ranges it should! */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/dds.h" -#include "spandsp/power_meter.h" - -#include "spandsp/v29rx.h" -#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) -#define FP_SCALE(x) FP_Q6_10(x) -#else -#define FP_SCALE(x) (x) -#endif - -#include "v22bis_tx_rrc.h" - -/* Quoting from the V.22bis spec. - -6.3.1.1 Interworking at 2400 bit/s - -6.3.1.1.1 Calling modem - -a) On connection to line the calling modem shall be conditioned to receive signals - in the high channel at 1200 bit/s and transmit signals in the low channel at 1200 bit/s - in accordance with section 2.5.2.2. It shall apply an ON condition to circuit 107 in accordance - with Recommendation V.25. The modem shall initially remain silent. - -b) After 155 +-10 ms of unscrambled binary 1 has been detected, the modem shall remain silent - for a further 456 +-10 ms then transmit an unscrambled repetitive double dibit pattern of 00 - and 11 at 1200 bit/s for 100 +-3 ms. Following this signal the modem shall transmit scrambled - binary 1 at 1200 bit/s. - -c) If the modem detects scrambled binary 1 in the high channel at 1200 bit/s for 270 +-40 ms, - the handshake shall continue in accordance with section 6.3.1.2.1 c) and d). However, if unscrambled - repetitive double dibit 00 and 11 at 1200 bit/s is detected in the high channel, then at the - end of receipt of this signal the modem shall apply an ON condition to circuit 112. - -d) 600 +-10 ms after circuit 112 has been turned ON the modem shall begin transmitting scrambled - binary 1 at 2400 bit/s, and 450 +-10 ms after circuit 112 has been turned ON the receiver may - begin making 16-way decisions. - -e) Following transmission of scrambled binary 1 at 2400 bit/s for 200 +-10 ms, circuit 106 shall - be conditioned to respond to circuit 105 and the modem shall be ready to transmit data at - 2400 bit/s. - -f) When 32 consecutive bits of scrambled binary 1 at 2400 bit/s have been detected in the high - channel the modem shall be ready to receive data at 2400 bit/s and shall apply an ON condition - to circuit 109. - -6.3.1.1.2 Answering modem - -a) On connection to line the answering modem shall be conditioned to transmit signals in the high - channel at 1200 bit/s in accordance with section 2.5.2.2 and receive signals in the low channel at - 1200 bit/s. Following transmission of the answer sequence in accordance with Recommendation - V.25, the modem shall apply an ON condition to circuit 107 and then transmit unscrambled - binary 1 at 1200 bit/s. - -b) If the modem detects scrambled binary 1 or 0 in the low channel at 1200 bit/s for 270 +-40 ms, - the handshake shall continue in accordance with section 6.3.1.2.2 b) and c). However, if unscrambled - repetitive double dibit 00 and 11 at 1200 bit/s is detected in the low channel, at the end of - receipt of this signal the modem shall apply an ON condition to circuit 112 and then transmit - an unscrambled repetitive double dibit pattern of 00 and 11 at 1200 bit/s for 100 +-3 ms. - Following these signals the modem shall transmit scrambled binary 1 at 1200 bit/s. - -c) 600 +-10 ms after circuit 112 has been turned ON the modem shall begin transmitting scrambled - binary 1 at 2400 bit/s, and 450 +-10 ms after circuit 112 has been turned ON the receiver may - begin making 16-way decisions. - -d) Following transmission of scrambled binary 1 at 2400 bit/s for 200 +-10 ms, circuit 106 shall - be conditioned to respond to circuit 105 and the modem shall be ready to transmit data at - 2400 bit/s. - -e) When 32 consecutive bits of scrambled binary 1 at 2400 bit/s have been detected in the low - channel the modem shall be ready to receive data at 2400 bit/s and shall apply an ON - condition to circuit 109. - -6.3.1.2 Interworking at 1200 bit/s - -The following handshake is identical to the Recommendation V.22 alternative A and B handshake. - -6.3.1.2.1 Calling modem - -a) On connection to line the calling modem shall be conditioned to receive signals in the high - channel at 1200 bit/s and transmit signals in the low channel at 1200 bit/s in accordance - with section 2.5.2.2. It shall apply an ON condition to circuit 107 in accordance with - Recommendation V.25. The modem shall initially remain silent. - -b) After 155 +-10 ms of unscrambled binary 1 has been detected, the modem shall remain silent - for a further 456 +-10 ms then transmit scrambled binary 1 at 1200 bit/s (a preceding V.22 bis - signal, as shown in Figure 7/V.22 bis, would not affect the operation of a V.22 answer modem). - -c) On detection of scrambled binary 1 in the high channel at 1200 bit/s for 270 +-40 ms the modem - shall be ready to receive data at 1200 bit/s and shall apply an ON condition to circuit 109 and - an OFF condition to circuit 112. - -d) 765 +-10 ms after circuit 109 has been turned ON, circuit 106 shall be conditioned to respond - to circuit 105 and the modem shall be ready to transmit data at 1200 bit/s. - -6.3.1.2.2 Answering modem - -a) On connection to line the answering modem shall be conditioned to transmit signals in the high - channel at 1200 bit/s in accordance with section 2.5.2.2 and receive signals in the low channel at - 1200 bit/s. - - Following transmission of the answer sequence in accordance with V.25 the modem shall apply - an ON condition to circuit 107 and then transmit unscrambled binary 1 at 1200 bit/s. - -b) On detection of scrambled binary 1 or 0 in the low channel at 1200 bit/s for 270 +-40 ms the - modem shall apply an OFF condition to circuit 112 and shall then transmit scrambled binary 1 - at 1200 bit/s. - -c) After scrambled binary 1 has been transmitted at 1200 bit/s for 765 +-10 ms the modem shall be - ready to transmit and receive data at 1200 bit/s, shall condition circuit 106 to respond to - circuit 105 and shall apply an ON condition to circuit 109. - -Note - Manufacturers may wish to note that in certain countries, for national purposes, modems are - in service which emit an answering tone of 2225 Hz instead of unscrambled binary 1. - - -V.22bis to V.22bis ------------------- -Calling party - S1 scrambled 1's scrambled 1's data - at 1200bps at 2400bps -|---------------------------------------------------------|XXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXX|XXXXXXXXXXXXX - |<155+-10>|<456+-10>|<100+-3>| |<------600+-10------>|<---200+-10-->| - ^ | ^<----450+-100---->|[16 way decisions begin] - | | | - | v | - | |<------450+-100----->|[16 way decisions begin] - | |<----------600+-10-------->| - |<2150+-350>|<--3300+-700->|<75+-20>| |<100+-3>| |<---200+-10--> - |-----------|XXXXXXXXXXXXXX|--------|XXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXX|XXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXX|XXXXXXXXXXXXX - silence 2100Hz unscrambled 1's S1 scrambled 1's scrambled 1's data - at 1200bps at 1200bps at 2400bps -Answering party - -S1 = Unscrambled double dibit 00 and 11 at 1200bps -When the 2400bps section starts, both sides should look for 32 bits of continuous ones, as a test of integrity. - - - - -V.22 to V.22bis ---------------- -Calling party - scrambled 1's data - at 1200bps -|---------------------------------------------------------|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX - |<155+-10>|<456+-10>| |<270+-40>|<--------765+-10-------->| - ^ | ^ - | | | - | | | - | | | - | v | - |<2150+-350>|<--3300+-700->|<75+-20>| |<270+-40>|<---------765+-10-------->| - |-----------|XXXXXXXXXXXXXX|--------|XXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX - silence 2100Hz unscrambled 1's scrambled 1's data - at 1200bps at 1200bps -Answering party - -Both ends should accept unscrambled binary 1 or binary 0 as the preamble. - - - - -V.22bis to V.22 ---------------- -Calling party - S1 scrambled 1's data - at 1200bps -|---------------------------------------------------------|XXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX - |<155+-10>|<456+-10>|<100+-3>| |<-270+-40-><------765+-10------>| - ^ | ^ - | | | - | v | - | | - | | - |<2150+-350>|<--3300+-700->|<75+-20>| |<-270+-40->|<------765+-10----->| - |-----------|XXXXXXXXXXXXXX|--------|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX - silence 2100Hz unscrambled 1's scrambled 1's data - at 1200bps at 1200bps -Answering party - -Both ends should accept unscrambled binary 1 or binary 0 as the preamble. -*/ - -#define ms_to_symbols(t) (((t)*600)/1000) - -static const int phase_steps[4] = -{ - 1, 0, 2, 3 -}; - -#if defined(SPANDSP_USE_FIXED_POINT) -const complexi16_t v22bis_constellation[16] = -#else -const complexf_t v22bis_constellation[16] = -#endif -{ - {FP_SCALE( 1.0f), FP_SCALE( 1.0f)}, - {FP_SCALE( 3.0f), FP_SCALE( 1.0f)}, /* 1200bps 00 */ - {FP_SCALE( 1.0f), FP_SCALE( 3.0f)}, - {FP_SCALE( 3.0f), FP_SCALE( 3.0f)}, - {FP_SCALE(-1.0f), FP_SCALE( 1.0f)}, - {FP_SCALE(-1.0f), FP_SCALE( 3.0f)}, /* 1200bps 01 */ - {FP_SCALE(-3.0f), FP_SCALE( 1.0f)}, - {FP_SCALE(-3.0f), FP_SCALE( 3.0f)}, - {FP_SCALE(-1.0f), FP_SCALE(-1.0f)}, - {FP_SCALE(-3.0f), FP_SCALE(-1.0f)}, /* 1200bps 10 */ - {FP_SCALE(-1.0f), FP_SCALE(-3.0f)}, - {FP_SCALE(-3.0f), FP_SCALE(-3.0f)}, - {FP_SCALE( 1.0f), FP_SCALE(-1.0f)}, - {FP_SCALE( 1.0f), FP_SCALE(-3.0f)}, /* 1200bps 11 */ - {FP_SCALE( 3.0f), FP_SCALE(-1.0f)}, - {FP_SCALE( 3.0f), FP_SCALE(-3.0f)} -}; - -static int fake_get_bit(void *user_data) -{ - return 1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int scramble(v22bis_state_t *s, int bit) -{ - int out_bit; - - if (s->tx.scrambler_pattern_count >= 64) - { - bit ^= 1; - s->tx.scrambler_pattern_count = 0; - } - out_bit = (bit ^ (s->tx.scramble_reg >> 13) ^ (s->tx.scramble_reg >> 16)) & 1; - s->tx.scramble_reg = (s->tx.scramble_reg << 1) | out_bit; - - if (out_bit == 1) - s->tx.scrambler_pattern_count++; - else - s->tx.scrambler_pattern_count = 0; - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int get_scrambled_bit(v22bis_state_t *s) -{ - int bit; - - if ((bit = s->tx.current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA) - { - /* Fill out this symbol with ones, and prepare to send - the rest of the shutdown sequence. */ - s->tx.current_get_bit = fake_get_bit; - s->tx.shutdown = 1; - bit = 1; - } - return scramble(s, bit); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static complexi16_t training_get(v22bis_state_t *s) -#else -static complexf_t training_get(v22bis_state_t *s) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t zero = {0, 0}; -#else - static const complexf_t zero = {0.0f, 0.0f}; -#endif - int bits; - - /* V.22bis training sequence */ - switch (s->tx.training) - { - case V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE: - /* The answerer waits 75ms, then sends unscrambled ones */ - if (++s->tx.training_count >= ms_to_symbols(75)) - { - /* Initial 75ms of silence is over */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U11 1200\n"); - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_U11; - } - /* Fall through */ - case V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE: - /* Silence */ - s->tx.constellation_state = 0; - return zero; - case V22BIS_TX_TRAINING_STAGE_U11: - /* Send continuous unscrambled ones at 1200bps (i.e. 270 degree phase steps). */ - /* Only the answering modem sends unscrambled ones. It is the first thing exchanged between the modems. */ - s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3]) & 3; - return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; - case V22BIS_TX_TRAINING_STAGE_U0011: - /* Continuous unscrambled double dibit 00 11 at 1200bps. This is termed the S1 segment in - the V.22bis spec. It is only sent to request or accept 2400bps mode, and lasts 100+-3ms. After this - timed burst, we unconditionally change to sending scrambled ones at 1200bps. */ - s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3*(s->tx.training_count & 1)]) & 3; - if (++s->tx.training_count >= ms_to_symbols(100)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n"); - if (s->calling_party) - { - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_S11; - } - else - { - s->tx.training_count = ms_to_symbols(756 - (600 - 100)); - s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11; - } - } - return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; - case V22BIS_TX_TRAINING_STAGE_TIMED_S11: - /* A timed period of scrambled ones at 1200bps. */ - if (++s->tx.training_count >= ms_to_symbols(756)) - { - if (s->negotiated_bit_rate == 2400) - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S1111 (C)\n"); - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_S1111; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Tx normal operation (1200)\n"); - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION; - v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->tx.current_get_bit = s->get_bit; - } - } - /* Fall through */ - case V22BIS_TX_TRAINING_STAGE_S11: - /* Scrambled ones at 1200bps. */ - bits = scramble(s, 1); - bits = (bits << 1) | scramble(s, 1); - s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; - return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; - case V22BIS_TX_TRAINING_STAGE_S1111: - /* Scrambled ones at 2400bps. We send a timed 200ms burst, and switch to normal operation at 2400bps */ - bits = scramble(s, 1); - bits = (bits << 1) | scramble(s, 1); - s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; - bits = scramble(s, 1); - bits = (bits << 1) | scramble(s, 1); - if (++s->tx.training_count >= ms_to_symbols(200)) - { - /* We have completed training. Now handle some real work. */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Tx normal operation (2400)\n"); - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION; - v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->tx.current_get_bit = s->get_bit; - } - return v22bis_constellation[(s->tx.constellation_state << 2) | bits]; - } - return zero; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static complexi16_t getbaud(v22bis_state_t *s) -#else -static complexf_t getbaud(v22bis_state_t *s) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t zero = {0, 0}; -#else - static const complexf_t zero = {0.0f, 0.0f}; -#endif - int bits; - - if (s->tx.training) - { - /* Send the training sequence */ - return training_get(s); - } - - /* There is no graceful shutdown procedure defined for V.22bis. Just - send some ones, to ensure we get the real data bits through, even - with bad ISI. */ - if (s->tx.shutdown) - { - if (++s->tx.shutdown > 10) - return zero; - } - /* The first two bits define the quadrant */ - bits = get_scrambled_bit(s); - bits = (bits << 1) | get_scrambled_bit(s); - s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; - if (s->negotiated_bit_rate == 1200) - { - bits = 0x01; - } - else - { - /* The other two bits define the position within the quadrant */ - bits = get_scrambled_bit(s); - bits = (bits << 1) | get_scrambled_bit(s); - } - return v22bis_constellation[(s->tx.constellation_state << 2) | bits]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t v; - complexi32_t x; - complexi32_t z; - int16_t iamp; -#else - complexf_t v; - complexf_t x; - complexf_t z; - float famp; -#endif - int sample; - - if (s->tx.shutdown > 10) - return 0; - for (sample = 0; sample < len; sample++) - { - if ((s->tx.baud_phase += 3) >= 40) - { - s->tx.baud_phase -= 40; - v = getbaud(s); - s->tx.rrc_filter_re[s->tx.rrc_filter_step] = v.re; - s->tx.rrc_filter_im[s->tx.rrc_filter_step] = v.im; - if (++s->tx.rrc_filter_step >= V22BIS_TX_FILTER_STEPS) - s->tx.rrc_filter_step = 0; - } -#if defined(SPANDSP_USE_FIXED_POINT) - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodi16(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 14; - x.im = vec_circular_dot_prodi16(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 14; - /* Now create and modulate the carrier */ - z = dds_complexi32(&s->tx.carrier_phase, s->tx.carrier_phase_rate); - iamp = (x.re*z.re - x.im*z.im) >> 15; - iamp = (int16_t) (((int32_t) iamp*s->tx.gain) >> 11); - if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0 || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0)) - { - /* Add the guard tone */ - iamp += dds_mod(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0); - } - /* Don't bother saturating. We should never clip. */ - amp[sample] = iamp; -#else - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodf(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step); - x.im = vec_circular_dot_prodf(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step); - /* Now create and modulate the carrier */ - z = dds_complexf(&s->tx.carrier_phase, s->tx.carrier_phase_rate); - famp = (x.re*z.re - x.im*z.im)*s->tx.gain; - if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0.0f || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0.0f)) - { - /* Add the guard tone */ - famp += dds_modf(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0); - } - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) lfastrintf(famp); -#endif - } - return sample; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power) -{ - float sig_power; - float guard_tone_power; - float sig_gain; - float guard_tone_gain; - - /* If is there is a guard tone we need to scale down the signal power a bit, so the aggregate of the signal - and guard tone power is the specified power. */ - if (s->tx.guard_phase_rate == dds_phase_ratef(550.0f)) - { - sig_power = power - 1.0f; - guard_tone_power = sig_power - 3.0f; - } - else if(s->tx.guard_phase_rate == dds_phase_ratef(1800.0f)) - { - sig_power = power - 0.55f; - guard_tone_power = sig_power - 6.0f; - } - else - { - sig_power = power; - guard_tone_power = -9999.0f; - } - sig_gain = 0.4490f*powf(10.0f, (sig_power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN; - guard_tone_gain = powf(10.0f, (guard_tone_power - DBM0_MAX_POWER)/20.0f)*32768.0f; -#if defined(SPANDSP_USE_FIXED_POINT) - s->tx.gain = (int16_t) sig_gain; - s->tx.guard_tone_gain = (int16_t) guard_tone_gain; -#else - s->tx.gain = sig_gain; - s->tx.guard_tone_gain = guard_tone_gain; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static int v22bis_tx_restart(v22bis_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0])); - vec_zeroi16(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0])); -#else - vec_zerof(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0])); - vec_zerof(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0])); -#endif - s->tx.rrc_filter_step = 0; - s->tx.scramble_reg = 0; - s->tx.scrambler_pattern_count = 0; - if (s->calling_party) - s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE; - else - s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE; - s->tx.training_count = 0; - s->tx.carrier_phase = 0; - s->tx.guard_phase = 0; - s->tx.baud_phase = 0; - s->tx.constellation_state = 0; - s->tx.current_get_bit = fake_get_bit; - s->tx.shutdown = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v22bis_set_get_bit(v22bis_state_t *s, get_bit_func_t get_bit, void *user_data) -{ - s->get_bit = get_bit; - s->get_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit, void *user_data) -{ - s->put_bit = put_bit; - s->put_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v22bis_get_logging_state(v22bis_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_restart(v22bis_state_t *s, int bit_rate) -{ - switch (bit_rate) - { - case 2400: - case 1200: - break; - default: - return -1; - } - s->bit_rate = bit_rate; - s->negotiated_bit_rate = 1200; - if (v22bis_tx_restart(s)) - return -1; - return v22bis_rx_restart(s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate) -{ - /* TODO: support bit rate switching */ - switch (bit_rate) - { - case 2400: - case 1200: - break; - default: - return -1; - } - /* TODO: support bit rate changes */ - /* Retrain is only valid when we are normal operation at 2400bps */ - if (s->rx.training != V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION - || - s->tx.training != V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION - || - s->negotiated_bit_rate != 2400) - { - return -1; - } - /* Send things back into the training process at the appropriate point. - The far end should detect the S1 signal, and reciprocate. */ - span_log(&s->logging, SPAN_LOG_FLOW, "+++ Initiating a retrain\n"); - s->rx.pattern_repeats = 0; - s->rx.training_count = 0; - s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200; - s->tx.training_count = 0; - s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011; - v22bis_equalizer_coefficient_reset(s); - v22bis_report_status_change(s, SIG_STATUS_MODEM_RETRAIN_OCCURRED); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, bool enable) -{ - /* TODO: */ - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_get_current_bit_rate(v22bis_state_t *s) -{ - return s->negotiated_bit_rate; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, - int bit_rate, - int guard, - bool calling_party, - get_bit_func_t get_bit, - void *get_bit_user_data, - put_bit_func_t put_bit, - void *put_bit_user_data) -{ - switch (bit_rate) - { - case 2400: - case 1200: - break; - default: - return NULL; - } - if (s == NULL) - { - if ((s = (v22bis_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, "V.22bis"); - s->bit_rate = bit_rate; - s->calling_party = calling_party; - - s->get_bit = get_bit; - s->get_bit_user_data = get_bit_user_data; - s->put_bit = put_bit; - s->put_bit_user_data = put_bit_user_data; - - if (s->calling_party) - { - s->tx.carrier_phase_rate = dds_phase_ratef(1200.0f); - } - else - { - s->tx.carrier_phase_rate = dds_phase_ratef(2400.0f); - switch (guard) - { - case V22BIS_GUARD_TONE_550HZ: - s->tx.guard_phase_rate = dds_phase_ratef(550.0f); - break; - case V22BIS_GUARD_TONE_1800HZ: - s->tx.guard_phase_rate = dds_phase_ratef(1800.0f); - break; - default: - s->tx.guard_phase_rate = 0; - break; - } - } - v22bis_tx_power(s, -14.0f); - v22bis_restart(s, s->bit_rate); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_release(v22bis_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v22bis_free(v22bis_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c deleted file mode 100644 index 9383d46af0..0000000000 --- a/libs/spandsp/src/v27ter_rx.c +++ /dev/null @@ -1,1150 +0,0 @@ -#define IAXMODEM_STUFF -/* - * SpanDSP - a series of DSP components for telephony - * - * v27ter_rx.c - ITU V.27ter modem receive part - * - * 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 */ - -#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 "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" -#include "spandsp/saturated.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/power_meter.h" -#include "spandsp/arctan2.h" -#include "spandsp/dds.h" -#include "spandsp/complex_filters.h" - -#include "spandsp/v29rx.h" -#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) -#define FP_SCALE(x) FP_Q6_10(x) -#define FP_FACTOR 4096 -#define FP_SHIFT_FACTOR 12 -#else -#define FP_SCALE(x) (x) -#endif - -#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x) - -#include "v27ter_rx_4800_rrc.h" -#include "v27ter_rx_2400_rrc.h" - -/* V.27ter is a DPSK modem, but this code treats it like QAM. It nails down the - signal to a static constellation, even though dealing with differences is all - that is necessary. */ - -/*! The nominal frequency of the carrier, in Hertz */ -#define CARRIER_NOMINAL_FREQ 1800.0f -/*! The nominal baud or symbol rate in 2400bps mode */ -#define BAUD_RATE_2400 1200 -/*! The nominal baud or symbol rate in 4800bps mode */ -#define BAUD_RATE_4800 1600 -/*! The adaption rate coefficient for the equalizer */ -#define EQUALIZER_DELTA 0.25f - -/* Segments of the training sequence */ -/* V.27ter defines a long and a short sequence. FAX doesn't use the - short sequence, so it is not implemented here. */ -/*! The length of training segment 3, in symbols */ -#define V27TER_TRAINING_SEG_3_LEN 50 -/*! The length of training segment 5, in symbols */ -#define V27TER_TRAINING_SEG_5_LEN 1074 -/*! The length of training segment 6, in symbols */ -#define V27TER_TRAINING_SEG_6_LEN 8 - -enum -{ - TRAINING_STAGE_NORMAL_OPERATION = 0, - TRAINING_STAGE_SYMBOL_ACQUISITION, - TRAINING_STAGE_LOG_PHASE, - TRAINING_STAGE_WAIT_FOR_HOP, - TRAINING_STAGE_TRAIN_ON_ABAB, - TRAINING_STAGE_TEST_ONES, - TRAINING_STAGE_PARKED -}; - -#if defined(SPANDSP_USE_FIXED_POINT) -static const complexi16_t v27ter_constellation[8] = -#else -static const complexf_t v27ter_constellation[8] = -#endif -{ - {FP_CONSTELLATION_SCALE( 1.414f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 45deg */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 1.414f)}, /* 90deg */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 135deg */ - {FP_CONSTELLATION_SCALE(-1.414f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 225deg */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-1.414f)}, /* 270deg */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-1.0f)} /* 315deg */ -}; - -SPAN_DECLARE(float) v27ter_rx_carrier_frequency(v27ter_rx_state_t *s) -{ - return dds_frequencyf(s->carrier_phase_rate); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v27ter_rx_symbol_timing_correction(v27ter_rx_state_t *s) -{ - int steps_per_symbol; - - steps_per_symbol = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5 : RX_PULSESHAPER_2400_COEFF_SETS*20/3; - return (float) s->total_baud_timing_correction/(float) steps_per_symbol; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v27ter_rx_signal_power(v27ter_rx_state_t *s) -{ - return power_meter_current_dbm0(&s->power) + 3.98f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_rx_signal_cutoff(v27ter_rx_state_t *s, float cutoff) -{ - /* The 0.4 factor allows for the gain of the DC blocker */ - s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f); - s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f); -} -/*- End of function --------------------------------------------------------*/ - -static void report_status_change(v27ter_rx_state_t *s, int status) -{ - if (s->status_handler) - s->status_handler(s->status_user_data, status); - else if (s->put_bit) - s->put_bit(s->put_bit_user_data, status); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexi16_t **coeffs) -#else -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 --------------------------------------------------------*/ - -static void equalizer_save(v27ter_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_LEN); -#else - cvec_copyf(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_LEN); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_restore(v27ter_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_LEN); - cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN); - s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN; -#else - cvec_copyf(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_LEN); - cvec_zerof(s->eq_buf, V27TER_EQUALIZER_LEN); - s->eq_delta = EQUALIZER_DELTA/V27TER_EQUALIZER_LEN; -#endif - - s->eq_put_step = (s->bit_rate == 4800) ? (RX_PULSESHAPER_4800_COEFF_SETS*5/2 - 1) : (RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2) - 1); - s->eq_step = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_reset(v27ter_rx_state_t *s) -{ - /* Start with an equalizer based on everything being perfect. */ -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t x = {FP_CONSTELLATION_SCALE(1.414f), FP_CONSTELLATION_SCALE(0.0f)}; - - cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_LEN); - s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x; - cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN); - s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN; -#else - static const complexf_t x = {FP_CONSTELLATION_SCALE(1.414f), FP_CONSTELLATION_SCALE(0.0f)}; - - cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_LEN); - s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x; - cvec_zerof(s->eq_buf, V27TER_EQUALIZER_LEN); - s->eq_delta = EQUALIZER_DELTA/V27TER_EQUALIZER_LEN; -#endif - - s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2); - s->eq_step = 0; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ complexi16_t equalizer_get(v27ter_rx_state_t *s) -{ - complexi32_t zz; - complexi16_t z; - - /* Get the next equalized value. */ - zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step); - z.re = zz.re >> 14; - z.im = zz.im >> 14; - return z; -} -#else -static __inline__ complexf_t equalizer_get(v27ter_rx_state_t *s) -{ - /* Get the next equalized value. */ - return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void tune_equalizer(v27ter_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) -{ - complexi16_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subi16(target, z); - err.re = ((int32_t) err.re*s->eq_delta) >> 13; - err.im = ((int32_t) err.im*s->eq_delta) >> 13; - cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step, &err); -} -#else -static void tune_equalizer(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target) -{ - complexf_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subf(target, z); - err.re *= s->eq_delta; - err.im *= s->eq_delta; - cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step, &err); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) -#else -static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t error; -#else - float error; -#endif - - /* For small errors the imaginary part of the difference between the actual and the target - positions is proportional to the phase error, for any particular target. However, the - different amplitudes of the various target positions scale things. */ -#if defined(SPANDSP_USE_FIXED_POINT) - error = ((int32_t) z->im*target->re - (int32_t) z->re*target->im) >> 10; - s->carrier_phase_rate += ((s->carrier_track_i*error) >> FP_SHIFT_FACTOR); - s->carrier_phase += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR); -#else - error = z->im*target->re - z->re*target->im; - s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error); - s->carrier_phase += (int32_t) (s->carrier_track_p*error); - //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate)); -#endif -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ int find_quadrant(const complexi16_t *z) -#else -static __inline__ int find_quadrant(const complexf_t *z) -#endif -{ - int b1; - int b2; - - /* Split the space along the two diagonals. */ - b1 = (z->im > z->re); - b2 = (z->im < -z->re); - return (b2 << 1) | (b1 ^ b2); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ int find_octant(complexi16_t *z) -#else -static __inline__ int find_octant(complexf_t *z) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t abs_re; - int32_t abs_im; -#else - float abs_re; - float abs_im; -#endif - int b1; - int b2; - int bits; - - /* Are we near an axis or a diagonal? */ -#if defined(SPANDSP_USE_FIXED_POINT) - abs_re = abs(z->re); - abs_im = abs(z->im); -#else - abs_re = fabsf(z->re); - abs_im = fabsf(z->im); -#endif - if (abs_im*FP_SCALE(1.0f) > abs_re*FP_SCALE(0.4142136f) && abs_im*FP_SCALE(1.0f) < abs_re*FP_SCALE(2.4142136f)) - { - /* Split the space along the two axes. */ - b1 = (z->re < FP_SCALE(0.0f)); - b2 = (z->im < FP_SCALE(0.0f)); - bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1; - } - else - { - /* Split the space along the two diagonals. */ - b1 = (z->im > z->re); - b2 = (z->im < -z->re); - bits = (b2 << 2) | ((b1 ^ b2) << 1); - } - return bits; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int descramble(v27ter_rx_state_t *s, int in_bit) -{ - int out_bit; - - in_bit &= 1; - out_bit = (in_bit ^ (s->scramble_reg >> 5) ^ (s->scramble_reg >> 6)) & 1; - if (s->scrambler_pattern_count >= 33) - { - out_bit ^= 1; - s->scrambler_pattern_count = 0; - } - else - { - if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION && s->training_stage < TRAINING_STAGE_TEST_ONES) - { - s->scrambler_pattern_count = 0; - } - else - { - if ((((s->scramble_reg >> 7) ^ in_bit) & ((s->scramble_reg >> 8) ^ in_bit) & ((s->scramble_reg >> 11) ^ in_bit) & 1)) - s->scrambler_pattern_count = 0; - else - s->scrambler_pattern_count++; - } - } - s->scramble_reg <<= 1; - if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION && s->training_stage < TRAINING_STAGE_TEST_ONES) - s->scramble_reg |= out_bit; - else - s->scramble_reg |= in_bit; - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void put_bit(v27ter_rx_state_t *s, int bit) -{ - int out_bit; - - out_bit = descramble(s, bit); - /* We need to strip the last part of the training before we let data - go to the application. */ - if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION) - { - s->put_bit(s->put_bit_user_data, out_bit); - } - else - { - //span_log(&s->logging, SPAN_LOG_FLOW, "Test bit %d\n", out_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. */ - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void decode_baud(v27ter_rx_state_t *s, complexi16_t *z) -#else -static void decode_baud(v27ter_rx_state_t *s, complexf_t *z) -#endif -{ - static const uint8_t phase_steps_4800[8] = - { - 4, 0, 2, 6, 7, 3, 1, 5 - }; - static const uint8_t phase_steps_2400[4] = - { - 0, 2, 3, 1 - }; - int nearest; - int raw_bits; - - if (s->bit_rate == 2400) - { - nearest = find_quadrant(z); - raw_bits = phase_steps_2400[(nearest - s->constellation_state) & 3]; - put_bit(s, raw_bits); - put_bit(s, raw_bits >> 1); - s->constellation_state = nearest; - nearest <<= 1; - } - else - { - nearest = find_octant(z); - raw_bits = phase_steps_4800[(nearest - s->constellation_state) & 7]; - put_bit(s, raw_bits); - put_bit(s, raw_bits >> 1); - put_bit(s, raw_bits >> 2); - s->constellation_state = nearest; - } - track_carrier(s, z, &v27ter_constellation[nearest]); - if (--s->eq_skip <= 0) - { - /* Once we are in the data the equalization should not need updating. - However, the line characteristics may slowly drift. We, therefore, - tune up on the occassional sample, keeping the compute down. */ - s->eq_skip = 100; - tune_equalizer(s, z, &v27ter_constellation[nearest]); - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void symbol_sync(v27ter_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t p; - int32_t q; -#else - float p; - float q; -#endif - - /* This routine adapts the position of the half baud samples entering the equalizer. */ - - /* Perform a Gardner test for baud alignment */ - p = s->eq_buf[(s->eq_step - 3) & (V27TER_EQUALIZER_LEN - 1)].re - - s->eq_buf[(s->eq_step - 1) & (V27TER_EQUALIZER_LEN - 1)].re; - p *= s->eq_buf[(s->eq_step - 2) & (V27TER_EQUALIZER_LEN - 1)].re; - - q = s->eq_buf[(s->eq_step - 3) & (V27TER_EQUALIZER_LEN - 1)].im - - s->eq_buf[(s->eq_step - 1) & (V27TER_EQUALIZER_LEN - 1)].im; - q *= s->eq_buf[(s->eq_step - 2) & (V27TER_EQUALIZER_LEN - 1)].im; - - s->gardner_integrate += (p + q > 0) ? s->gardner_step : -s->gardner_step; - - if (abs(s->gardner_integrate) >= 128) - { - /* This integrate and dump approach avoids rapid changes of the equalizer put step. - Rapid changes, without hysteresis, are bad. They degrade the equalizer performance - when the true symbol boundary is close to a sample boundary. */ - //span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate); - s->eq_put_step += (s->gardner_integrate/128); - s->total_baud_timing_correction += (s->gardner_integrate/128); - if (s->qam_report) - s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate); - s->gardner_integrate = 0; - } - //span_log(&s->logging, SPAN_LOG_FLOW, "Gardner=%10.5f 0x%X\n", p, s->eq_put_step); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexi16_t *sample) -#else -static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t *sample) -#endif -{ - static const int abab_pos[2] = {0, 4}; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t z; - complexi16_t z16; - const complexi16_t *target; - 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 = {FP_SCALE(0.0f), FP_SCALE(0.0f)}; -#endif - int i; - int j; - int32_t angle; - int32_t ang; - int constellation_state; - - /* Add a sample to the equalizer's circular buffer, but don't calculate anything - at this time. */ - s->eq_buf[s->eq_step] = *sample; - if (++s->eq_step >= V27TER_EQUALIZER_LEN) - s->eq_step = 0; - - /* On alternate insertions we have a whole baud, and must process it. */ - if ((s->baud_half ^= 1)) - return; - - symbol_sync(s); - - z = equalizer_get(s); - - //span_log(&s->logging, SPAN_LOG_FLOW, "Equalized symbol - %15.5f %15.5f\n", z.re, z.im); - switch (s->training_stage) - { - case TRAINING_STAGE_NORMAL_OPERATION: - decode_baud(s, &z); - constellation_state = (s->bit_rate == 4800) ? s->constellation_state : (s->constellation_state << 1); - target = &v27ter_constellation[constellation_state]; - break; - case TRAINING_STAGE_SYMBOL_ACQUISITION: - /* Allow time for the Gardner algorithm to settle the baud timing */ - /* Don't start narrowing the bandwidth of the Gardner algorithm too early. - Some modems are a bit wobbly when they start sending the signal. Also, we start - this analysis before our filter buffers have completely filled. */ - target = &zero; - if (++s->training_count >= 30) - { - s->gardner_step = 32; - s->training_stage = TRAINING_STAGE_LOG_PHASE; - vec_zeroi32(s->diff_angles, 16); - s->last_angles[0] = arctan2(z.im, z.re); - } - break; - case TRAINING_STAGE_LOG_PHASE: - /* Record the current alternate phase angle */ - target = &zero; - s->last_angles[1] = arctan2(z.im, z.re); - s->training_count = 1; - s->training_stage = TRAINING_STAGE_WAIT_FOR_HOP; - break; - case TRAINING_STAGE_WAIT_FOR_HOP: - target = &zero; - angle = arctan2(z.im, z.re); - /* Look for the initial ABAB sequence to display a phase reversal, which will - signal the start of the scrambled ABAB segment */ - i = s->training_count + 1; - ang = angle - s->last_angles[i & 1]; - s->last_angles[i & 1] = angle; - s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4); - if ((ang > DDS_PHASE(45.0f) || ang < DDS_PHASE(-45.0f)) && s->training_count >= 13) - { - /* We seem to have a phase reversal */ - /* Slam the carrier frequency into line, based on the total phase drift over the last - section. Use the shift from the odd bits and the shift from the even bits to get - better jitter suppression. We need to scale here, or at the maximum specified - frequency deviation we could overflow, and get a silly answer. */ - /* Step back a few symbols so we don't get ISI distorting things. */ - i = (s->training_count - 8) & ~1; - /* Avoid the possibility of a divide by zero */ - if (i > 1) - { - j = i & 0xF; - ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1); - if (s->bit_rate == 4800) - s->carrier_phase_rate += 16*(ang/10); - else - s->carrier_phase_rate += 3*16*(ang/40); - } - span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count); - /* Check if the carrier frequency is plausible */ - if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f) - || - s->carrier_phase_rate > DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ + 20.0f)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); - /* Park this modem */ - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - break; - } - - /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer - buffer, as well as the carrier phase, for this to play out nicely. */ - angle += DDS_PHASE(180.0f); -#if defined(SPANDSP_USE_FIXED_POINT) - z16 = complex_seti16(fixed_cos(angle >> 16), -fixed_sin(angle >> 16)); - for (i = 0; i < V27TER_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mul_q1_15(&s->eq_buf[i], &z16); -#else - p = dds_phase_to_radians(angle); - zz = complex_setf(cosf(p), -sinf(p)); - for (i = 0; i < V27TER_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz); -#endif - s->carrier_phase += angle; - s->gardner_step = 2; - /* We have just seen the first element of the scrambled sequence so skip it. */ - s->training_bc = 1; - s->training_bc ^= descramble(s, 1); - descramble(s, 1); - descramble(s, 1); - s->constellation_state = abab_pos[s->training_bc]; - target = &v27ter_constellation[s->constellation_state]; - s->training_count = 1; - s->training_stage = TRAINING_STAGE_TRAIN_ON_ABAB; - report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS); - } - else if (++s->training_count > V27TER_TRAINING_SEG_3_LEN) - { - /* This is bogus. There are not this many bits in this section - of a real training sequence. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); - /* Park this modem */ - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - break; - case TRAINING_STAGE_TRAIN_ON_ABAB: - /* Train on the scrambled ABAB section */ - s->training_bc ^= descramble(s, 1); - descramble(s, 1); - descramble(s, 1); - s->constellation_state = abab_pos[s->training_bc]; - target = &v27ter_constellation[s->constellation_state]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - -#if defined(SPANDSP_USE_FIXED_POINT) - s->carrier_track_i = 400 + (200000 - 400)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN; - s->carrier_track_p = 1000000 + (10000000 - 1000000)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN; -#else - s->carrier_track_i = 400.0f + (200000.0f - 400.0f)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN; - s->carrier_track_p = 1000000.0f + (10000000.0f - 1000000.0f)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN; -#endif - if (++s->training_count >= V27TER_TRAINING_SEG_5_LEN) - { - s->constellation_state = (s->bit_rate == 4800) ? 4 : 2; - s->training_count = 0; - s->training_stage = TRAINING_STAGE_TEST_ONES; - } - break; - case TRAINING_STAGE_TEST_ONES: - decode_baud(s, &z); - constellation_state = (s->bit_rate == 4800) ? s->constellation_state : (s->constellation_state << 1); - target = &v27ter_constellation[constellation_state]; - /* Measure the training error */ -#if defined(SPANDSP_USE_FIXED_POINT) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error += powerf(&zz); -#endif - if (++s->training_count >= V27TER_TRAINING_SEG_6_LEN) - { - /* At 4800bps the symbols are 1.08238 (Euclidian) apart. - At 2400bps the symbols are 2.0 (Euclidian) apart. */ - if ((s->bit_rate == 4800 && s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.25f)) - || - (s->bit_rate == 2400 && s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.5f))) - { -#if defined(SPANDSP_USE_FIXED_POINT) - span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error); -#else - 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 */ - report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); - /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through - the processing. */ - s->signal_present = (s->bit_rate == 4800) ? 90 : 120; - s->training_stage = TRAINING_STAGE_NORMAL_OPERATION; - equalizer_save(s); - s->carrier_phase_rate_save = s->carrier_phase_rate; - s->agc_scaling_save = s->agc_scaling; - } - else - { - /* Training has failed */ -#if defined(SPANDSP_USE_FIXED_POINT) - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error); -#endif - /* Park this modem */ - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - } - break; - case TRAINING_STAGE_PARKED: - default: - /* We failed to train! */ - /* Park here until the carrier drops. */ - target = &zero; - break; - } - if (s->qam_report) - { -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t zi; - complexi16_t targeti; - - zi.re = z.re*1024.0f; - zi.im = z.im*1024.0f; - targeti.re = target->re*1024.0f; - targeti.im = target->im*1024.0f; - s->qam_report(s->qam_user_data, &zi, &targeti, s->constellation_state); -#else - s->qam_report(s->qam_user_data, &z, target, s->constellation_state); -#endif - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int signal_detect(v27ter_rx_state_t *s, int16_t amp) -{ - int16_t diff; - int16_t x; - int32_t power; - - /* There should be no DC in the signal, but sometimes there is. - We need to measure the power with the DC blocked, but not using - a slow to respond DC blocker. Use the most elementary HPF. */ - x = amp >> 1; - /* There could be overflow here, but it isn't a problem in practice */ - diff = x - s->last_sample; - s->last_sample = x; - power = power_meter_update(&s->power, diff); -#if defined(IAXMODEM_STUFF) - /* Quick power drop fudge */ - diff = abs(diff); - if (10*diff < s->high_sample) - { - if (++s->low_samples > 120) - { - power_meter_init(&s->power, 4); - s->high_sample = 0; - s->low_samples = 0; - } - } - else - { - s->low_samples = 0; - if (diff > s->high_sample) - s->high_sample = diff; - } -#endif - //span_log(&s->logging, SPAN_LOG_FLOW, "Power = %f\n", power_meter_current_dbm0(&s->power)); - if (s->signal_present > 0) - { - /* Look for power below turn-off threshold to turn the carrier off */ -#if defined(IAXMODEM_STUFF) - if (s->carrier_drop_pending || power < s->carrier_off_power) -#else - if (power < s->carrier_off_power) -#endif - { - if (--s->signal_present <= 0) - { - /* Count down a short delay, to ensure we push the last - few bits through the filters before stopping. */ - v27ter_rx_restart(s, s->bit_rate, false); - report_status_change(s, 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; -#endif - } - } - else - { - /* Look for power exceeding turn-on threshold to turn the carrier on */ - if (power < s->carrier_on_power) - return 0; - s->signal_present = 1; -#if defined(IAXMODEM_STUFF) - s->carrier_drop_pending = false; -#endif - report_status_change(s, SIG_STATUS_CARRIER_UP); - } - return power; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len) -{ - int i; - int step; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t z; - complexi16_t zz; - complexi16_t sample; - int32_t v; -#else - complexf_t z; - complexf_t zz; - complexf_t sample; - float v; -#endif - int32_t root_power; - int32_t power; - - if (s->bit_rate == 4800) - { - for (i = 0; i < len; i++) - { - s->rrc_filter[s->rrc_filter_step] = amp[i]; - if (++s->rrc_filter_step >= V27TER_RX_4800_FILTER_STEPS) - s->rrc_filter_step = 0; - - if ((power = signal_detect(s, amp[i])) == 0) - continue; - /* Only spend effort processing this data if the modem is not - parked, after training failure. */ - if (s->training_stage == TRAINING_STAGE_PARKED) - continue; - - /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm - will fiddle the step to align this with the symbols. */ - if ((s->eq_put_step -= RX_PULSESHAPER_4800_COEFF_SETS) <= 0) - { - if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION) - { - /* Only AGC during the initial training */ - if ((root_power = fixed_sqrt32(power)) == 0) - root_power = 1; -#if defined(SPANDSP_USE_FIXED_POINT) - s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.414f)*1024.0f))/root_power); -#else - s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_4800_GAIN)/root_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. */ - step = -s->eq_put_step; - if (step > RX_PULSESHAPER_4800_COEFF_SETS - 1) - step = RX_PULSESHAPER_4800_COEFF_SETS - 1; -#if defined(SPANDSP_USE_FIXED_POINT) - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - sample.re = (v*s->agc_scaling) >> 10; - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - sample.im = (v*s->agc_scaling) >> 10; - z = dds_lookup_complexi16(s->carrier_phase); - zz.re = ((int32_t) sample.re*z.re - (int32_t) sample.im*z.im) >> 15; - zz.im = ((int32_t) -sample.re*z.im - (int32_t) sample.im*z.re) >> 15; -#else - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step); - sample.re = v*s->agc_scaling; - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_4800_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step); - sample.im = v*s->agc_scaling; - z = dds_lookup_complexf(s->carrier_phase); - zz.re = sample.re*z.re - sample.im*z.im; - zz.im = -sample.re*z.im - sample.im*z.re; -#endif - s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2; - process_half_baud(s, &zz); - } -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - } - } - else - { - for (i = 0; i < len; i++) - { - s->rrc_filter[s->rrc_filter_step] = amp[i]; - if (++s->rrc_filter_step >= V27TER_RX_2400_FILTER_STEPS) - s->rrc_filter_step = 0; - - if ((power = signal_detect(s, amp[i])) == 0) - continue; - /* Only spend effort processing this data if the modem is not - parked, after training failure. */ - if (s->training_stage == TRAINING_STAGE_PARKED) - continue; - - /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm - will fiddle the step to align this with the symbols. */ - if ((s->eq_put_step -= RX_PULSESHAPER_2400_COEFF_SETS) <= 0) - { - if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION) - { - /* Only AGC during the initial training */ - if ((root_power = fixed_sqrt32(power)) == 0) - root_power = 1; -#if defined(SPANDSP_USE_FIXED_POINT) - s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.414f)*1024.0f))/root_power); -#else - s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_2400_GAIN)/root_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 bandband by complex mixing. - No further filtering, to remove mixer harmonics, is needed. */ - step = -s->eq_put_step; - if (step > RX_PULSESHAPER_2400_COEFF_SETS - 1) - step = RX_PULSESHAPER_2400_COEFF_SETS - 1; -#if defined(SPANDSP_USE_FIXED_POINT) - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - sample.re = (v*s->agc_scaling) >> 10; - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - sample.im = (v*s->agc_scaling) >> 10; - z = dds_lookup_complexi16(s->carrier_phase); - zz.re = ((int32_t) sample.re*z.re - (int32_t) sample.im*z.im) >> 15; - zz.im = ((int32_t) -sample.re*z.im - (int32_t) sample.im*z.re) >> 15; -#else - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step); - sample.re = v*s->agc_scaling; - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_2400_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step); - sample.im = v*s->agc_scaling; - z = dds_lookup_complexf(s->carrier_phase); - zz.re = sample.re*z.re - sample.im*z.im; - zz.im = -sample.re*z.im - sample.im*z.re; -#endif - s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2); - process_half_baud(s, &zz); - } -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len) -{ - int i; - - /* We want to sustain the current state (i.e carrier on<->carrier off), and - try to sustain the carrier phase. We should probably push the filters, as well */ - span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len); - if (s->signal_present <= 0) - return 0; - if (s->training_stage == TRAINING_STAGE_PARKED) - return 0; - for (i = 0; i < len; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - /* Advance the symbol phase the appropriate amount */ - if (s->bit_rate == 4800) - { - if ((s->eq_put_step -= RX_PULSESHAPER_4800_COEFF_SETS) <= 0) - s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2; - } - else - { - if ((s->eq_put_step -= RX_PULSESHAPER_2400_COEFF_SETS) <= 0) - s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2); - } - /* TODO: Should we rotate any buffers */ - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t put_bit, void *user_data) -{ - s->put_bit = put_bit; - s->put_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v27ter_rx_get_logging_state(v27ter_rx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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) - return -1; - s->bit_rate = bit_rate; - -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); -#else - vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); -#endif - s->training_error = FP_CONSTELLATION_SCALE(0.0f); - s->rrc_filter_step = 0; - - s->scramble_reg = 0x3C; - s->scrambler_pattern_count = 0; - s->training_stage = TRAINING_STAGE_SYMBOL_ACQUISITION; - s->training_bc = 0; - s->training_count = 0; - s->signal_present = 0; -#if defined(IAXMODEM_STUFF) - s->high_sample = 0; - s->low_samples = 0; - s->carrier_drop_pending = false; -#endif - vec_zeroi32(s->diff_angles, 16); - - s->carrier_phase = 0; -#if defined(SPANDSP_USE_FIXED_POINT) - s->carrier_track_i = 200000; - s->carrier_track_p = 10000000; -#else - s->carrier_track_i = 200000.0f; - s->carrier_track_p = 10000000.0f; -#endif - power_meter_init(&s->power, 4); - - s->constellation_state = 0; - - if (s->old_train) - { - s->carrier_phase_rate = s->carrier_phase_rate_save; - s->agc_scaling = s->agc_scaling_save; - equalizer_restore(s); - } - else - { - s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ); -#if defined(SPANDSP_USE_FIXED_POINT) - s->agc_scaling = (float) FP_SCALE(1.414f)*1024.0f/283.0f; -#else - s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_4800_GAIN)/283.0f; -#endif - equalizer_reset(s); - } - s->eq_skip = 0; - s->last_sample = 0; - - s->gardner_integrate = 0; - s->total_baud_timing_correction = 0; - s->gardner_step = 512; - s->baud_half = 0; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v27ter_rx_state_t *) v27ter_rx_init(v27ter_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data) -{ - switch (bit_rate) - { - case 4800: - case 2400: - break; - default: - return NULL; - } - if (s == NULL) - { - if ((s = (v27ter_rx_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, "V.27ter RX"); - v27ter_rx_signal_cutoff(s, -45.5f); - s->put_bit = put_bit; - s->put_bit_user_data = user_data; - - v27ter_rx_restart(s, bit_rate, false); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_rx_release(v27ter_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_rx_free(v27ter_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_rx_set_qam_report_handler(v27ter_rx_state_t *s, qam_report_handler_t handler, void *user_data) -{ - s->qam_report = handler; - s->qam_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v27ter_tx.c b/libs/spandsp/src/v27ter_tx.c deleted file mode 100644 index e0f2aaf1af..0000000000 --- a/libs/spandsp/src/v27ter_tx.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v27ter_tx.c - ITU V.27ter modem transmit part - * - * 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 */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/dds.h" -#include "spandsp/power_meter.h" - -#include "spandsp/v27ter_tx.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/v27ter_tx.h" - -#if defined(SPANDSP_USE_FIXED_POINT) -#define FP_SCALE(x) FP_Q6_10(x) -#else -#define FP_SCALE(x) (x) -#endif - -#include "v27ter_tx_4800_rrc.h" -#include "v27ter_tx_2400_rrc.h" - -/*! The nominal frequency of the carrier, in Hertz */ -#define CARRIER_NOMINAL_FREQ 1800.0f - -/* Segments of the training sequence */ -/* V.27ter defines a long and a short sequence. FAX doesn't use the - short sequence, so it is not implemented here. */ -/*! The start of training segment 1, in symbols */ -#define V27TER_TRAINING_SEG_1 0 -/*! The start of training segment 2, in symbols */ -#define V27TER_TRAINING_SEG_2 (V27TER_TRAINING_SEG_1 + 320) -/*! The start of training segment 3, in symbols */ -#define V27TER_TRAINING_SEG_3 (V27TER_TRAINING_SEG_2 + 32) -/*! The start of training segment 4, in symbols */ -#define V27TER_TRAINING_SEG_4 (V27TER_TRAINING_SEG_3 + 50) -/*! The start of training segment 5, in symbols */ -#define V27TER_TRAINING_SEG_5 (V27TER_TRAINING_SEG_4 + 1074) -/*! The end of the training, in symbols */ -#define V27TER_TRAINING_END (V27TER_TRAINING_SEG_5 + 8) -/*! The end of the shutdown sequence, in symbols */ -#define V27TER_TRAINING_SHUTDOWN_END (V27TER_TRAINING_END + 32) - -static int fake_get_bit(void *user_data) -{ - return 1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int scramble(v27ter_tx_state_t *s, int in_bit) -{ - int out_bit; - - /* This scrambler is really quite messy to implement. There seems to be no efficient shortcut */ - out_bit = (in_bit ^ (s->scramble_reg >> 5) ^ (s->scramble_reg >> 6)) & 1; - if (s->scrambler_pattern_count >= 33) - { - out_bit ^= 1; - s->scrambler_pattern_count = 0; - } - else - { - if ((((s->scramble_reg >> 7) ^ out_bit) & ((s->scramble_reg >> 8) ^ out_bit) & ((s->scramble_reg >> 11) ^ out_bit) & 1)) - s->scrambler_pattern_count = 0; - else - s->scrambler_pattern_count++; - } - s->scramble_reg = (s->scramble_reg << 1) | out_bit; - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int get_scrambled_bit(v27ter_tx_state_t *s) -{ - int bit; - - if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA) - { - /* End of real data. Switch to the fake get_bit routine, until we - have shut down completely. */ - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); - s->current_get_bit = fake_get_bit; - s->in_training = true; - bit = 1; - } - return scramble(s, bit); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static complexi16_t getbaud(v27ter_tx_state_t *s) -#else -static complexf_t getbaud(v27ter_tx_state_t *s) -#endif -{ - static const int phase_steps_4800[8] = - { - 1, 0, 2, 3, 6, 7, 5, 4 - }; - static const int phase_steps_2400[4] = - { - 0, 2, 6, 4 - }; -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t zero = {0, 0}; - static const complexi16_t constellation[8] = -#else - static const complexf_t zero = {0.0f, 0.0f}; - static const complexf_t constellation[8] = -#endif - { - {FP_SCALE( 1.414f), FP_SCALE( 0.0f)}, /* 0deg */ - {FP_SCALE( 1.0f), FP_SCALE( 1.0f)}, /* 45deg */ - {FP_SCALE( 0.0f), FP_SCALE( 1.414f)}, /* 90deg */ - {FP_SCALE(-1.0f), FP_SCALE( 1.0f)}, /* 135deg */ - {FP_SCALE(-1.414f), FP_SCALE( 0.0f)}, /* 180deg */ - {FP_SCALE(-1.0f), FP_SCALE(-1.0f)}, /* 225deg */ - {FP_SCALE( 0.0f), FP_SCALE(-1.414f)}, /* 270deg */ - {FP_SCALE( 1.0f), FP_SCALE(-1.0f)} /* 315deg */ - }; - int bits; - - if (s->in_training) - { - /* Send the training sequence */ - if (++s->training_step <= V27TER_TRAINING_SEG_5) - { - if (s->training_step <= V27TER_TRAINING_SEG_4) - { - if (s->training_step <= V27TER_TRAINING_SEG_2) - { - /* Segment 1: Unmodulated carrier (talker echo protection) */ - return constellation[0]; - } - if (s->training_step <= V27TER_TRAINING_SEG_3) - { - /* Segment 2: Silence */ - return zero; - } - /* Segment 3: Regular reversals... */ - s->constellation_state = (s->constellation_state + 4) & 7; - return constellation[s->constellation_state]; - } - /* Segment 4: Scrambled reversals... */ - /* Apply the 1 + x^-6 + x^-7 scrambler. We want every third - bit from the scrambler. */ - bits = get_scrambled_bit(s) << 2; - get_scrambled_bit(s); - get_scrambled_bit(s); - s->constellation_state = (s->constellation_state + bits) & 7; - return constellation[s->constellation_state]; - } - /* We should be in the block of test ones, or shutdown ones, if we get here. */ - /* There is no graceful shutdown procedure defined for V.27ter. Just - send some ones, to ensure we get the real data bits through, even - with bad ISI. */ - if (s->training_step == V27TER_TRAINING_END + 1) - { - /* End of the last segment - segment 5: All ones */ - /* 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; - } - if (s->training_step == V27TER_TRAINING_SHUTDOWN_END) - { - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE); - } - } - /* 4800bps uses 8 phases. 2400bps uses 4 phases. */ - if (s->bit_rate == 4800) - { - bits = get_scrambled_bit(s); - bits = (bits << 1) | get_scrambled_bit(s); - bits = (bits << 1) | get_scrambled_bit(s); - bits = phase_steps_4800[bits]; - } - else - { - bits = get_scrambled_bit(s); - bits = (bits << 1) | get_scrambled_bit(s); - bits = phase_steps_2400[bits]; - } - s->constellation_state = (s->constellation_state + bits) & 7; - return constellation[s->constellation_state]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t v; - complexi32_t x; - complexi32_t z; - int16_t iamp; -#else - complexf_t v; - complexf_t x; - complexf_t z; - float famp; -#endif - int sample; - - if (s->training_step >= V27TER_TRAINING_SHUTDOWN_END) - { - /* Once we have sent the shutdown symbols, we stop sending completely. */ - return 0; - } - /* The symbol rates for the two bit rates are different. This makes it difficult to - merge both generation procedures into a single efficient loop. We do not bother - trying. We use two independent loops, filter coefficients, etc. */ - if (s->bit_rate == 4800) - { - for (sample = 0; sample < len; sample++) - { - if (++s->baud_phase >= 5) - { - s->baud_phase -= 5; - v = getbaud(s);; - s->rrc_filter_re[s->rrc_filter_step] = v.re; - s->rrc_filter_im[s->rrc_filter_step] = v.im; - if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS) - s->rrc_filter_step = 0; - } -#if defined(SPANDSP_USE_FIXED_POINT) - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4); - x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4); - /* Now create and modulate the carrier */ - z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate); - iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) (((int32_t) iamp*s->gain_4800) >> 11); -#else - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step); - x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step); - /* Now create and modulate the carrier */ - z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate); - famp = x.re*z.re - x.im*z.im; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) lfastrintf(famp*s->gain_4800); -#endif - } - } - else - { - for (sample = 0; sample < len; sample++) - { - if ((s->baud_phase += 3) >= 20) - { - s->baud_phase -= 20; - v = getbaud(s); - s->rrc_filter_re[s->rrc_filter_step] = v.re; - s->rrc_filter_im[s->rrc_filter_step] = v.im; - if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS) - s->rrc_filter_step = 0; - } -#if defined(SPANDSP_USE_FIXED_POINT) - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4); - x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4); - /* Now create and modulate the carrier */ - z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate); - iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) (((int32_t) iamp*s->gain_2400) >> 11); -#else - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step); - x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step); - /* Now create and modulate the carrier */ - z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate); - famp = x.re*z.re - x.im*z.im; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) lfastrintf(famp*s->gain_2400); -#endif - } - } - return sample; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_tx_power(v27ter_tx_state_t *s, float power) -{ - float gain; - - gain = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f; -#if defined(SPANDSP_USE_FIXED_POINT) - s->gain_2400 = (int16_t) (gain/TX_PULSESHAPER_2400_GAIN); - s->gain_4800 = (int16_t) (gain/TX_PULSESHAPER_4800_GAIN); -#else - s->gain_2400 = gain/TX_PULSESHAPER_2400_GAIN; - s->gain_4800 = gain/TX_PULSESHAPER_4800_GAIN; -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t get_bit, void *user_data) -{ - if (s->get_bit == s->current_get_bit) - s->current_get_bit = get_bit; - s->get_bit = get_bit; - s->get_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v27ter_tx_get_logging_state(v27ter_tx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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; - s->bit_rate = bit_rate; -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0])); - vec_zeroi16(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0])); -#else - vec_zerof(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0])); - vec_zerof(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0])); -#endif - s->rrc_filter_step = 0; - s->scramble_reg = 0x3C; - s->scrambler_pattern_count = 0; - s->in_training = true; - s->training_step = (tep) ? V27TER_TRAINING_SEG_1 : V27TER_TRAINING_SEG_2; - s->carrier_phase = 0; - s->baud_phase = 0; - s->constellation_state = 0; - s->current_get_bit = fake_get_bit; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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) - { - case 4800: - case 2400: - break; - default: - return NULL; - } - if (s == NULL) - { - if ((s = (v27ter_tx_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, "V.27ter TX"); - s->get_bit = get_bit; - s->get_bit_user_data = user_data; - s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); - v27ter_tx_power(s, -14.0f); - v27ter_tx_restart(s, bit_rate, tep); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_tx_release(v27ter_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v27ter_tx_free(v27ter_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c deleted file mode 100644 index 4bed319246..0000000000 --- a/libs/spandsp/src/v29rx.c +++ /dev/null @@ -1,1217 +0,0 @@ -#define IAXMODEM_STUFF -/* - * SpanDSP - a series of DSP components for telephony - * - * v29rx.c - ITU V.29 modem receive part - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "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" -#include "spandsp/saturated.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/power_meter.h" -#include "spandsp/arctan2.h" -#include "spandsp/dds.h" -#include "spandsp/complex_filters.h" - -#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) -#define FP_SCALE(x) FP_Q4_12(x) -#define FP_FACTOR 4096 -#define FP_SHIFT_FACTOR 12 -#else -#define FP_SCALE(x) (x) -#endif - -#if defined(SPANDSP_USE_FIXED_POINT) -#define FP_SYNC_SCALE(x) FP_Q6_10(x) -#define FP_SYNC_SCALE_32(x) FP_Q22_10(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 "v29rx_rrc.h" -#include "v29tx_constellation_maps.h" - -/*! The nominal frequency of the carrier, in Hertz */ -#define CARRIER_NOMINAL_FREQ 1700.0f -/*! The nominal baud or symbol rate */ -#define BAUD_RATE 2400 -/*! The adaption rate coefficient for the equalizer */ -#define EQUALIZER_DELTA 0.21f - -/* Segments of the training sequence */ -/*! The length of training segment 2, in symbols */ -#define V29_TRAINING_SEG_2_LEN 128 -/*! The length of training segment 3, in symbols */ -#define V29_TRAINING_SEG_3_LEN 384 -/*! The length of training segment 4, in symbols */ -#define V29_TRAINING_SEG_4_LEN 48 - -/* 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.382683432f -#define COS_LOW_BAND_EDGE 0.923879533f -#define SIN_HIGH_BAND_EDGE 0.760405966f -#define COS_HIGH_BAND_EDGE -0.649448048f -#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, - TRAINING_STAGE_SYMBOL_ACQUISITION, - TRAINING_STAGE_LOG_PHASE, - TRAINING_STAGE_WAIT_FOR_CDCD, - TRAINING_STAGE_TRAIN_ON_CDCD, - TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST, - TRAINING_STAGE_TEST_ONES, - TRAINING_STAGE_PARKED -}; - -static const uint8_t space_map_9600[20][20] = -{ - /* Middle V Middle */ - {13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11}, - {13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11}, - {13, 13, 13, 13, 13, 13, 13, 4, 4, 4, 4, 4, 4, 11, 11, 11, 11, 11, 11, 11}, - {13, 13, 13, 13, 13, 13, 13, 4, 4, 4, 4, 4, 4, 11, 11, 11, 11, 11, 11, 11}, - {13, 13, 13, 13, 13, 13, 13, 4, 4, 4, 4, 4, 4, 11, 11, 11, 11, 11, 11, 11}, - {13, 13, 13, 13, 13, 13, 13, 5, 4, 4, 4, 4, 3, 11, 11, 11, 11, 11, 11, 11}, - {14, 13, 13, 13, 13, 13, 5, 5, 5, 5, 3, 3, 3, 3, 11, 11, 11, 11, 11, 10}, - {14, 14, 6, 6, 6, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 2, 2, 2, 10, 10}, - {14, 14, 6, 6, 6, 6, 5, 5, 5, 5, 3, 3, 3, 3, 2, 2, 2, 2, 10, 10}, - {14, 14, 6, 6, 6, 6, 5, 5, 5, 5, 3, 3, 3, 3, 2, 2, 2, 2, 10, 10}, /* << Middle */ - {14, 14, 6, 6, 6, 6, 7, 7, 7, 7, 1, 1, 1, 1, 2, 2, 2, 2, 10, 10}, /* << Middle */ - {14, 14, 6, 6, 6, 6, 7, 7, 7, 7, 1, 1, 1, 1, 2, 2, 2, 2, 10, 10}, - {14, 14, 6, 6, 6, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 2, 2, 2, 10, 10}, - {14, 15, 15, 15, 15, 15, 7, 7, 7, 7, 1, 1, 1, 1, 9, 9, 9, 9, 9, 10}, - {15, 15, 15, 15, 15, 15, 15, 7, 0, 0, 0, 0, 1, 9, 9, 9, 9, 9, 9, 9}, - {15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9}, - {15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9}, - {15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9}, - {15, 15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9}, - {15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9} - /* Middle ^ Middle */ -}; - -SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s) -{ - return dds_frequencyf(s->carrier_phase_rate); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v29_rx_symbol_timing_correction(v29_rx_state_t *s) -{ - return (float) s->total_baud_timing_correction/((float) RX_PULSESHAPER_COEFF_SETS*10.0f/3.0f); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(float) v29_rx_signal_power(v29_rx_state_t *s) -{ - return power_meter_current_dbm0(&s->power) + 3.98f; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_rx_signal_cutoff(v29_rx_state_t *s, float cutoff) -{ - /* The 0.4 factor allows for the gain of the DC blocker */ - s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f); - s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f); -} -/*- End of function --------------------------------------------------------*/ - -static void report_status_change(v29_rx_state_t *s, int status) -{ - if (s->status_handler) - s->status_handler(s->status_user_data, status); - else if (s->put_bit) - s->put_bit(s->put_bit_user_data, status); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -SPAN_DECLARE(int) v29_rx_equalizer_state(v29_rx_state_t *s, complexi16_t **coeffs) -#else -SPAN_DECLARE(int) v29_rx_equalizer_state(v29_rx_state_t *s, complexf_t **coeffs) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - *coeffs = NULL; - return 0; -#else - *coeffs = s->eq_coeff; - return V29_EQUALIZER_LEN; -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_save(v29_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_LEN); -#else - cvec_copyf(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_LEN); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_restore(v29_rx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_LEN); - cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN); - s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN; -#else - cvec_copyf(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_LEN); - cvec_zerof(s->eq_buf, V29_EQUALIZER_LEN); - s->eq_delta = EQUALIZER_DELTA/V29_EQUALIZER_LEN; -#endif - - s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1; - s->eq_step = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void equalizer_reset(v29_rx_state_t *s) -{ - /* Start with an equalizer based on everything being perfect */ -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)}; - - cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_LEN); - s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x; - cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN); - s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN; -#else - static const complexf_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)}; - - cvec_zerof(s->eq_coeff, V29_EQUALIZER_LEN); - s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x; - cvec_zerof(s->eq_buf, V29_EQUALIZER_LEN); - s->eq_delta = EQUALIZER_DELTA/V29_EQUALIZER_LEN; -#endif - - s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1; - s->eq_step = 0; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ complexi16_t equalizer_get(v29_rx_state_t *s) -{ - complexi32_t zz; - complexi16_t z; - - /* Get the next equalized value. */ - zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step); - z.re = zz.re >> FP_CONSTELLATION_SHIFT_FACTOR; - z.im = zz.im >> FP_CONSTELLATION_SHIFT_FACTOR; - return z; -} -#else -static __inline__ complexf_t equalizer_get(v29_rx_state_t *s) -{ - /* Get the next equalized value. */ - return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void tune_equalizer(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) -{ - complexi16_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subi16(target, z); - err.re = ((int32_t) err.re*s->eq_delta) >> 15; - err.im = ((int32_t) err.im*s->eq_delta) >> 15; - cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step, &err); -} -#else -static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target) -{ - complexf_t err; - - /* Find the x and y mismatch from the exact constellation position. */ - err = complex_subf(target, z); - err.re *= s->eq_delta; - err.im *= s->eq_delta; - cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step, &err); -} -#endif -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) -#else -static __inline__ void track_carrier(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target) -#endif -{ -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t error; -#else - float error; -#endif - - /* The initial coarse carrier frequency and phase estimation should have - got us in the right ballpark. Now we need to fine tune fairly quickly, - to get the receovered carrier more precisely on target. Then we need to - fine tune in a more damped way to keep us on target. The goal is to have - things running really well by the time the training is complete. - We assume the frequency of the oscillators at the two ends drift only - very slowly. The PSTN has rather limited doppler problems. :-) Any - remaining FDM in the network should also drift slowly. */ - /* For small errors the imaginary part of the difference between the actual and the target - positions is proportional to the phase error, for any particular target. However, the - different amplitudes of the various target positions scale things. This isn't all bad, - as the angular error for the larger amplitude constellation points is probably - a more reliable indicator, and we are weighting it as such. */ - /* Use a proportional-integral approach to tracking the carrier. The PI - parameters are coarser at first, until we get precisely on target. Then, - the filter will be damped more to keep us on target. */ -#if defined(SPANDSP_USE_FIXED_POINT) - error = (((int32_t) z->im*target->re) >> FP_SHIFT_FACTOR) - (((int32_t) z->re*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 - error = z->im*target->re - z->re*target->im; - s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error); - s->carrier_phase += (int32_t) (s->carrier_track_p*error); -#endif -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ int find_quadrant(const complexi16_t *z) -#else -static __inline__ int find_quadrant(const complexf_t *z) -#endif -{ - int b1; - int b2; - - /* Split the space along the two diagonals. */ - b1 = (z->im > z->re); - b2 = (z->im < -z->re); - return (b2 << 1) | (b1 ^ b2); -} -/*- End of function --------------------------------------------------------*/ - -static int scrambled_training_bit(v29_rx_state_t *s) -{ - int bit; - - /* Segment 3 of the training sequence - the scrambled CDCD part. */ - /* Apply the 1 + x^-6 + x^-7 scrambler */ - bit = s->training_scramble_reg & 1; - s->training_scramble_reg >>= 1; - if (bit ^ (s->training_scramble_reg & 1)) - s->training_scramble_reg |= 0x40; - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int descramble(v29_rx_state_t *s, int in_bit) -{ - int out_bit; - - /* Descramble the bit */ - in_bit &= 1; - out_bit = (in_bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1; - s->scramble_reg = (s->scramble_reg << 1) | in_bit; - - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void put_bit(v29_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) - { - s->put_bit(s->put_bit_user_data, out_bit); - } - else - { - /* 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. */ - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void decode_baud(v29_rx_state_t *s, complexi16_t *z) -#else -static void decode_baud(v29_rx_state_t *s, complexf_t *z) -#endif -{ - static const uint8_t phase_steps_9600[8] = - { - 4, 0, 2, 6, 7, 3, 1, 5 - }; - static const uint8_t phase_steps_4800[4] = - { - 0, 2, 3, 1 - }; - int nearest; - int raw_bits; - int i; - int re; - int im; - - if (s->bit_rate == 4800) - { - /* 4800 is a special case. */ - nearest = find_quadrant(z) << 1; - raw_bits = phase_steps_4800[((nearest - s->constellation_state) >> 1) & 3]; - put_bit(s, raw_bits); - put_bit(s, raw_bits >> 1); - } - else - { - /* 9600 and 7200 are quite similar. */ -#if defined(SPANDSP_USE_FIXED_POINT) - re = (z->re + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1); - im = (z->im + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1); -#else - re = (int) ((z->re + FP_CONSTELLATION_SCALE(5.0f))*2.0f); - im = (int) ((z->im + FP_CONSTELLATION_SCALE(5.0f))*2.0f); -#endif - if (re > 19) - re = 19; - else if (re < 0) - re = 0; - if (im > 19) - im = 19; - else if (im < 0) - im = 0; - nearest = space_map_9600[re][im]; - if (s->bit_rate == 9600) - { - /* Send out the top (amplitude) bit. */ - put_bit(s, nearest >> 3); - } - else - { - /* We can reuse the space map for 9600, but drop the top bit. */ - nearest &= 7; - } - raw_bits = phase_steps_9600[(nearest - s->constellation_state) & 7]; - for (i = 0; i < 3; i++) - { - put_bit(s, raw_bits); - raw_bits >>= 1; - } - } - - track_carrier(s, z, &v29_9600_constellation[nearest]); - if (--s->eq_skip <= 0) - { - /* Once we are in the data the equalization should not need updating. - However, the line characteristics may slowly drift. We, therefore, - tune up on the occassional sample, keeping the compute down. */ - s->eq_skip = 10; - tune_equalizer(s, z, &v29_9600_constellation[nearest]); - } - s->constellation_state = nearest; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void symbol_sync(v29_rx_state_t *s) -{ - int i; -#if defined(SPANDSP_USE_FIXED_POINT) - int32_t v; - int32_t p; -#else - float v; - float p; -#endif - - /* This routine adapts the position of the half baud samples entering the equalizer. */ - - /* This symbol sync scheme is based on the technique first described by Dominique Godard in - Passband Timing Recovery in an All-Digital Modem Receiver - IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */ - - /* This is slightly rearranged from figure 3b of the Godard paper, as this saves a couple of - maths operations */ -#if defined(SPANDSP_USE_FIXED_POINT) - /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */ - /* Cross correlate */ - v = (((s->symbol_sync_low[1] >> (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]; - s->symbol_sync_dc_filter[0] = v; - /* A little integration will now filter away much of the HF noise */ - s->baud_phase -= p; - v = labs(s->baud_phase); -#else - /* Cross correlate */ - v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2 - - s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2 - + s->symbol_sync_low[1]*s->symbol_sync_high[1]*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]; - s->symbol_sync_dc_filter[0] = v; - /* A little integration will now filter away much of the HF noise */ - s->baud_phase -= p; - v = fabsf(s->baud_phase); -#endif - if (v > FP_SYNC_SCALE_32(30.0f)) - { - i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 5 : 1; - if (s->baud_phase < FP_SYNC_SCALE_32(0.0f)) - i = -i; - s->eq_put_step += i; - s->total_baud_timing_correction += i; - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void process_half_baud(v29_rx_state_t *s, complexi16_t *sample) -#else -static void process_half_baud(v29_rx_state_t *s, complexf_t *sample) -#endif -{ - static const int cdcd_pos[6] = - { - 0, 11, - 0, 3, - 0, 2 - }; -#if defined(SPANDSP_USE_FIXED_POINT) - uint16_t ip; - complexi16_t z; - complexi16_t z16; - const complexi16_t *target; - static const complexi16_t zero = {FP_CONSTELLATION_SCALE(0.0f), FP_CONSTELLATION_SCALE(0.0f)}; -#else - float p; - complexf_t z; - complexf_t zz; - const complexf_t *target; - static const complexf_t zero = {FP_CONSTELLATION_SCALE(0.0f), FP_CONSTELLATION_SCALE(0.0f)}; -#endif - int bit; - int i; - int j; - int32_t angle; - int32_t ang; - - /* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate. */ - - /* Add a sample to the equalizer's circular buffer, but don't calculate anything at this time. */ - s->eq_buf[s->eq_step] = *sample; - if (++s->eq_step >= V29_EQUALIZER_LEN) - s->eq_step = 0; - - /* On alternate insertions we have a whole baud, and must process it. */ - if ((s->baud_half ^= 1)) - return; - - /* Symbol timing synchronisation */ - symbol_sync(s); - - z = equalizer_get(s); - - switch (s->training_stage) - { - case TRAINING_STAGE_NORMAL_OPERATION: - /* Normal operation. */ - decode_baud(s, &z); - target = &v29_9600_constellation[s->constellation_state]; - break; - case TRAINING_STAGE_SYMBOL_ACQUISITION: - /* Allow time for symbol synchronisation to settle the symbol timing. */ - target = &zero; - if (++s->training_count >= 60) - { - /* Record the current phase angle */ - s->training_stage = TRAINING_STAGE_LOG_PHASE; - vec_zeroi32(s->diff_angles, 16); - s->last_angles[0] = arctan2(z.im, z.re); - if (s->agc_scaling_save == FP_SCALE(0.0f)) - { -#if defined(SPANDSP_USE_FIXED_POINT) - span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %d\n", s->agc_scaling); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %f\n", s->agc_scaling); -#endif - s->agc_scaling_save = s->agc_scaling; - } - } - break; - case TRAINING_STAGE_LOG_PHASE: - /* Record the current alternate phase angle */ - target = &zero; - s->last_angles[1] = arctan2(z.im, z.re); - s->training_count = 1; - s->training_stage = TRAINING_STAGE_WAIT_FOR_CDCD; - break; - case TRAINING_STAGE_WAIT_FOR_CDCD: - target = &zero; - angle = arctan2(z.im, z.re); - /* Look for the initial ABAB sequence to display a phase reversal, which will - signal the start of the scrambled CDCD segment */ - i = s->training_count + 1; - ang = angle - s->last_angles[i & 1]; - s->last_angles[i & 1] = angle; - s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4); - if ((ang > DDS_PHASE(45.0f) || ang < DDS_PHASE(-45.0f)) && s->training_count >= 13) - { - /* We seem to have a phase reversal */ - /* Slam the carrier frequency into line, based on the total phase drift over the last - section. Use the shift from the odd bits and the shift from the even bits to get - better jitter suppression. We need to scale here, or at the maximum specified - frequency deviation we could overflow, and get a silly answer. */ - /* Step back a few symbols so we don't get ISI distorting things. */ - i = (s->training_count - 8) & ~1; - /* Avoid the possibility of a divide by zero */ - if (i > 1) - { - j = i & 0xF; - ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1); - s->carrier_phase_rate += 3*16*(ang/20); - } - span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f\n", dds_frequencyf(s->carrier_phase_rate)); - /* Check if the carrier frequency is plausible */ - if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f) - || - s->carrier_phase_rate > DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ + 20.0f)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); - /* Park this modem */ - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - break; - } - /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer - buffer, as well as the carrier phase, for this to play out nicely. */ -#if defined(SPANDSP_USE_FIXED_POINT) - ip = angle >> 16; - span_log(&s->logging, SPAN_LOG_FLOW, "Spin by %d\n", ip); - z16 = complex_seti16(fixed_cos(ip), -fixed_sin(ip)); - for (i = 0; i < V29_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mul_q1_15(&s->eq_buf[i], &z16); -#else - p = dds_phase_to_radians(angle); - span_log(&s->logging, SPAN_LOG_FLOW, "Spin by %.5f rads\n", p); - zz = complex_setf(cosf(p), -sinf(p)); - for (i = 0; i < V29_EQUALIZER_LEN; i++) - s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz); -#endif - s->carrier_phase += angle; - /* We have just seen the first bit of the scrambled sequence, so skip it. */ - bit = scrambled_training_bit(s); - s->constellation_state = cdcd_pos[s->training_cd + bit]; - target = &v29_9600_constellation[s->constellation_state]; - s->training_count = 1; - s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD; - report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS); - break; - } - if (++s->training_count > V29_TRAINING_SEG_2_LEN) - { - /* This is bogus. There are not this many bauds in this section - of a real training sequence. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); - /* Park this modem */ - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - break; - case TRAINING_STAGE_TRAIN_ON_CDCD: - /* Train on the scrambled CDCD section. */ - bit = scrambled_training_bit(s); - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f %15.5f, %15.5f\n", s->training_count, z.re, z.im, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].re, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].im); - s->constellation_state = cdcd_pos[s->training_cd + bit]; - target = &v29_9600_constellation[s->constellation_state]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - if (++s->training_count >= V29_TRAINING_SEG_3_LEN - 48) - { - s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST; - s->training_error = FP_CONSTELLATION_SCALE(0.0f); -#if defined(SPANDSP_USE_FIXED_POINT) - s->carrier_track_i = 200; - s->carrier_track_p = 1000000; -#else - s->carrier_track_i = 200.0f; - s->carrier_track_p = 1000000.0f; -#endif - } - break; - case TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST: - /* Continue training on the scrambled CDCD section, but measure the quality of training too. */ - bit = scrambled_training_bit(s); - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f %15.5f, %15.5f\n", s->training_count, z.re, z.im, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].re, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].im); - s->constellation_state = cdcd_pos[s->training_cd + bit]; - target = &v29_9600_constellation[s->constellation_state]; - track_carrier(s, &z, target); - tune_equalizer(s, &z, target); - /* Measure the training error */ -#if defined(SPANDSP_USE_FIXED_POINT) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error += powerf(&zz); -#endif - if (++s->training_count >= V29_TRAINING_SEG_3_LEN) - { -#if defined(SPANDSP_USE_FIXED_POINT) - span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %d\n", s->training_error); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %f\n", s->training_error); -#endif - if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(2.0f)) - { - s->training_error = FP_CONSTELLATION_SCALE(0.0f); - s->training_count = 0; - s->constellation_state = 0; - s->training_stage = TRAINING_STAGE_TEST_ONES; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n"); - /* Park this modem */ - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - } - break; - case TRAINING_STAGE_TEST_ONES: - /* We are in the test phase, where we check that we can receive reliably. - We should get a run of 1's, 48 symbols (192 bits at 9600bps) long. */ - //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f\n", s->training_count, z.re, z.im); - decode_baud(s, &z); - target = &v29_9600_constellation[s->constellation_state]; - /* Measure the training error */ -#if defined(SPANDSP_USE_FIXED_POINT) - z16 = complex_subi16(&z, target); - s->training_error += poweri16(&z16); -#else - zz = complex_subf(&z, target); - s->training_error += powerf(&zz); -#endif - if (++s->training_count >= V29_TRAINING_SEG_4_LEN) - { - if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(1.0f)) - { - /* We are up and running */ -#if defined(SPANDSP_USE_FIXED_POINT) - span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error); -#endif - report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); - /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through - the processing. */ - s->signal_present = 60; - s->training_stage = TRAINING_STAGE_NORMAL_OPERATION; - equalizer_save(s); - s->carrier_phase_rate_save = s->carrier_phase_rate; - s->agc_scaling_save = s->agc_scaling; - } - else - { - /* Training has failed. Park this modem */ -#if defined(SPANDSP_USE_FIXED_POINT) - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error); -#else - span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error); -#endif - s->agc_scaling_save = FP_SCALE(0.0f); - s->training_stage = TRAINING_STAGE_PARKED; - report_status_change(s, SIG_STATUS_TRAINING_FAILED); - } - } - break; - case TRAINING_STAGE_PARKED: - default: - /* We failed to train! */ - /* Park here until the carrier drops. */ - target = &zero; - break; - } - if (s->qam_report) - { -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t zi; - complexi16_t targeti; - - zi.re = z.re*1024.0f; - zi.im = z.im*1024.0f; - targeti.re = target->re*1024.0f; - targeti.im = target->im*1024.0f; - s->qam_report(s->qam_user_data, &zi, &targeti, s->constellation_state); -#else - s->qam_report(s->qam_user_data, &z, target, s->constellation_state); -#endif - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp) -{ - int16_t diff; - int16_t x; - int32_t power; - - /* There should be no DC in the signal, but sometimes there is. - We need to measure the power with the DC blocked, but not using - a slow to respond DC blocker. Use the most elementary HPF. */ - x = amp >> 1; - /* There could be overflow here, but it isn't a problem in practice */ - diff = x - s->last_sample; - s->last_sample = x; - power = power_meter_update(&s->power, diff); -#if defined(IAXMODEM_STUFF) - /* Quick power drop fudge */ - diff = abs(diff); - if (10*diff < s->high_sample) - { - if (++s->low_samples > 120) - { - power_meter_init(&s->power, 4); - s->high_sample = 0; - s->low_samples = 0; - } - } - else - { - s->low_samples = 0; - if (diff > s->high_sample) - s->high_sample = diff; - } -#endif - if (s->signal_present > 0) - { - /* Look for power below turn-off threshold to turn the carrier off */ -#if defined(IAXMODEM_STUFF) - if (s->carrier_drop_pending || power < s->carrier_off_power) -#else - if (power < s->carrier_off_power) -#endif - { - if (--s->signal_present <= 0) - { - /* Count down a short delay, to ensure we push the last - few bits through the filters before stopping. */ - v29_rx_restart(s, s->bit_rate, false); - report_status_change(s, 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; -#endif - } - } - else - { - /* Look for power exceeding turn-on threshold to turn the carrier on */ - if (power < s->carrier_on_power) - return 0; - s->signal_present = 1; -#if defined(IAXMODEM_STUFF) - s->carrier_drop_pending = false; -#endif - report_status_change(s, SIG_STATUS_CARRIER_UP); - } - return power; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len) -{ - int i; - int step; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t z; - complexi16_t zz; - complexi16_t sample; - int32_t v; -#else - complexf_t z; - complexf_t zz; - complexf_t sample; - float v; -#endif - int32_t root_power; - int32_t power; - - for (i = 0; i < len; i++) - { - s->rrc_filter[s->rrc_filter_step] = amp[i]; - if (++s->rrc_filter_step >= V29_RX_FILTER_STEPS) - s->rrc_filter_step = 0; - - if ((power = signal_detect(s, amp[i])) == 0) - continue; - if (s->training_stage == TRAINING_STAGE_PARKED) - continue; - /* Only spend effort processing this data if the modem is not - parked, after training failure. */ - s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS; - step = -s->eq_put_step; - if (step < 0) - step += RX_PULSESHAPER_COEFF_SETS; - if (step < 0) - step = 0; - else if (step > RX_PULSESHAPER_COEFF_SETS - 1) - step = RX_PULSESHAPER_COEFF_SETS - 1; -#if defined(SPANDSP_USE_FIXED_POINT) - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - 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) >> 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) >> 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 - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step); - sample.re = v*s->agc_scaling; - /* Symbol timing synchronisation band edge filters */ - /* Low Nyquist band edge filter */ - v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0 - + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1 - + sample.re; - s->symbol_sync_low[1] = s->symbol_sync_low[0]; - s->symbol_sync_low[0] = v; - /* High Nyquist band edge filter */ - v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0 - + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1 - + sample.re; - s->symbol_sync_high[1] = s->symbol_sync_high[0]; - s->symbol_sync_high[0] = v; -#endif - /* Put things into the equalization buffer at T/2 rate. The symbol synchronisation - will fiddle the step to align this with the symbols. */ - if (s->eq_put_step <= 0) - { - /* Only AGC until we have locked down the setting. */ - if (s->agc_scaling_save == FP_SCALE(0.0f)) - { - if ((root_power = fixed_sqrt32(power)) == 0) - root_power = 1; -#if defined(SPANDSP_USE_FIXED_POINT) - s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.25f)*1024.0f))/root_power); -#else - s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/root_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. */ -#if defined(SPANDSP_USE_FIXED_POINT) - v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; - sample.im = (v*s->agc_scaling) >> 10; - z = dds_lookup_complexi16(s->carrier_phase); - zz.re = ((int32_t) sample.re*z.re - (int32_t) sample.im*z.im) >> 15; - zz.im = ((int32_t) -sample.re*z.im - (int32_t) sample.im*z.re) >> 15; -#else - v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step); - sample.im = v*s->agc_scaling; - z = dds_lookup_complexf(s->carrier_phase); - zz.re = sample.re*z.re - sample.im*z.im; - zz.im = -sample.re*z.im - sample.im*z.re; -#endif - s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2); - process_half_baud(s, &zz); - } -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len) -{ - int i; - - /* We want to sustain the current state (i.e carrier on<->carrier off), and - try to sustain the carrier phase. We should probably push the filters, as well */ - span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len); - if (s->signal_present <= 0) - return 0; - if (s->training_stage == TRAINING_STAGE_PARKED) - return 0; - for (i = 0; i < len; i++) - { -#if defined(SPANDSP_USE_FIXED_POINT) - dds_advance(&s->carrier_phase, s->carrier_phase_rate); -#else - dds_advancef(&s->carrier_phase, s->carrier_phase_rate); -#endif - /* Advance the symbol phase the appropriate amount */ - s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS; - if (s->eq_put_step <= 0) - s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2); - /* TODO: Should we rotate any buffers */ - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit, void *user_data) -{ - s->put_bit = put_bit; - s->put_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v29_rx_get_logging_state(v29_rx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, bool old_train) -{ - int i; - - switch (bit_rate) - { - case 9600: - s->training_cd = 0; - break; - case 7200: - s->training_cd = 2; - break; - case 4800: - s->training_cd = 4; - break; - default: - return -1; - } - s->bit_rate = bit_rate; - -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); -#else - vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); -#endif - s->rrc_filter_step = 0; - - s->scramble_reg = 0; - s->training_scramble_reg = 0x2A; - s->training_stage = TRAINING_STAGE_SYMBOL_ACQUISITION; - s->training_count = 0; - s->signal_present = 0; -#if defined(IAXMODEM_STUFF) - s->high_sample = 0; - s->low_samples = 0; - s->carrier_drop_pending = false; -#endif - s->old_train = old_train; - vec_zeroi32(s->diff_angles, 16); - - s->carrier_phase = 0; - - power_meter_init(&s->power, 4); - - s->constellation_state = 0; - - if (s->old_train) - { - s->carrier_phase_rate = s->carrier_phase_rate_save; - equalizer_restore(s); - s->agc_scaling = s->agc_scaling_save; - } - else - { - 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_POINT) - s->agc_scaling = (float) (FP_SCALE(1.25f)*1024.0f)/735.0f; -#else - s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/735.0f; -#endif - } -#if defined(SPANDSP_USE_FIXED_POINT) - s->carrier_track_i = 8000; - s->carrier_track_p = 8000000; -#else - s->carrier_track_i = 8000.0f; - s->carrier_track_p = 8000000.0f; -#endif - s->last_sample = 0; - s->eq_skip = 0; - - /* Initialise the working data for symbol timing synchronisation */ - for (i = 0; i < 2; i++) - { - 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 = FP_SCALE(0.0f); - s->baud_half = 0; - - s->total_baud_timing_correction = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v29_rx_state_t *) v29_rx_init(v29_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data) -{ - switch (bit_rate) - { - case 9600: - case 7200: - case 4800: - break; - default: - return NULL; - } - if (s == NULL) - { - if ((s = (v29_rx_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, "V.29 RX"); - s->put_bit = put_bit; - s->put_bit_user_data = user_data; - /* The V.29 spec says the thresholds should be -31dBm and -26dBm, but that makes little - sense. V.17 uses -48dBm and -43dBm, and there seems no good reason to cut off at a - higher level (though at 9600bps and 7200bps, TCM should put V.17 sensitivity several - dB ahead of V.29). */ - /* 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); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_rx_release(v29_rx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_rx_free(v29_rx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_rx_set_qam_report_handler(v29_rx_state_t *s, qam_report_handler_t handler, void *user_data) -{ - s->qam_report = handler; - s->qam_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v29tx.c b/libs/spandsp/src/v29tx.c deleted file mode 100644 index bef54364e8..0000000000 --- a/libs/spandsp/src/v29tx.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v29tx.c - ITU V.29 modem transmit part - * - * 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 */ - -#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 "floating_fudge.h" - -#include "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/fast_convert.h" -#include "spandsp/logging.h" -#include "spandsp/complex.h" -#include "spandsp/vector_float.h" -#include "spandsp/complex_vector_float.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex_vector_int.h" -#include "spandsp/async.h" -#include "spandsp/dds.h" -#include "spandsp/power_meter.h" - -#include "spandsp/v29tx.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/v29tx.h" - -#if defined(SPANDSP_USE_FIXED_POINT) -#define FP_SCALE(x) ((int16_t) x) -#else -#define FP_SCALE(x) (x) -#endif - -#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x) - -#include "v29tx_rrc.h" -#include "v29tx_constellation_maps.h" - -/*! The nominal frequency of the carrier, in Hertz */ -#define CARRIER_NOMINAL_FREQ 1700.0f - -/* Segments of the training sequence */ -/*! The start of the optional TEP, that may preceed the actual training, in symbols */ -#define V29_TRAINING_SEG_TEP 0 -/*! The start of training segment 1, in symbols */ -#define V29_TRAINING_SEG_1 (V29_TRAINING_SEG_TEP + 480) -/*! The start of training segment 2, in symbols */ -#define V29_TRAINING_SEG_2 (V29_TRAINING_SEG_1 + 48) -/*! The start of training segment 3, in symbols */ -#define V29_TRAINING_SEG_3 (V29_TRAINING_SEG_2 + 128) -/*! The start of training segment 4, in symbols */ -#define V29_TRAINING_SEG_4 (V29_TRAINING_SEG_3 + 384) -/*! The end of the training, in symbols */ -#define V29_TRAINING_END (V29_TRAINING_SEG_4 + 48) -/*! The end of the shutdown sequence, in symbols */ -#define V29_TRAINING_SHUTDOWN_END (V29_TRAINING_END + 32) - -static int fake_get_bit(void *user_data) -{ - return 1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int get_scrambled_bit(v29_tx_state_t *s) -{ - int bit; - int out_bit; - - if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA) - { - /* End of real data. Switch to the fake get_bit routine, until we - have shut down completely. */ - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); - s->current_get_bit = fake_get_bit; - s->in_training = true; - bit = 1; - } - out_bit = (bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1; - s->scramble_reg = (s->scramble_reg << 1) | out_bit; - return out_bit; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static __inline__ complexi16_t getbaud(v29_tx_state_t *s) -#else -static __inline__ complexf_t getbaud(v29_tx_state_t *s) -#endif -{ - static const int phase_steps_9600[8] = - { - 1, 0, 2, 3, 6, 7, 5, 4 - }; - static const int phase_steps_4800[4] = - { - 0, 2, 6, 4 - }; -#if defined(SPANDSP_USE_FIXED_POINT) - static const complexi16_t zero = {0, 0}; -#else - static const complexf_t zero = {0.0f, 0.0f}; -#endif - int bits; - int amp; - int bit; - - if (s->in_training) - { - /* Send the training sequence */ - if (++s->training_step <= V29_TRAINING_SEG_4) - { - if (s->training_step <= V29_TRAINING_SEG_3) - { - if (s->training_step <= V29_TRAINING_SEG_1) - { - /* Optional segment: Unmodulated carrier (talker echo protection) */ - return v29_9600_constellation[0]; - } - if (s->training_step <= V29_TRAINING_SEG_2) - { - /* Segment 1: silence */ - return zero; - } - /* Segment 2: ABAB... */ - return v29_abab_constellation[(s->training_step & 1) + s->training_offset]; - } - /* Segment 3: CDCD... */ - /* Apply the 1 + x^-6 + x^-7 training scrambler */ - bit = s->training_scramble_reg & 1; - s->training_scramble_reg >>= 1; - s->training_scramble_reg |= (((bit ^ s->training_scramble_reg) & 1) << 6); - return v29_cdcd_constellation[bit + s->training_offset]; - } - /* We should be in the block of test ones, or shutdown ones, if we get here. */ - /* There is no graceful shutdown procedure defined for V.29. Just - send some ones, to ensure we get the real data bits through, even - with bad ISI. */ - if (s->training_step == V29_TRAINING_END + 1) - { - /* 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; - } - if (s->training_step == V29_TRAINING_SHUTDOWN_END) - { - if (s->status_handler) - s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE); - } - } - /* 9600bps uses the full constellation. - 7200bps uses only the first half of the full constellation. - 4800bps uses the smaller constellation. */ - amp = 0; - /* We only use an amplitude bit at 9600bps */ - if (s->bit_rate == 9600 && get_scrambled_bit(s)) - amp = 8; - /*endif*/ - bits = get_scrambled_bit(s); - bits = (bits << 1) | get_scrambled_bit(s); - if (s->bit_rate == 4800) - { - bits = phase_steps_4800[bits]; - } - else - { - bits = (bits << 1) | get_scrambled_bit(s); - bits = phase_steps_9600[bits]; - } - s->constellation_state = (s->constellation_state + bits) & 7; - return v29_9600_constellation[amp | s->constellation_state]; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t v; - complexi32_t x; - complexi32_t z; - int16_t iamp; -#else - complexf_t v; - complexf_t x; - complexf_t z; - float famp; -#endif - int sample; - - if (s->training_step >= V29_TRAINING_SHUTDOWN_END) - { - /* Once we have sent the shutdown symbols, we stop sending completely. */ - return 0; - } - for (sample = 0; sample < len; sample++) - { - if ((s->baud_phase += 3) >= 10) - { - s->baud_phase -= 10; - v = getbaud(s); - s->rrc_filter_re[s->rrc_filter_step] = v.re; - s->rrc_filter_im[s->rrc_filter_step] = v.im; - if (++s->rrc_filter_step >= V29_TX_FILTER_STEPS) - s->rrc_filter_step = 0; - } -#if defined(SPANDSP_USE_FIXED_POINT) - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step) >> 4; - x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step) >> 4; - /* Now create and modulate the carrier */ - z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate); - iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) (((int32_t) iamp*s->gain) >> 11); -#else - /* Root raised cosine pulse shaping at baseband */ - x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step); - x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step); - /* Now create and modulate the carrier */ - z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate); - famp = x.re*z.re - x.im*z.im; - /* Don't bother saturating. We should never clip. */ - amp[sample] = (int16_t) lfastrintf(famp*s->gain); -#endif - } - return sample; -} -/*- End of function --------------------------------------------------------*/ - -static void set_working_gain(v29_tx_state_t *s) -{ -#if defined(SPANDSP_USE_FIXED_POINT) - switch (s->bit_rate) - { - case 9600: - s->gain = ((int32_t) FP_Q4_12(0.387f)*s->base_gain) >> 12; - break; - case 7200: - s->gain = ((int32_t) FP_Q4_12(0.605f)*s->base_gain) >> 12; - break; - case 4800: - s->gain = ((int32_t) FP_Q4_12(0.470f)*s->base_gain) >> 12; - break; - default: - break; - } -#else - switch (s->bit_rate) - { - case 9600: - s->gain = 0.387f*s->base_gain; - break; - case 7200: - s->gain = 0.605f*s->base_gain; - break; - case 4800: - s->gain = 0.470f*s->base_gain; - break; - default: - break; - } -#endif -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_tx_power(v29_tx_state_t *s, float power) -{ - float gain; - - /* The constellation does not maintain constant average power as we change bit rates. - We need to scale the gain we get here by a bit rate specific scaling factor each - time we restart the modem. */ - gain = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN; -#if defined(SPANDSP_USE_FIXED_POINT) - s->base_gain = (int16_t) gain; -#else - s->base_gain = gain; -#endif - set_working_gain(s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit, void *user_data) -{ - if (s->get_bit == s->current_get_bit) - s->current_get_bit = get_bit; - s->get_bit = get_bit; - s->get_bit_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_status_func_t handler, void *user_data) -{ - s->status_handler = handler; - s->status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v29_tx_get_logging_state(v29_tx_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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; - set_working_gain(s); - switch (s->bit_rate) - { - case 9600: - s->training_offset = 0; - break; - case 7200: - s->training_offset = 2; - break; - case 4800: - s->training_offset = 4; - break; - default: - return -1; - } -#if defined(SPANDSP_USE_FIXED_POINT) - vec_zeroi16(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0])); - vec_zeroi16(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0])); -#else - vec_zerof(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0])); - vec_zerof(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0])); -#endif - s->rrc_filter_step = 0; - s->scramble_reg = 0; - s->training_scramble_reg = 0x2A; - s->in_training = true; - s->training_step = (tep) ? V29_TRAINING_SEG_TEP : V29_TRAINING_SEG_1; - s->carrier_phase = 0; - s->baud_phase = 0; - s->constellation_state = 0; - s->current_get_bit = fake_get_bit; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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) - { - case 9600: - case 7200: - case 4800: - break; - default: - return NULL; - } - if (s == NULL) - { - if ((s = (v29_tx_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, "V.29 TX"); - s->get_bit = get_bit; - s->get_bit_user_data = user_data; - s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); - v29_tx_power(s, -14.0f); - v29_tx_restart(s, bit_rate, tep); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_tx_release(v29_tx_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v29_tx_free(v29_tx_state_t *s) -{ - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v29tx_constellation_maps.h b/libs/spandsp/src/v29tx_constellation_maps.h deleted file mode 100644 index 2178ad2ace..0000000000 --- a/libs/spandsp/src/v29tx_constellation_maps.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v29tx_constellation_maps.h - ITU V.29 modem transmit part. - * Constellation mapping. - * - * Written by Steve Underwood - * - * Copyright (C) 2008, 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 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_USE_FIXED_POINT) -static const complexi16_t v29_abab_constellation[6] = -#else -static const complexf_t v29_abab_constellation[6] = -#endif -{ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 315deg high 9600 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg low */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 315deg low 7200 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg low */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 270deg low 4800 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 0.0f)} /* 180deg low */ -}; - -#if defined(SPANDSP_USE_FIXED_POINT) -static const complexi16_t v29_cdcd_constellation[6] = -#else -static const complexf_t v29_cdcd_constellation[6] = -#endif -{ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg low 9600 */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 135deg high */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg low 7200 */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 135deg low */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg low 4800 */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 3.0f)} /* 90deg low */ -}; - -#if defined(SPANDSP_USE_FIXED_POINT) -static const complexi16_t v29_9600_constellation[16] = -#else -static const complexf_t v29_9600_constellation[16] = -#endif -{ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg low */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 45deg low */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 90deg low */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 135deg low */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg low */ - {FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 225deg low */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 270deg low */ - {FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 315deg low */ - {FP_CONSTELLATION_SCALE( 5.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg high */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 45deg high */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 5.0f)}, /* 90deg high */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE( 3.0f)}, /* 135deg high */ - {FP_CONSTELLATION_SCALE(-5.0f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg high */ - {FP_CONSTELLATION_SCALE(-3.0f), FP_CONSTELLATION_SCALE(-3.0f)}, /* 225deg high */ - {FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-5.0f)}, /* 270deg high */ - {FP_CONSTELLATION_SCALE( 3.0f), FP_CONSTELLATION_SCALE(-3.0f)} /* 315deg high */ -}; - -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c deleted file mode 100644 index 4dac118f65..0000000000 --- a/libs/spandsp/src/v42.c +++ /dev/null @@ -1,1573 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42.c - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 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. - */ - -/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#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" -#include "spandsp/hdlc.h" -#include "spandsp/v42.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/hdlc.h" -#include "spandsp/private/v42.h" - -/* Detection phase timer */ -#define T_400 750 -/* Acknowledgement timer - 1 second between SABME's */ -#define T_401 1000 -/* Replay delay timer (optional) */ -#define T_402 1000 -/* Inactivity timer (optional). No default - use 10 seconds with no packets */ -#define T_403 10000 - -#define LAPM_DLCI_DTE_TO_DTE 0 -#define LAPM_DLCI_LAYER2_MANAGEMENT 63 - -#define elements(a) (sizeof(a)/sizeof((a)[0])) - -/* LAPM definitions */ - -#define LAPM_FRAMETYPE_MASK 0x03 - -enum -{ - LAPM_FRAMETYPE_I = 0x00, - LAPM_FRAMETYPE_I_ALT = 0x02, - LAPM_FRAMETYPE_S = 0x01, - LAPM_FRAMETYPE_U = 0x03 -}; - -/* Supervisory headers */ -enum -{ - LAPM_S_RR = 0x00, /* cr */ - LAPM_S_RNR = 0x04, /* cr */ - LAPM_S_REJ = 0x08, /* cr */ - LAPM_S_SREJ = 0x0C /* cr */ -}; - -#define LAPM_S_PF 0x01 - -/* Unnumbered headers */ -enum -{ - LAPM_U_UI = 0x00, /* cr */ - LAPM_U_DM = 0x0C, /* r */ - LAPM_U_DISC = 0x40, /* c */ - LAPM_U_UA = 0x60, /* r */ - LAPM_U_SABME = 0x6C, /* c */ - LAPM_U_FRMR = 0x84, /* r */ - LAPM_U_XID = 0xAC, /* cr */ - LAPM_U_TEST = 0xE0 /* c */ -}; - -#define LAPM_U_PF 0x10 - -/* XID sub-field definitions */ -#define FI_GENERAL 0x82 -#define GI_PARAM_NEGOTIATION 0x80 -#define GI_PRIVATE_NEGOTIATION 0xF0 -#define GI_USER_DATA 0xFF - -/* Param negotiation (Table 11a/V.42) */ -enum -{ - PI_HDLC_OPTIONAL_FUNCTIONS = 0x03, - PI_TX_INFO_MAXSIZE = 0x05, - PI_RX_INFO_MAXSIZE = 0x06, - PI_TX_WINDOW_SIZE = 0x07, - PI_RX_WINDOW_SIZE = 0x08 -}; - -/* Private param negotiation (Table 11b/V.42) */ -enum -{ - PI_PARAMETER_SET_ID = 0x00, - PI_V42BIS_COMPRESSION_REQUEST = 0x01, - PI_V42BIS_NUM_CODEWORDS = 0x02, - PI_V42BIS_MAX_STRING_LENGTH = 0x03 -}; - -#define LAPM_DLCI_DTE_TO_DTE 0 -#define LAPM_DLCI_LAYER2_MANAGEMENT 63 - -/* Type definitions */ -enum -{ - LAPM_DETECT = 0, - LAPM_IDLE = 1, - LAPM_ESTABLISH = 2, - LAPM_DATA = 3, - LAPM_RELEASE = 4, - LAPM_SIGNAL = 5, - LAPM_SETPARM = 6, - LAPM_TEST = 7, - LAPM_V42_UNSUPPORTED = 8 -}; - -/* Prototypes */ -static int lapm_connect(v42_state_t *ss); -static int lapm_disconnect(v42_state_t *s); -static void reset_lapm(v42_state_t *s); -static void lapm_hdlc_underflow(void *user_data); - -static int lapm_config(v42_state_t *ss); - -SPAN_DECLARE(const char *) lapm_status_to_str(int status) -{ - switch (status) - { - case LAPM_DETECT: - return "LAPM_DETECT"; - case LAPM_IDLE: - return "LAPM_IDLE"; - case LAPM_ESTABLISH: - return "LAPM_ESTABLISH"; - case LAPM_DATA: - return "LAPM_DATA"; - case LAPM_RELEASE: - return "LAPM_RELEASE"; - case LAPM_SIGNAL: - return "LAPM_SIGNAL"; - case LAPM_SETPARM: - return "LAPM_SETPARM"; - case LAPM_TEST: - return "LAPM_TEST"; - case LAPM_V42_UNSUPPORTED: - return "LAPM_V42_UNSUPPORTED"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -static void report_rx_status_change(v42_state_t *s, int status) -{ - if (s->lapm.status_handler) - s->lapm.status_handler(s->lapm.status_user_data, status); - else if (s->lapm.iframe_put) - s->lapm.iframe_put(s->lapm.iframe_put_user_data, NULL, status); -} -/*- End of function --------------------------------------------------------*/ - -static inline uint32_t pack_value(const uint8_t *buf, int len) -{ - uint32_t val; - - val = 0; - while (len--) - { - val <<= 8; - val |= *buf++; - } - return val; -} -/*- End of function --------------------------------------------------------*/ - -static inline v42_frame_t *get_next_free_ctrl_frame(lapm_state_t *s) -{ - v42_frame_t *f; - int ctrl_put_next; - - if ((ctrl_put_next = s->ctrl_put + 1) >= V42_CTRL_FRAMES) - ctrl_put_next = 0; - if (ctrl_put_next == s->ctrl_get) - return NULL; - f = &s->ctrl_buf[s->ctrl_put]; - s->ctrl_put = ctrl_put_next; - return f; -} -/*- End of function --------------------------------------------------------*/ - -static int tx_unnumbered_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint8_t *info, int len) -{ - v42_frame_t *f; - uint8_t *buf; - - if ((f = get_next_free_ctrl_frame(s)) == NULL) - return -1; - buf = f->buf; - buf[0] = addr; - buf[1] = LAPM_FRAMETYPE_U | ctrl; - f->len = 2; - if (info && len) - { - memcpy(&buf[f->len], info, len); - f->len += len; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int tx_supervisory_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint8_t pf_mask) -{ - v42_frame_t *f; - uint8_t *buf; - - if ((f = get_next_free_ctrl_frame(s)) == NULL) - return -1; - buf = f->buf; - buf[0] = addr; - buf[1] = LAPM_FRAMETYPE_S | ctrl; - buf[2] = (s->vr << 1) | pf_mask; - f->len = 3; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int set_param(int param, int value, int def) -{ - if ((value < def && param >= def) || (value >= def && param < def)) - return def; - if ((value < def && param < value) || (value >= def && param > value)) - return value; - return param; -} -/*- End of function --------------------------------------------------------*/ - -static int receive_xid(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - v42_config_parameters_t config; - const uint8_t *buf; - uint8_t group_id; - uint16_t group_len; - uint32_t param_val; - uint8_t param_id; - uint8_t param_len; - - s = &ss->lapm; - if (frame[2] != FI_GENERAL) - return -1; - memset(&config, 0, sizeof(config)); - /* Skip the header octets */ - frame += 3; - len -= 3; - while (len > 0) - { - group_id = frame[0]; - group_len = frame[1]; - group_len = (group_len << 8) | frame[2]; - frame += 3; - len -= (3 + group_len); - if (len < 0) - break; - buf = frame; - frame += group_len; - switch (group_id) - { - case GI_PARAM_NEGOTIATION: - while (group_len > 0) - { - param_id = buf[0]; - param_len = buf[1]; - buf += 2; - if (group_len < (2 + param_len)) - break; - group_len -= (2 + param_len); - switch (param_id) - { - case PI_HDLC_OPTIONAL_FUNCTIONS: - /* TODO: param_val is never used right now. */ - //param_val = pack_value(buf, param_len); - break; - case PI_TX_INFO_MAXSIZE: - param_val = pack_value(buf, param_len); - param_val >>= 3; - config.v42_tx_n401 = - s->tx_n401 = set_param(s->tx_n401, param_val, ss->config.v42_tx_n401); - break; - case PI_RX_INFO_MAXSIZE: - param_val = pack_value(buf, param_len); - param_val >>= 3; - config.v42_rx_n401 = - s->rx_n401 = set_param(s->rx_n401, param_val, ss->config.v42_rx_n401); - break; - case PI_TX_WINDOW_SIZE: - param_val = pack_value(buf, param_len); - config.v42_tx_window_size_k = - s->tx_window_size_k = set_param(s->tx_window_size_k, param_val, ss->config.v42_tx_window_size_k); - break; - case PI_RX_WINDOW_SIZE: - param_val = pack_value(buf, param_len); - config.v42_rx_window_size_k = - s->rx_window_size_k = set_param(s->rx_window_size_k, param_val, ss->config.v42_rx_window_size_k); - break; - default: - break; - } - buf += param_len; - } - break; - case GI_PRIVATE_NEGOTIATION: - while (group_len > 0) - { - param_id = buf[0]; - param_len = buf[1]; - buf += 2; - if (group_len < 2 + param_len) - break; - group_len -= (2 + param_len); - switch (param_id) - { - case PI_PARAMETER_SET_ID: - /* This might be worth monitoring, but it doesn't serve mnuch other purpose */ - break; - case PI_V42BIS_COMPRESSION_REQUEST: - config.comp = pack_value(buf, param_len); - break; - case PI_V42BIS_NUM_CODEWORDS: - config.comp_dict_size = pack_value(buf, param_len); - break; - case PI_V42BIS_MAX_STRING_LENGTH: - config.comp_max_string = pack_value(buf, param_len); - break; - default: - break; - } - buf += param_len; - } - break; - default: - break; - } - } - //v42_update_config(ss, &config); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void transmit_xid(v42_state_t *ss, uint8_t addr) -{ - lapm_state_t *s; - uint8_t *buf; - int len; - int group_len; - uint32_t param_val; - v42_frame_t *f; - - s = &ss->lapm; - if ((f = get_next_free_ctrl_frame(s)) == NULL) - return; - - buf = f->buf; - len = 0; - - /* Figure 11/V.42 */ - *buf++ = addr; - *buf++ = LAPM_U_XID | LAPM_FRAMETYPE_U; - /* Format identifier subfield */ - *buf++ = FI_GENERAL; - len += 3; - - /* Parameter negotiation group */ - group_len = 20; - *buf++ = GI_PARAM_NEGOTIATION; - *buf++ = (group_len >> 8) & 0xFF; - *buf++ = group_len & 0xFF; - len += 3; - - /* For conformance with the encoding rules in ISO/IEC 8885, the transmitter of an XID command frame shall - set bit positions 2, 4, 8, 9, 12 and 16 to 1. (Table 11a/V.42) - Optional bits are: - 3 Selective retransmission procedure (SREJ frame) single I frame request - 14 Loop-back test procedure (TEST frame) - 17 - Extended FCS procedure (32-bit FCS) - 24 Selective retransmission procedure (SREJ frame) multiple I frame request with span list - capability. */ - *buf++ = PI_HDLC_OPTIONAL_FUNCTIONS; - *buf++ = 4; - *buf++ = 0x8A; /* Bits 2, 4, and 8 set */ - *buf++ = 0x89; /* Bits 9, 12, and 16 set */ - *buf++ = 0x00; - *buf++ = 0x00; - - /* Send the maximum as a number of bits, rather than octets */ - param_val = ss->config.v42_tx_n401 << 3; - *buf++ = PI_TX_INFO_MAXSIZE; - *buf++ = 2; - *buf++ = (param_val >> 8) & 0xFF; - *buf++ = (param_val & 0xFF); - - /* Send the maximum as a number of bits, rather than octets */ - param_val = ss->config.v42_rx_n401 << 3; - *buf++ = PI_RX_INFO_MAXSIZE; - *buf++ = 2; - *buf++ = (param_val >> 8) & 0xFF; - *buf++ = (param_val & 0xFF); - - *buf++ = PI_TX_WINDOW_SIZE; - *buf++ = 1; - *buf++ = ss->config.v42_tx_window_size_k; - - *buf++ = PI_RX_WINDOW_SIZE; - *buf++ = 1; - *buf++ = ss->config.v42_rx_window_size_k; - - len += group_len; - - if (ss->config.comp) - { - /* Private parameter negotiation group */ - group_len = 15; - *buf++ = GI_PRIVATE_NEGOTIATION; - *buf++ = (group_len >> 8) & 0xFF; - *buf++ = group_len & 0xFF; - len += 3; - - /* Private parameter for V.42 (ASCII for V42). V.42 says ".42", but V.42bis says "V42", - and that seems to be what should be used. */ - *buf++ = PI_PARAMETER_SET_ID; - *buf++ = 3; - *buf++ = 'V'; - *buf++ = '4'; - *buf++ = '2'; - - /* V.42bis P0 - 00 Compression in neither direction (default); - 01 Negotiation initiator-responder direction only; - 10 Negotiation responder-initiator direction only; - 11 Both directions. */ - *buf++ = PI_V42BIS_COMPRESSION_REQUEST; - *buf++ = 1; - *buf++ = ss->config.comp; - - /* V.42bis P1 */ - param_val = ss->config.comp_dict_size; - *buf++ = PI_V42BIS_NUM_CODEWORDS; - *buf++ = 2; - *buf++ = (param_val >> 8) & 0xFF; - *buf++ = param_val & 0xFF; - - /* V.42bis P2 */ - *buf++ = PI_V42BIS_MAX_STRING_LENGTH; - *buf++ = 1; - *buf++ = ss->config.comp_max_string; - - len += group_len; - } - - f->len = len; -} -/*- End of function --------------------------------------------------------*/ - -static int ms_to_bits(v42_state_t *s, int time) -{ - return ((time*s->tx_bit_rate)/1000); -} -/*- End of function --------------------------------------------------------*/ - -static void t400_expired(v42_state_t *ss) -{ - /* Give up trying to detect a V.42 capable peer. */ - ss->bit_timer = 0; - ss->lapm.state = LAPM_V42_UNSUPPORTED; - report_rx_status_change(ss, ss->lapm.state); -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void t400_start(v42_state_t *s) -{ - s->bit_timer = ms_to_bits(s, T_400); - s->bit_timer_func = t400_expired; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void t400_stop(v42_state_t *s) -{ - s->bit_timer = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void t401_expired(v42_state_t *ss) -{ - lapm_state_t *s; - - span_log(&ss->logging, SPAN_LOG_FLOW, "T.401 expired\n"); - s = &ss->lapm; - if (s->retry_count > V42_DEFAULT_N_400) - { - s->retry_count = 0; - switch (s->state) - { - case LAPM_ESTABLISH: - case LAPM_RELEASE: - s->state = LAPM_IDLE; - report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); - break; - case LAPM_DATA: - lapm_disconnect(ss); - break; - } - return ; - } - s->retry_count++; - if (s->configuring) - { - transmit_xid(ss, s->cmd_addr); - } - else - { - switch (s->state) - { - case LAPM_ESTABLISH: - tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_SABME | LAPM_U_PF, NULL, 0); - break; - case LAPM_RELEASE: - tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_DISC | LAPM_U_PF, NULL, 0); - break; - case LAPM_DATA: - tx_supervisory_frame(s, s->cmd_addr, (s->local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); - break; - } - } - ss->bit_timer = ms_to_bits(ss, T_401); - ss->bit_timer_func = t401_expired; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void t401_start(v42_state_t *s) -{ - s->bit_timer = ms_to_bits(s, T_401); - s->bit_timer_func = t401_expired; - s->lapm.retry_count = 0; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void t401_stop(v42_state_t *s) -{ - s->bit_timer = 0; - s->lapm.retry_count = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void t403_expired(v42_state_t *ss) -{ - lapm_state_t *s; - - span_log(&ss->logging, SPAN_LOG_FLOW, "T.403 expired\n"); - if (ss->lapm.state != LAPM_DATA) - return; - s = &ss->lapm; - tx_supervisory_frame(s, s->cmd_addr, (ss->lapm.local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); - t401_start(ss); - ss->lapm.retry_count = 1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void t401_stop_t403_start(v42_state_t *s) -{ - s->bit_timer = ms_to_bits(s, T_403); - s->bit_timer_func = t403_expired; - s->lapm.retry_count = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void initiate_negotiation_expired(v42_state_t *s) -{ - /* Timer service routine */ - span_log(&s->logging, SPAN_LOG_FLOW, "Start negotiation\n"); - lapm_config(s); - lapm_hdlc_underflow(s); -} -/*- End of function --------------------------------------------------------*/ - -static int tx_information_frame(v42_state_t *ss) -{ - lapm_state_t *s; - v42_frame_t *f; - uint8_t *buf; - int n; - int info_put_next; - - s = &ss->lapm; - if (s->far_busy || ((s->vs - s->va) & 0x7F) >= s->tx_window_size_k) - return false; - if (s->info_get != s->info_put) - 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; - f = &s->info_buf[s->info_put]; - buf = f->buf; - if (s->iframe_get == NULL) - 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; - } - if (n == 0) - return false; - - f->len = n + 3; - s->info_put = info_put_next; - return true; -} -/*- End of function --------------------------------------------------------*/ - -static void tx_information_rr_rnr_response(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - - s = &ss->lapm; - /* Respond with information frame, RR, or RNR, as appropriate */ - /* p = 1 may be used for status checking */ - if ((frame[2] & 0x1) || !tx_information_frame(ss)) - tx_supervisory_frame(s, frame[0], (s->local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); -} -/*- End of function --------------------------------------------------------*/ - -static int reject_info(lapm_state_t *s) -{ - uint8_t n; - - /* Reject all non-acked frames */ - if (s->state != LAPM_DATA) - return 0; - n = (s->vs - s->va) & 0x7F; - s->vs = s->va; - s->info_get = s->info_acked; - return n; -} -/*- End of function --------------------------------------------------------*/ - -static int ack_info(v42_state_t *ss, uint8_t nr) -{ - lapm_state_t *s; - int n; - - s = &ss->lapm; - /* Check that NR is valid - i.e. VA <= NR <= VS && VS-VA <= k */ - if (!((((nr - s->va) & 0x7F) + ((s->vs - nr) & 0x7F)) <= s->tx_window_size_k - && - ((s->vs - s->va) & 0x7F) <= s->tx_window_size_k)) - { - lapm_disconnect(ss); - return -1; - } - n = 0; - while (s->va != nr && s->info_acked != s->info_get) - { - if (++s->info_acked >= V42_INFO_FRAMES) - s->info_acked = 0; - s->va = (s->va + 1) & 0x7F; - n++; - } - if (n > 0 && s->retry_count == 0) - { - t401_stop_t403_start(ss); - /* 8.4.8 */ - if (((s->vs - s->va) & 0x7F)) - t401_start(ss); - } - return n; -} -/*- End of function --------------------------------------------------------*/ - -static int valid_data_state(v42_state_t *ss) -{ - lapm_state_t *s; - - s = &ss->lapm; - switch (s->state) - { - case LAPM_DETECT: - case LAPM_IDLE: - break; - case LAPM_ESTABLISH: - reset_lapm(ss); - s->state = LAPM_DATA; - report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); - return 1; - case LAPM_DATA: - return 1; - case LAPM_RELEASE: - reset_lapm(ss); - s->state = LAPM_IDLE; - report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); - break; - case LAPM_SIGNAL: - case LAPM_SETPARM: - case LAPM_TEST: - case LAPM_V42_UNSUPPORTED: - break; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void receive_information_frame(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - - s = &ss->lapm; - if (!valid_data_state(ss)) - return; - if (len > s->rx_n401 + 3) - return; - /* Ack I frames: NR - 1 */ - ack_info(ss, frame[2] >> 1); - if (s->local_busy) - { - /* 8.4.7 */ - if ((frame[2] & 0x1)) - tx_supervisory_frame(s, s->rsp_addr, LAPM_S_RNR, 1); - return; - } - /* NS sequence error */ - if ((frame[1] >> 1) != s->vr) - { - if (!s->rejected) - { - tx_supervisory_frame(s, s->rsp_addr, LAPM_S_REJ, (frame[2] & 0x1)); - s->rejected = true; - } - return; - } - s->rejected = false; - - s->iframe_put(s->iframe_put_user_data, frame + 3, len - 3); - /* Increment vr */ - s->vr = (s->vr + 1) & 0x7F; - tx_information_rr_rnr_response(ss, frame, len); -} -/*- End of function --------------------------------------------------------*/ - -static void rx_supervisory_cmd_frame(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - - s = &ss->lapm; - /* If l->local_busy each RR,RNR,REJ with p=1 should be replied by RNR with f=1 (8.4.7) */ - switch (frame[1] & 0x0C) - { - case LAPM_S_RR: - 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; - 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; - ack_info(ss, frame[2] >> 1); - if (s->retry_count == 0) - { - t401_stop_t403_start(ss); - reject_info(s); - } - tx_information_rr_rnr_response(ss, frame, len); - break; - case LAPM_S_SREJ: - /* TODO: */ - return; - default: - return; - } -} -/*- End of function --------------------------------------------------------*/ - -static void rx_supervisory_rsp_frame(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - - s = &ss->lapm; - if (s->retry_count == 0 && (frame[2] & 0x1)) - return; - /* Ack I frames <= NR - 1 */ - switch (frame[1] & 0x0C) - { - case LAPM_S_RR: - s->far_busy = false; - ack_info(ss, frame[2] >> 1); - if (s->retry_count && (frame[2] & 0x1)) - { - reject_info(s); - t401_stop_t403_start(ss); - } - break; - case LAPM_S_RNR: - s->far_busy = true; - ack_info(ss, frame[2] >> 1); - if (s->retry_count && (frame[2] & 0x1)) - { - reject_info(s); - t401_stop_t403_start(ss); - } - if (s->retry_count == 0) - t401_start(ss); - break; - case LAPM_S_REJ: - s->far_busy = false; - ack_info(ss, frame[2] >> 1); - if (s->retry_count == 0 || (frame[2] & 0x1)) - { - reject_info(s); - t401_stop_t403_start(ss); - } - break; - case LAPM_S_SREJ: - /* TODO: */ - return; - default: - return; - } -} -/*- End of function --------------------------------------------------------*/ - -static int rx_unnumbered_cmd_frame(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - - s = &ss->lapm; - switch (frame[1] & 0xEC) - { - case LAPM_U_SABME: - /* Discard un-acked I frames. Reset vs, vr, and va. Clear exceptions */ - reset_lapm(ss); - /* Going to connected state */ - s->state = LAPM_DATA; - /* Respond UA (or DM on error) */ - // fixme: why may be error and LAPM_U_DM ?? - tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_UA | (frame[1] & 0x10), NULL, 0); - t401_stop_t403_start(ss); - report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); - break; - case LAPM_U_UI: - /* Break signal */ - /* TODO: */ - break; - case LAPM_U_DISC: - /* Respond UA (or DM) */ - if (s->state == LAPM_IDLE) - { - tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_DM | LAPM_U_PF, NULL, 0); - } - else - { - /* Going to disconnected state, discard unacked I frames, reset all. */ - s->state = LAPM_IDLE; - reset_lapm(ss); - tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_UA | (frame[1] & 0x10), NULL, 0); - t401_stop(ss); - /* TODO: notify CF */ - report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); - } - break; - case LAPM_U_XID: - /* Exchange general ID info */ - receive_xid(ss, frame, len); - transmit_xid(ss, s->rsp_addr); - break; - case LAPM_U_TEST: - /* TODO: */ - break; - default: - return -1; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_unnumbered_rsp_frame(v42_state_t *ss, const uint8_t *frame, int len) -{ - lapm_state_t *s; - - s = &ss->lapm; - switch (frame[1] & 0xEC) - { - case LAPM_U_DM: - switch (s->state) - { - case LAPM_IDLE: - if (!(frame[1] & 0x10)) - { - /* TODO: notify CF */ - report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); - } - break; - case LAPM_ESTABLISH: - case LAPM_RELEASE: - if ((frame[1] & 0x10)) - { - s->state = LAPM_IDLE; - reset_lapm(ss); - t401_stop(ss); - /* TODO: notify CF */ - report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); - } - break; - case LAPM_DATA: - if (s->retry_count || !(frame[1] & 0x10)) - { - s->state = LAPM_IDLE; - reset_lapm(ss); - /* TODO: notify CF */ - report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); - } - break; - default: - break; - } - break; - case LAPM_U_UI: - /* TODO: */ - break; - case LAPM_U_UA: - switch (s->state) - { - case LAPM_ESTABLISH: - s->state = LAPM_DATA; - reset_lapm(ss); - t401_stop_t403_start(ss); - report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); - break; - case LAPM_RELEASE: - s->state = LAPM_IDLE; - reset_lapm(ss); - t401_stop(ss); - report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); - break; - default: - /* Unsolicited UA */ - /* TODO: */ - break; - } - /* Clear all exceptions, busy states (self and peer) */ - /* Reset vars */ - break; - case LAPM_U_FRMR: - /* Non-recoverable error */ - /* TODO: */ - break; - case LAPM_U_XID: - if (s->configuring) - { - receive_xid(ss, frame, len); - s->configuring = false; - t401_stop(ss); - switch (s->state) - { - case LAPM_IDLE: - lapm_connect(ss); - break; - case LAPM_DATA: - s->local_busy = false; - tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RR, 0); - break; - } - } - break; - default: - break; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void lapm_hdlc_underflow(void *user_data) -{ - lapm_state_t *s; - v42_state_t *ss; - v42_frame_t *f; - - ss = (v42_state_t *) user_data; - s = &ss->lapm; - if (s->ctrl_get != s->ctrl_put) - { - /* Send control frame */ - f = &s->ctrl_buf[s->ctrl_get]; - if (++s->ctrl_get >= V42_CTRL_FRAMES) - s->ctrl_get = 0; - } - else - { - if (s->far_busy || s->configuring || s->state != LAPM_DATA) - { - hdlc_tx_flags(&s->hdlc_tx, 10); - return; - } - if (s->info_get == s->info_put && !tx_information_frame(ss)) - { - hdlc_tx_flags(&s->hdlc_tx, 10); - return; - } - /* Send info frame */ - f = &s->info_buf[s->info_get]; - if (++s->info_get >= V42_INFO_FRAMES) - s->info_get = 0; - - f->buf[0] = s->cmd_addr; - f->buf[1] = s->vs << 1; - f->buf[2] = s->vr << 1; - s->vs = (s->vs + 1) & 0x7F; - if (ss->bit_timer == 0) - t401_start(ss); - } - hdlc_tx_frame(&s->hdlc_tx, f->buf, f->len); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok) -{ - lapm_state_t *s; - v42_state_t *ss; - - ss = (v42_state_t *) user_data; - s = &ss->lapm; - if (len < 0) - { - span_log(&ss->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len); - return; - } - if (!ok) - return; - - switch ((frame[1] & LAPM_FRAMETYPE_MASK)) - { - case LAPM_FRAMETYPE_I: - case LAPM_FRAMETYPE_I_ALT: - receive_information_frame(ss, frame, len); - break; - case LAPM_FRAMETYPE_S: - if (!valid_data_state(ss)) - return; - if (frame[0] == s->rsp_addr) - rx_supervisory_cmd_frame(ss, frame, len); - else - rx_supervisory_rsp_frame(ss, frame, len); - break; - case LAPM_FRAMETYPE_U: - if (frame[0] == s->rsp_addr) - rx_unnumbered_cmd_frame(ss, frame, len); - else - rx_unnumbered_rsp_frame(ss, frame, len); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int lapm_connect(v42_state_t *ss) -{ - lapm_state_t *s; - - s = &ss->lapm; - if (s->state != LAPM_IDLE) - return -1; - - /* Negotiate params */ - //transmit_xid(s, s->cmd_addr); - - reset_lapm(ss); - /* Connect */ - s->state = LAPM_ESTABLISH; - tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_SABME | LAPM_U_PF, NULL, 0); - /* Start T401 (and not T403) */ - t401_start(ss); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int lapm_disconnect(v42_state_t *ss) -{ - lapm_state_t *s; - - s = &ss->lapm; - s->state = LAPM_RELEASE; - tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_DISC | LAPM_U_PF, NULL, 0); - t401_start(ss); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int lapm_config(v42_state_t *ss) -{ - lapm_state_t *s; - - s = &ss->lapm; - s->configuring = true; - if (s->state == LAPM_DATA) - { - s->local_busy = true; - tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RNR, 1); - } - transmit_xid(ss, s->cmd_addr); - t401_start(ss); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void reset_lapm(v42_state_t *ss) -{ - lapm_state_t *s; - - s = &ss->lapm; - /* Reset the LAP.M state */ - s->local_busy = false; - s->far_busy = false; - s->vs = 0; - s->va = 0; - s->vr = 0; - /* Discard any info frames still queued for transmission */ - s->info_put = 0; - s->info_acked = 0; - s->info_get = 0; - /* Discard any control frames */ - s->ctrl_put = 0; - s->ctrl_get = 0; - - s->tx_window_size_k = ss->config.v42_tx_window_size_k; - s->rx_window_size_k = ss->config.v42_rx_window_size_k; - s->tx_n401 = ss->config.v42_tx_n401; - s->rx_n401 = ss->config.v42_rx_n401; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v42_stop(v42_state_t *ss) -{ - lapm_state_t *s; - - s = &ss->lapm; - ss->bit_timer = 0; - s->packer_process = NULL; - lapm_disconnect(ss); -} -/*- End of function --------------------------------------------------------*/ - -static void restart_lapm(v42_state_t *s) -{ - if (s->calling_party) - { - s->bit_timer = 48*8; - s->bit_timer_func = initiate_negotiation_expired; - } - else - { - lapm_hdlc_underflow(s); - } - s->lapm.packer_process = NULL; - s->lapm.state = LAPM_IDLE; -} -/*- End of function --------------------------------------------------------*/ - -static void negotiation_rx_bit(v42_state_t *s, int new_bit) -{ - /* DC1 with even parity, 8-16 ones, DC1 with odd parity, 8-16 ones */ - /* uint8_t odp = "0100010001 11111111 0100010011 11111111"; */ - /* V.42 OK E , 8-16 ones, C, 8-16 ones */ - /* uint8_t adp_v42 = "0101000101 11111111 0110000101 11111111"; */ - /* V.42 disabled E, 8-16 ones, NULL, 8-16 ones */ - /* uint8_t adp_nov42 = "0101000101 11111111 0000000001 11111111"; */ - - /* There may be no negotiation, so we need to process this data through the - HDLC receiver as well */ - if (new_bit < 0) - { - /* Special conditions */ - span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(new_bit), new_bit); - return; - } - /*endif*/ - new_bit &= 1; - s->neg.rxstream = (s->neg.rxstream << 1) | new_bit; - switch (s->neg.rx_negotiation_step) - { - case 0: - /* Look for some ones */ - if (new_bit) - break; - /*endif*/ - s->neg.rx_negotiation_step = 1; - s->neg.rxbits = 0; - s->neg.rxstream = ~1; - s->neg.rxoks = 0; - break; - case 1: - /* Look for the first character */ - if (++s->neg.rxbits < 9) - break; - /*endif*/ - s->neg.rxstream &= 0x3FF; - if (s->calling_party && s->neg.rxstream == 0x145) - { - s->neg.rx_negotiation_step++; - } - else if (!s->calling_party && s->neg.rxstream == 0x111) - { - s->neg.rx_negotiation_step++; - } - else - { - s->neg.rx_negotiation_step = 0; - } - /*endif*/ - s->neg.rxbits = 0; - s->neg.rxstream = ~0; - break; - case 2: - /* Look for 8 to 16 ones */ - s->neg.rxbits++; - if (new_bit) - break; - /*endif*/ - if (s->neg.rxbits >= 8 && s->neg.rxbits <= 16) - s->neg.rx_negotiation_step++; - else - s->neg.rx_negotiation_step = 0; - /*endif*/ - s->neg.rxbits = 0; - s->neg.rxstream = ~1; - break; - case 3: - /* Look for the second character */ - if (++s->neg.rxbits < 9) - break; - /*endif*/ - s->neg.rxstream &= 0x3FF; - if (s->calling_party && s->neg.rxstream == 0x185) - { - s->neg.rx_negotiation_step++; - } - else if (s->calling_party && s->neg.rxstream == 0x001) - { - s->neg.rx_negotiation_step++; - } - else if (!s->calling_party && s->neg.rxstream == 0x113) - { - s->neg.rx_negotiation_step++; - } - else - { - s->neg.rx_negotiation_step = 0; - } - /*endif*/ - s->neg.rxbits = 0; - s->neg.rxstream = ~0; - break; - case 4: - /* Look for 8 to 16 ones */ - s->neg.rxbits++; - if (new_bit) - break; - /*endif*/ - if (s->neg.rxbits >= 8 && s->neg.rxbits <= 16) - { - if (++s->neg.rxoks >= 2) - { - /* HIT - we have found the "V.42 supported" pattern. */ - s->neg.rx_negotiation_step++; - if (s->calling_party) - { - t400_stop(s); - s->lapm.state = LAPM_IDLE; - report_rx_status_change(s, s->lapm.state); - restart_lapm(s); - } - else - { - s->neg.odp_seen = true; - } - /*endif*/ - break; - } - /*endif*/ - s->neg.rx_negotiation_step = 1; - s->neg.rxbits = 0; - s->neg.rxstream = ~1; - } - else - { - s->neg.rx_negotiation_step = 0; - s->neg.rxbits = 0; - s->neg.rxstream = ~0; - } - /*endif*/ - break; - case 5: - /* Parked */ - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static int v42_support_negotiation_tx_bit(v42_state_t *s) -{ - int bit; - - if (s->calling_party) - { - if (s->neg.txbits <= 0) - { - s->neg.txstream = 0x3FE22; - s->neg.txbits = 36; - } - else if (s->neg.txbits == 18) - { - s->neg.txstream = 0x3FF22; - } - /*endif*/ - bit = s->neg.txstream & 1; - s->neg.txstream >>= 1; - s->neg.txbits--; - } - else - { - if (s->neg.odp_seen && s->neg.txadps < 10) - { - if (s->neg.txbits <= 0) - { - if (++s->neg.txadps >= 10) - { - t400_stop(s); - s->lapm.state = LAPM_IDLE; - report_rx_status_change(s, s->lapm.state); - s->neg.txstream = 1; - restart_lapm(s); - } - else - { - s->neg.txstream = 0x3FE8A; - s->neg.txbits = 36; - } - /*endif*/ - } - else if (s->neg.txbits == 18) - { - s->neg.txstream = 0x3FE86; - } - /*endif*/ - bit = s->neg.txstream & 1; - s->neg.txstream >>= 1; - s->neg.txbits--; - } - else - { - bit = 1; - } - /*endif*/ - } - /*endif*/ - return bit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v42_rx_bit(void *user_data, int bit) -{ - v42_state_t *s; - - s = (v42_state_t *) user_data; - if (s->lapm.state == LAPM_DETECT) - negotiation_rx_bit(s, bit); - else - hdlc_rx_put_bit(&s->lapm.hdlc_rx, bit); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42_tx_bit(void *user_data) -{ - v42_state_t *s; - int bit; - - s = (v42_state_t *) user_data; - if (s->bit_timer && (--s->bit_timer) <= 0) - { - s->bit_timer = 0; - s->bit_timer_func(s); - } - if (s->lapm.state == LAPM_DETECT) - bit = v42_support_negotiation_tx_bit(s); - else - bit = hdlc_tx_get_bit(&s->lapm.hdlc_tx); - /*endif*/ - return bit; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42_set_local_busy_status(v42_state_t *s, int busy) -{ - int previous_busy; - - previous_busy = s->lapm.local_busy; - s->lapm.local_busy = busy; - return previous_busy; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42_get_far_busy_status(v42_state_t *s) -{ - return s->lapm.far_busy; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v42_get_logging_state(v42_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t status_handler, void *user_data) -{ - s->lapm.status_handler = status_handler; - s->lapm.status_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -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); - - if (s->detect) - { - /* We need to do the V.42 support detection sequence */ - s->neg.txstream = ~0; - s->neg.txbits = 0; - s->neg.rxstream = ~0; - s->neg.rxbits = 0; - s->neg.rxoks = 0; - s->neg.txadps = 0; - s->neg.rx_negotiation_step = 0; - s->neg.odp_seen = false; - t400_start(s); - s->lapm.state = LAPM_DETECT; - } - else - { - /* Go directly to LAP.M mode */ - s->lapm.state = LAPM_IDLE; - restart_lapm(s); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *ss, - bool calling_party, - bool detect, - get_msg_func_t iframe_get, - put_msg_func_t iframe_put, - void *user_data) -{ - lapm_state_t *s; - - if (ss == NULL) - { - if ((ss = (v42_state_t *) span_alloc(sizeof(*ss))) == NULL) - return NULL; - } - memset(ss, 0, sizeof(*ss)); - - s = &ss->lapm; - ss->calling_party = calling_party; - ss->detect = detect; - s->iframe_get = iframe_get; - s->iframe_get_user_data = user_data; - s->iframe_put = iframe_put; - s->iframe_put_user_data = user_data; - - s->state = (ss->detect) ? LAPM_DETECT : LAPM_IDLE; - s->local_busy = false; - s->far_busy = false; - - /* The address octet is: - Data link connection identifier (0) - Command/response (0 if answerer, 1 if originator) - Extended address (1) */ - s->cmd_addr = (LAPM_DLCI_DTE_TO_DTE << 2) | ((ss->calling_party) ? 0x02 : 0x00) | 0x01; - s->rsp_addr = (LAPM_DLCI_DTE_TO_DTE << 2) | ((ss->calling_party) ? 0x00 : 0x02) | 0x01; - - /* Set default values for the LAP.M parameters. These can be modified later. */ - ss->config.v42_tx_window_size_k = V42_DEFAULT_WINDOW_SIZE_K; - ss->config.v42_rx_window_size_k = V42_DEFAULT_WINDOW_SIZE_K; - ss->config.v42_tx_n401 = V42_DEFAULT_N_401; - ss->config.v42_rx_n401 = V42_DEFAULT_N_401; - - /* TODO: This should be part of the V.42bis startup */ - ss->config.comp = 1; - ss->config.comp_dict_size = 512; - ss->config.comp_max_string = 6; - - ss->tx_bit_rate = 28800; - - reset_lapm(ss); - - span_log_init(&ss->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&ss->logging, "V.42"); - return ss; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42_release(v42_state_t *s) -{ - reset_lapm(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42_free(v42_state_t *s) -{ - v42_release(s); - span_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v42bis.c b/libs/spandsp/src/v42bis.c deleted file mode 100644 index 3ca07fc493..0000000000 --- a/libs/spandsp/src/v42bis.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42bis.c - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#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" -#include "spandsp/v42bis.h" - -#include "spandsp/private/logging.h" -#include "spandsp/private/v42bis.h" - -/* Fixed parameters from the spec. */ -/* Character size (bits) */ -#define V42BIS_N3 8 -/* Number of characters in the alphabet */ -#define V42BIS_N4 256 -/* Index number of first dictionary entry used to store a string */ -#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) -/* Number of control codewords */ -#define V42BIS_N6 3 -/* V.42bis/9.2 */ -#define V42BIS_ESC_STEP 51 - -/* Compreeibility monitoring parameters for assessing automated switches between - transparent and compressed mode */ -#define COMPRESSIBILITY_MONITOR (256*V42BIS_N3) -#define COMPRESSIBILITY_MONITOR_HYSTERESIS 11 - -/* Control code words in compressed mode */ -enum -{ - V42BIS_ETM = 0, /* Enter transparent mode */ - V42BIS_FLUSH = 1, /* Flush data */ - V42BIS_STEPUP = 2 /* Step up codeword size */ -}; - -/* Command codes in transparent mode */ -enum -{ - V42BIS_ECM = 0, /* Enter compression mode */ - V42BIS_EID = 1, /* Escape character in data */ - V42BIS_RESET = 2 /* Force reinitialisation */ -}; - -static __inline__ void push_octet(v42bis_comp_state_t *s, int octet) -{ - s->output_buf[s->output_octet_count++] = (uint8_t) octet; - if (s->output_octet_count >= s->max_output_len) - { - s->handler(s->user_data, s->output_buf, s->output_octet_count); - s->output_octet_count = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len) -{ - int i; - int chunk; - - i = 0; - while ((s->output_octet_count + len - i) >= s->max_output_len) - { - chunk = s->max_output_len - s->output_octet_count; - memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); - s->handler(s->user_data, s->output_buf, s->max_output_len); - s->output_octet_count = 0; - i += chunk; - } - chunk = len - i; - if (chunk > 0) - { - memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); - s->output_octet_count += chunk; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_compressed_code(v42bis_comp_state_t *s, int code) -{ - s->bit_buffer |= code << s->bit_count; - s->bit_count += s->v42bis_parm_c2; - while (s->bit_count >= 8) - { - push_octet(s, s->bit_buffer & 0xFF); - s->bit_buffer >>= 8; - s->bit_count -= 8; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_octet_alignment(v42bis_comp_state_t *s) -{ - if ((s->bit_count & 7)) - { - s->bit_count += (8 - (s->bit_count & 7)); - while (s->bit_count >= 8) - { - push_octet(s, s->bit_buffer & 0xFF); - s->bit_buffer >>= 8; - s->bit_count -= 8; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void flush_octets(v42bis_comp_state_t *s) -{ - if (s->output_octet_count > 0) - { - s->handler(s->user_data, s->output_buf, s->output_octet_count); - s->output_octet_count = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void dictionary_init(v42bis_comp_state_t *s) -{ - int i; - - memset(s->dict, 0, sizeof(s->dict)); - for (i = 0; i < V42BIS_N4; i++) - s->dict[i + V42BIS_N6].node_octet = i; - s->v42bis_parm_c1 = V42BIS_N5; - s->v42bis_parm_c2 = V42BIS_N3 + 1; - s->v42bis_parm_c3 = V42BIS_N4 << 1; - s->last_matched = 0; - s->update_at = 0; - s->last_added = 0; - s->bit_buffer = 0; - s->bit_count = 0; - s->flushed_length = 0; - s->string_length = 0; - s->escape_code = 0; - s->transparent = true; - s->escaped = false; - s->compression_performance = COMPRESSIBILITY_MONITOR; -} -/*- End of function --------------------------------------------------------*/ - -static uint16_t match_octet(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) -{ - uint16_t e; - - if (at == 0) - return octet + V42BIS_N6; - e = s->dict[at].child; - while (e) - { - if (s->dict[e].node_octet == octet) - return e; - e = s->dict[e].next; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static uint16_t add_octet_to_dictionary(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) -{ - uint16_t newx; - uint16_t next; - uint16_t e; - - newx = s->v42bis_parm_c1; - s->dict[newx].node_octet = octet; - s->dict[newx].parent = at; - s->dict[newx].child = 0; - s->dict[newx].next = s->dict[at].child; - s->dict[at].child = newx; - next = newx; - /* 6.5 Recovering a dictionary entry to use next */ - do - { - /* 6.5(a) and (b) */ - if (++next == s->v42bis_parm_n2) - next = V42BIS_N5; - } - while (s->dict[next].child); - /* 6.5(c) We need to reuse a leaf node */ - if (s->dict[next].parent) - { - /* 6.5(d) Detach the leaf node from its parent, and re-use it */ - e = s->dict[next].parent; - if (s->dict[e].child == next) - { - s->dict[e].child = s->dict[next].next; - } - else - { - e = s->dict[e].child; - while (s->dict[e].next != next) - e = s->dict[e].next; - s->dict[e].next = s->dict[next].next; - } - } - s->v42bis_parm_c1 = next; - return newx; -} -/*- End of function --------------------------------------------------------*/ - -static void send_string(v42bis_comp_state_t *s) -{ - push_octets(s, s->string, s->string_length); - s->string_length = 0; - s->flushed_length = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void expand_codeword_to_string(v42bis_comp_state_t *s, uint16_t code) -{ - int i; - uint16_t p; - - /* Work out the length */ - for (i = 0, p = code; p; i++) - p = s->dict[p].parent; - s->string_length += i; - /* Now expand the known length of string */ - i = s->string_length - 1; - for (p = code; p; ) - { - s->string[i--] = s->dict[p].node_octet; - p = s->dict[p].parent; - } -} -/*- End of function --------------------------------------------------------*/ - -static void send_encoded_data(v42bis_comp_state_t *s, uint16_t code) -{ - int i; - - /* Update compressibility metric */ - /* Integrate at the compressed bit rate, and leak at the pre-compression bit rate */ - s->compression_performance += (s->v42bis_parm_c2 - s->compression_performance*s->string_length*V42BIS_N3/COMPRESSIBILITY_MONITOR); - if (s->transparent) - { - for (i = 0; i < s->string_length; i++) - { - push_octet(s, s->string[i]); - if (s->string[i] == s->escape_code) - { - push_octet(s, V42BIS_EID); - s->escape_code += V42BIS_ESC_STEP; - } - } - } - else - { - /* Allow for any escape octets in the string */ - for (i = 0; i < s->string_length; i++) - { - if (s->string[i] == s->escape_code) - s->escape_code += V42BIS_ESC_STEP; - } - /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ - while (code >= s->v42bis_parm_c3) - { - /* We need to increase the codeword size */ - /* 7.4(a) */ - push_compressed_code(s, V42BIS_STEPUP); - /* 7.4(b) */ - s->v42bis_parm_c2++; - /* 7.4(c) */ - s->v42bis_parm_c3 <<= 1; - /* 7.4(d) this might need to be repeated, so we loop */ - } - /* 7.5 Transfer - output the last state of the string */ - push_compressed_code(s, code); - } - s->string_length = 0; - s->flushed_length = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void go_compressed(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - - s = &ss->compress; - if (!s->transparent) - return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); - /* Switch out of transparent now, between codes. We need to send the octet which did not - match, just before switching. */ - if (s->last_matched) - { - s->update_at = s->last_matched; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - } - push_octet(s, s->escape_code); - push_octet(s, V42BIS_ECM); - s->bit_buffer = 0; - s->transparent = false; -} -/*- End of function --------------------------------------------------------*/ - -static void go_transparent(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - - s = &ss->compress; - if (s->transparent) - return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); - /* Switch into transparent now, between codes, and the unmatched octet should - go out in transparent mode, just below */ - if (s->last_matched) - { - s->update_at = s->last_matched; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - } - s->last_added = 0; - push_compressed_code(s, V42BIS_ETM); - push_octet_alignment(s); - s->transparent = true; -} -/*- End of function --------------------------------------------------------*/ - -static void monitor_for_mode_change(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - - s = &ss->compress; - switch (s->compression_mode) - { - case V42BIS_COMPRESSION_MODE_DYNAMIC: - /* 7.8 Data compressibility test */ - if (s->transparent) - { - if (s->compression_performance < COMPRESSIBILITY_MONITOR - COMPRESSIBILITY_MONITOR_HYSTERESIS) - { - /* 7.8.1 Transition to compressed mode */ - go_compressed(ss); - } - } - else - { - if (s->compression_performance > COMPRESSIBILITY_MONITOR) - { - /* 7.8.2 Transition to transparent mode */ - go_transparent(ss); - } - } - /* 7.8.3 Reset function - TODO */ - break; - case V42BIS_COMPRESSION_MODE_ALWAYS: - if (s->transparent) - go_compressed(ss); - break; - case V42BIS_COMPRESSION_MODE_NEVER: - if (!s->transparent) - go_transparent(ss); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int v42bis_comp_init(v42bis_comp_state_t *s, - int p1, - int p2, - put_msg_func_t handler, - void *user_data, - int max_output_len) -{ - memset(s, 0, sizeof(*s)); - s->v42bis_parm_n2 = p1; - s->v42bis_parm_n7 = p2; - s->handler = handler; - s->user_data = user_data; - s->max_output_len = (max_output_len < V42BIS_MAX_OUTPUT_LENGTH) ? max_output_len : V42BIS_MAX_OUTPUT_LENGTH; - s->output_octet_count = 0; - dictionary_init(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int comp_exit(v42bis_comp_state_t *s) -{ - s->v42bis_parm_n2 = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *ss, const uint8_t buf[], int len) -{ - v42bis_comp_state_t *s; - int i; - uint16_t code; - - s = &ss->compress; - if (!s->v42bis_parm_p0) - { - /* Compression is off - just push the incoming data out */ - push_octets(s, buf, len); - return 0; - } - for (i = 0; i < len; ) - { - /* 6.4 Add the string to the dictionary */ - if (s->update_at) - { - if (match_octet(s, s->update_at, buf[i]) == 0) - s->last_added = add_octet_to_dictionary(s, s->update_at, buf[i]); - s->update_at = 0; - } - /* Match string */ - while (i < len) - { - code = match_octet(s, s->last_matched, buf[i]); - if (code == 0) - { - s->update_at = s->last_matched; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - break; - } - if (code == s->last_added) - { - s->last_added = 0; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - break; - } - s->last_matched = code; - /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry - created by the last invocation of the string matching procedure, then the - next character shall be read and appended to the string and this step - repeated. */ - s->string[s->string_length++] = buf[i++]; - /* 6.4(a) The string must not exceed N7 in length */ - if (s->string_length + s->flushed_length == s->v42bis_parm_n7) - { - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - break; - } - } - monitor_for_mode_change(ss); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - int len; - - s = &ss->compress; - if (s->update_at) - return 0; - if (s->last_matched) - { - len = s->string_length; - send_encoded_data(s, s->last_matched); - s->flushed_length += len; - } - if (!s->transparent) - { - s->update_at = s->last_matched; - s->last_matched = 0; - s->flushed_length = 0; - push_compressed_code(s, V42BIS_FLUSH); - push_octet_alignment(s); - } - flush_octets(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len) -{ - v42bis_comp_state_t *s; - int i; - int j; - int yyy; - uint16_t code; - uint16_t p; - uint8_t ch; - uint8_t in; - - s = &ss->decompress; - if (!s->v42bis_parm_p0) - { - /* Compression is off - just push the incoming data out */ - push_octets(s, buf, len); - return 0; - } - for (i = 0; i < len; ) - { - if (s->transparent) - { - in = buf[i]; - if (s->escaped) - { - /* Command */ - 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->update_at = s->last_matched; - s->last_matched = 0; - i++; - continue; - case V42BIS_EID: - /* Escape symbol */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); - in = s->escape_code; - s->escape_code += V42BIS_ESC_STEP; - break; - case V42BIS_RESET: - /* Reset dictionary */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); - /* TODO: */ - send_string(s); - dictionary_init(s); - i++; - continue; - default: - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); - return -1; - } - } - else if (in == s->escape_code) - { - s->escaped = true; - i++; - continue; - } - - yyy = true; - for (j = 0; j < 2 && yyy; j++) - { - if (s->update_at) - { - if (match_octet(s, s->update_at, in) == 0) - s->last_added = add_octet_to_dictionary(s, s->update_at, in); - s->update_at = 0; - } - - code = match_octet(s, s->last_matched, in); - if (code == 0) - { - s->update_at = s->last_matched; - send_string(s); - s->last_matched = 0; - } - else if (code == s->last_added) - { - s->last_added = 0; - send_string(s); - s->last_matched = 0; - } - else - { - s->last_matched = code; - s->string[s->string_length++] = in; - if (s->string_length + s->flushed_length == s->v42bis_parm_n7) - { - send_string(s); - s->last_matched = 0; - } - i++; - yyy = false; - } - } - } - else - { - /* Get code from input */ - while (s->bit_count < s->v42bis_parm_c2 && i < len) - { - s->bit_buffer |= buf[i++] << s->bit_count; - s->bit_count += 8; - } - if (s->bit_count < s->v42bis_parm_c2) - continue; - code = s->bit_buffer & ((1 << s->v42bis_parm_c2) - 1); - s->bit_buffer >>= s->v42bis_parm_c2; - s->bit_count -= s->v42bis_parm_c2; - - if (code < V42BIS_N6) - { - /* We have a control code. */ - switch (code) - { - case V42BIS_ETM: - /* Enter transparent mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); - s->bit_count = 0; - s->transparent = true; - s->last_matched = 0; - s->last_added = 0; - break; - case V42BIS_FLUSH: - /* Flush signal */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); - s->bit_count = 0; - break; - case V42BIS_STEPUP: - /* Increase code word size */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); - s->v42bis_parm_c2++; - s->v42bis_parm_c3 <<= 1; - if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) - return -1; - break; - } - continue; - } - /* Regular codeword */ - if (code == s->v42bis_parm_c1) - return -1; - expand_codeword_to_string(s, code); - if (s->update_at) - { - ch = s->string[0]; - if ((p = match_octet(s, s->update_at, ch)) == 0) - { - s->last_added = add_octet_to_dictionary(s, s->update_at, ch); - if (code == s->v42bis_parm_c1) - return -1; - } - else if (p == s->last_added) - { - s->last_added = 0; - } - } - s->update_at = ((s->string_length + s->flushed_length) == s->v42bis_parm_n7) ? 0 : code; - /* Allow for any escapes which may be in this string */ - for (j = 0; j < s->string_length; j++) - { - if (s->string[j] == s->escape_code) - s->escape_code += V42BIS_ESC_STEP; - } - send_string(s); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - int len; - - s = &ss->decompress; - len = s->string_length; - send_string(s); - s->flushed_length += len; - flush_octets(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) -{ - s->compress.compression_mode = mode; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v42bis_get_logging_state(v42bis_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, - int negotiated_p0, - int negotiated_p1, - int negotiated_p2, - put_msg_func_t encode_handler, - void *encode_user_data, - int max_encode_len, - put_msg_func_t decode_handler, - void *decode_user_data, - int max_decode_len) -{ - int ret; - - if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE || negotiated_p1 > 65535) - return NULL; - if (negotiated_p2 < V42BIS_MIN_STRING_SIZE || negotiated_p2 > V42BIS_MAX_STRING_SIZE) - return NULL; - if (s == NULL) - { - if ((s = (v42bis_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, "V.42bis"); - - if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) - return NULL; - if ((ret = v42bis_comp_init(&s->decompress, negotiated_p1, negotiated_p2, decode_handler, decode_user_data, max_decode_len))) - { - comp_exit(&s->compress); - return NULL; - } - s->compress.v42bis_parm_p0 = negotiated_p0 & 2; - s->decompress.v42bis_parm_p0 = negotiated_p0 & 1; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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 --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v8.c b/libs/spandsp/src/v8.c deleted file mode 100644 index 318ecad564..0000000000 --- a/libs/spandsp/src/v8.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v8.c - V.8 modem negotiation processing. - * - * 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(HAVE_CONFIG_H) -#include "config.h" -#endif - -#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 "spandsp/telephony.h" -#include "spandsp/alloc.h" -#include "spandsp/logging.h" -#include "spandsp/queue.h" -#include "spandsp/async.h" -#include "spandsp/vector_int.h" -#include "spandsp/complex.h" -#include "spandsp/dds.h" -#include "spandsp/tone_detect.h" -#include "spandsp/tone_generate.h" -#include "spandsp/super_tone_rx.h" -#include "spandsp/power_meter.h" -#include "spandsp/fsk.h" -#include "spandsp/modem_connect_tones.h" -#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" - -enum -{ - /* Start point when sending CI */ - V8_WAIT_1S = 0, - /* Start point when sending initial silence */ - V8_AWAIT_ANSAM, - V8_CI_ON, - V8_CI_OFF, - V8_HEARD_ANSAM, - V8_CM_ON, - V8_CJ_ON, - V8_CM_WAIT, - - V8_SIGC, - V8_JM_ON, - V8_SIGA, - - V8_PARKED -} v8_states_e; - -enum -{ - V8_SYNC_UNKNOWN = 0, - V8_SYNC_CI, - V8_SYNC_CM_JM, - V8_SYNC_V92 -} v8_sync_types_e; - -enum -{ - V8_CALL_FUNCTION_TAG = 0x01, - V8_MODULATION_TAG = 0x05, - V8_PROTOCOLS_TAG = 0x0A, - V8_PSTN_ACCESS_TAG = 0x0D, - V8_NSF_TAG = 0x0F, - V8_PCM_MODEM_AVAILABILITY_TAG = 0x07, - V8_T66_TAG = 0x0E -}; - -enum -{ - V8_CI_SYNC_OCTET = 0x00, - V8_CM_JM_SYNC_OCTET = 0xE0, - V8_V92_SYNC_OCTET = 0x55 -}; - -#define Te_TIMEOUT 500 - -SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function) -{ - switch (call_function) - { - case V8_CALL_TBS: - return "TBS"; - case V8_CALL_H324: - return "H.324 PSTN multimedia terminal"; - case V8_CALL_V18: - return "V.18 textphone"; - case V8_CALL_T101: - return "T.101 videotext"; - case V8_CALL_T30_TX: - return "T.30 Tx FAX"; - case V8_CALL_T30_RX: - return "T.30 Rx FAX"; - case V8_CALL_V_SERIES: - return "V series modem data"; - case V8_CALL_FUNCTION_EXTENSION: - return "Call function is in extension octet"; - } - /*endswitch*/ - return "Unknown call function"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) v8_modulation_to_str(int modulation_scheme) -{ - switch (modulation_scheme) - { - case V8_MOD_V17: - return "V.17 half-duplex"; - case V8_MOD_V21: - return "V.21 duplex"; - case V8_MOD_V22: - return "V.22/V.22bis duplex"; - case V8_MOD_V23HDX: - return "V.23 half-duplex"; - case V8_MOD_V23: - return "V.23 duplex"; - case V8_MOD_V26BIS: - return "V.26bis duplex"; - case V8_MOD_V26TER: - return "V.26ter duplex"; - case V8_MOD_V27TER: - return "V.27ter duplex"; - case V8_MOD_V29: - return "V.29 half-duplex"; - case V8_MOD_V32: - return "V.32/V.32bis duplex"; - case V8_MOD_V34HDX: - return "V.34 half-duplex"; - case V8_MOD_V34: - return "V.34 duplex"; - case V8_MOD_V90: - return "V.90 duplex"; - case V8_MOD_V92: - return "V.92 duplex"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol) -{ - switch (protocol) - { - case V8_PROTOCOL_NONE: - return "None"; - case V8_PROTOCOL_LAPM_V42: - return "LAPM"; - case V8_PROTOCOL_EXTENSION: - return "Extension"; - } - /*endswitch*/ - return "Undefined"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access) -{ - switch (pstn_access) - { - case V8_PSTN_ACCESS_CALL_DCE_CELLULAR: - 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): - 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): - return "DCE on digital, and calling modem on 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): - return "DCE on digital, and answering and calling modems on cellular"; - } - /*endswitch*/ - return "PSTN access unknown"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf) -{ - switch (nsf) - { - case 0: - return "???"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability) -{ - switch (pcm_modem_availability) - { - case 0: - return "PCM unavailable"; - case V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: - 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): - 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): - return "V.91 and V.90/V.92 analogue available"; - 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): - return "V.91 and V.90/V.92 digital/analogue available"; - } - /*endswitch*/ - return "PCM availability unknown"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(const char *) v8_t66_to_str(int t66) -{ - /* T.66 doesn't really define any V.8 values. The bits are all reserved. */ - switch (t66) - { - case 0: - return "???"; - case 1: - return "Reserved TIA"; - case 2: - return "Reserved"; - case 3: - return "Reserved TIA + others"; - case 4: - return "Reserved"; - case 5: - return "Reserved TIA + others"; - case 6: - return "Reserved"; - case 7: - return "Reserved TIA + others"; - } - /*endswitch*/ - return "???"; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v8_log_supported_modulations(v8_state_t *s, int modulation_schemes) -{ - const char *comma; - int i; - - comma = ""; - span_log(&s->logging, SPAN_LOG_FLOW, ""); - for (i = 0; i < 32; i++) - { - if ((modulation_schemes & (1 << i))) - { - span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s%s", comma, v8_modulation_to_str(modulation_schemes & (1 << i))); - comma = ", "; - } - /*endif*/ - } - /*endfor*/ - span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " supported\n"); -} -/*- End of function --------------------------------------------------------*/ - -static int report_event(v8_state_t *s) -{ - if (s->result_handler) - s->result_handler(s->result_handler_user_data, &s->result); - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_call_function(v8_state_t *s, const uint8_t *p) -{ - s->result.call_function = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(s->result.call_function)); - return ++p; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p) -{ - unsigned int modulations; - - /* Modulation mode octets */ - /* We must record the number of bytes of modulation information, so a resulting - JM can be made to have the same number (V.8/8.2.3) */ - modulations = 0; - s->modulation_bytes = 1; - if (*p & 0x80) - modulations |= V8_MOD_V34HDX; - /*endif*/ - if (*p & 0x40) - modulations |= V8_MOD_V34; - /*endif*/ - if (*p & 0x20) - modulations |= V8_MOD_V90; - /*endif*/ - ++p; - - /* Check for an extension octet */ - if ((*p & 0x38) == 0x10) - { - s->modulation_bytes++; - if (*p & 0x80) - modulations |= V8_MOD_V27TER; - /*endif*/ - if (*p & 0x40) - modulations |= V8_MOD_V29; - /*endif*/ - if (*p & 0x04) - modulations |= V8_MOD_V17; - /*endif*/ - if (*p & 0x02) - modulations |= V8_MOD_V22; - /*endif*/ - if (*p & 0x01) - modulations |= V8_MOD_V32; - /*endif*/ - ++p; - - /* Check for an extension octet */ - if ((*p & 0x38) == 0x10) - { - s->modulation_bytes++; - if (*p & 0x80) - modulations |= V8_MOD_V21; - /*endif*/ - if (*p & 0x40) - modulations |= V8_MOD_V23HDX; - /*endif*/ - if (*p & 0x04) - modulations |= V8_MOD_V23; - /*endif*/ - if (*p & 0x02) - modulations |= V8_MOD_V26BIS; - /*endif*/ - if (*p & 0x01) - modulations |= V8_MOD_V26TER; - /*endif*/ - ++p; - } - /*endif*/ - } - /*endif*/ - s->result.modulations = modulations; - v8_log_supported_modulations(s, modulations); - return p; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_protocols(v8_state_t *s, const uint8_t *p) -{ - s->result.protocol = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_protocol_to_str(s->result.protocol)); - return ++p; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_pstn_access(v8_state_t *s, const uint8_t *p) -{ - s->result.pstn_access = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_pstn_access_to_str(s->result.pstn_access)); - return ++p; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_non_standard_facilities(v8_state_t *s, const uint8_t *p) -{ - /* TODO: This is wrong */ - s->result.nsf = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_nsf_to_str(s->result.nsf)); - return p; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_pcm_modem_availability(v8_state_t *s, const uint8_t *p) -{ - s->result.pcm_modem_availability = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_pcm_modem_availability_to_str(s->result.pcm_modem_availability)); - return ++p; -} -/*- End of function --------------------------------------------------------*/ - -static const uint8_t *process_t66(v8_state_t *s, const uint8_t *p) -{ - s->result.t66 = (*p >> 5) & 0x07; - span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_t66_to_str(s->result.t66)); - return ++p; -} -/*- End of function --------------------------------------------------------*/ - -static void ci_decode(v8_state_t *s) -{ - if ((s->rx_data[0] & 0x1F) == V8_CALL_FUNCTION_TAG) - process_call_function(s, &s->rx_data[0]); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void cm_jm_decode(v8_state_t *s) -{ - const uint8_t *p; - - if (s->got_cm_jm) - return; - /*endif*/ - - /* We must receive two consecutive identical CM or JM sequences to accept it. */ - if (s->cm_jm_len <= 0 - || - s->cm_jm_len != s->rx_data_ptr - || - memcmp(s->cm_jm_data, s->rx_data, s->rx_data_ptr)) - { - /* Save the current CM or JM sequence */ - s->cm_jm_len = s->rx_data_ptr; - memcpy(s->cm_jm_data, s->rx_data, s->rx_data_ptr); - return; - } - /*endif*/ - /* We have a matching pair of CMs or JMs, so we are happy this is correct. */ - s->got_cm_jm = true; - - span_log(&s->logging, SPAN_LOG_FLOW, "Decoding\n"); - - /* Zero indicates the end */ - s->cm_jm_data[s->cm_jm_len] = 0; - - s->result.modulations = 0; - p = s->cm_jm_data; - - while (*p) - { - switch (*p & 0x1F) - { - case V8_CALL_FUNCTION_TAG: - p = process_call_function(s, p); - break; - case V8_MODULATION_TAG: - p = process_modulation_mode(s, p); - break; - case V8_PROTOCOLS_TAG: - p = process_protocols(s, p); - break; - case V8_PSTN_ACCESS_TAG: - p = process_pstn_access(s, p); - break; - case V8_NSF_TAG: - p = process_non_standard_facilities(s, p); - break; - case V8_PCM_MODEM_AVAILABILITY_TAG: - p = process_pcm_modem_availability(s, p); - break; - case V8_T66_TAG: - p = process_t66(s, p); - break; - default: - p++; - break; - } - /*endswitch*/ - /* Skip any future extensions we do not understand */ - while ((*p & 0x38) == 0x10) - p++; - /*endwhile*/ - } - /*endwhile*/ -} -/*- End of function --------------------------------------------------------*/ - -static void put_bit(void *user_data, int bit) -{ - v8_state_t *s; - int new_preamble_type; - const char *tag; - uint8_t data; - - s = user_data; - if (bit < 0) - { - /* Special conditions */ - switch (bit) - { - case SIG_STATUS_CARRIER_UP: - case SIG_STATUS_CARRIER_DOWN: - case SIG_STATUS_TRAINING_SUCCEEDED: - case SIG_STATUS_TRAINING_FAILED: - break; - default: - break; - } - /*endswitch*/ - return; - } - /*endif*/ - //span_log(&s->logging, SPAN_LOG_FLOW, "Bit %d\n", bit); - /* Wait until we sync. */ - s->bit_stream = (s->bit_stream >> 1) | (bit << 19); - /* CI preamble is 10 ones then a framed 0x00 - CM/JM preamble is 10 ones then a framed 0x07 - V.92 preamble is 10 ones then a framed 0x55 - Should we look at all 10 ones? The first couple might be - settling down. */ - /* The preamble + synchronisation bit sequence should be unique in - any bit stream, so we can rely on seeing this at any time as being - a real sync code. */ - switch (s->bit_stream) - { - case 0x803FF: - new_preamble_type = V8_SYNC_CI; - break; - case 0xF03FF: - new_preamble_type = V8_SYNC_CM_JM; - break; - case 0xAABFF: - new_preamble_type = V8_SYNC_V92; - break; - default: - new_preamble_type = V8_SYNC_UNKNOWN; - break; - } - /*endswitch*/ - if (new_preamble_type != V8_SYNC_UNKNOWN) - { - /* We have seen a fresh sync code */ - /* Debug */ - if (span_log_test(&s->logging, SPAN_LOG_FLOW)) - { - if (s->preamble_type != V8_SYNC_UNKNOWN) - { - switch (s->preamble_type) - { - case V8_SYNC_CI: - tag = ">CI: "; - break; - case V8_SYNC_CM_JM: - tag = (s->calling_party) ? ">JM: " : ">CM: "; - break; - case V8_SYNC_V92: - tag = ">V.92: "; - break; - default: - tag = ">??: "; - break; - } - /*endswitch*/ - span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr); - } - /*endif*/ - } - /*endif*/ - /* If we were handling a valid sync code then we should process what has been - received to date. */ - switch (s->preamble_type) - { - case V8_SYNC_CI: - ci_decode(s); - break; - case V8_SYNC_CM_JM: - cm_jm_decode(s); - break; - } - /*endswitch*/ - s->preamble_type = new_preamble_type; - s->bit_cnt = 0; - s->rx_data_ptr = 0; - } - /*endif*/ - - if (s->preamble_type != V8_SYNC_UNKNOWN) - { - /* Parse octets with 1 bit start, 1 bit stop */ - s->bit_cnt++; - /* Start, stop? */ - if ((s->bit_stream & 0x80400) == 0x80000 && s->bit_cnt >= 10) - { - /* Store the available data */ - data = (uint8_t) ((s->bit_stream >> 11) & 0xFF); - /* CJ (3 successive zero octets) detection */ - if (data == 0) - { - if (++s->zero_byte_count == 3) - s->got_cj = true; - /*endif*/ - } - else - { - s->zero_byte_count = 0; - } - /*endif*/ - - if (s->rx_data_ptr < (int) (sizeof(s->rx_data) - 1)) - s->rx_data[s->rx_data_ptr++] = data; - /*endif*/ - s->bit_cnt = 0; - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void v8_decode_init(v8_state_t *s) -{ - fsk_rx_init(&s->v21rx, - &preset_fsk_specs[(s->calling_party) ? FSK_V21CH2 : FSK_V21CH1], - FSK_FRAME_MODE_ASYNC, - put_bit, - s); - fsk_rx_signal_cutoff(&s->v21rx, -45.5f); - 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->zero_byte_count = 0; - s->rx_data_ptr = 0; -} -/*- End of function --------------------------------------------------------*/ - -static int get_bit(void *user_data) -{ - v8_state_t *s; - uint8_t bit; - - s = user_data; - if (queue_read(s->tx_queue, &bit, 1) <= 0) - return SIG_STATUS_END_OF_DATA; - /*endif*/ - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static void v8_put_preamble(v8_state_t *s) -{ - static const uint8_t preamble[10] = - { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - }; - - queue_write(s->tx_queue, preamble, 10); -} -/*- End of function --------------------------------------------------------*/ - -static void v8_put_bytes(v8_state_t *s, uint8_t buf[], int len) -{ - int i; - int j; - uint8_t byte; - uint8_t bits[10]; - - /* Insert start & stop bits */ - for (i = 0; i < len; i++) - { - bits[0] = 0; - byte = buf[i]; - for (j = 1; j < 9; j++) - { - bits[j] = byte & 1; - byte >>= 1; - } - /*endfor*/ - bits[9] = 1; - queue_write(s->tx_queue, bits, 10); - } - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static void send_cm_jm(v8_state_t *s) -{ - int val; - unsigned int offered_modulations; - int bytes; - uint8_t buf[10]; - int ptr; - - /* Send a CM, or a JM as appropriate */ - v8_put_preamble(s); - ptr = 0; - buf[ptr++] = V8_CM_JM_SYNC_OCTET; - /* Data call */ - buf[ptr++] = (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG; - - /* Supported modulations */ - offered_modulations = s->result.modulations; - bytes = 0; - val = 0x05; - if (offered_modulations & V8_MOD_V90) - val |= 0x20; - /*endif*/ - if (offered_modulations & V8_MOD_V34) - val |= 0x40; - /*endif*/ - if (offered_modulations & V8_MOD_V34HDX) - val |= 0x80; - /*endif*/ - buf[ptr++] = val; - if (++bytes < s->modulation_bytes) - { - val = 0x10; - if (offered_modulations & V8_MOD_V32) - val |= 0x01; - /*endif*/ - if (offered_modulations & V8_MOD_V22) - val |= 0x02; - /*endif*/ - if (offered_modulations & V8_MOD_V17) - val |= 0x04; - /*endif*/ - if (offered_modulations & V8_MOD_V29) - val |= 0x40; - /*endif*/ - if (offered_modulations & V8_MOD_V27TER) - val |= 0x80; - /*endif*/ - buf[ptr++] = val; - } - /*endif*/ - if (++bytes < s->modulation_bytes) - { - val = 0x10; - if (offered_modulations & V8_MOD_V26TER) - val |= 0x01; - /*endif*/ - if (offered_modulations & V8_MOD_V26BIS) - val |= 0x02; - /*endif*/ - if (offered_modulations & V8_MOD_V23) - val |= 0x04; - /*endif*/ - if (offered_modulations & V8_MOD_V23HDX) - val |= 0x40; - /*endif*/ - if (offered_modulations & V8_MOD_V21) - val |= 0x80; - /*endif*/ - buf[ptr++] = val; - } - /*endif*/ - if (s->parms.protocol) - buf[ptr++] = (s->parms.protocol << 5) | V8_PROTOCOLS_TAG; - /*endif*/ - if (s->parms.pstn_access) - buf[ptr++] = (s->parms.pstn_access << 5) | V8_PSTN_ACCESS_TAG; - /*endif*/ - if (s->parms.pcm_modem_availability) - buf[ptr++] = (s->parms.pcm_modem_availability << 5) | V8_PCM_MODEM_AVAILABILITY_TAG; - /*endif*/ - if (s->parms.t66 >= 0) - buf[ptr++] = (s->parms.t66 << 5) | V8_T66_TAG; - /*endif*/ - /* No NSF */ - //buf[ptr++] = (0 << 5) | V8_NSF_TAG; - span_log_buf(&s->logging, SPAN_LOG_FLOW, (s->calling_party) ? "logging, SPAN_LOG_FLOW, "v8_tx state %d\n", s->state); - len = 0; - if (s->modem_connect_tone_tx_on) - { - if (s->modem_connect_tone_tx_on == (milliseconds_to_samples(75) + 2)) - { - if (s->fsk_tx_on) - { - /* The initial silence is over */ - s->modem_connect_tone_tx_on = 0; - } - /*endif*/ - } - else if (s->modem_connect_tone_tx_on == (milliseconds_to_samples(75) + 1)) - { - /* Send the ANSam tone */ - len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len); - if (len < max_len) - { - span_log(&s->logging, SPAN_LOG_FLOW, "ANSam or ANSam/ ended\n"); - s->modem_connect_tone_tx_on = milliseconds_to_samples(75); - } - /*endif*/ - } - else - { - /* Send the 75ms of silence after the ANSam tone */ - if (max_len > s->modem_connect_tone_tx_on) - len = s->modem_connect_tone_tx_on; - else - len = max_len; - /*endif*/ - vec_zeroi16(amp, len); - s->modem_connect_tone_tx_on -= len; - } - /*endif*/ - } - /*endif*/ - if (s->fsk_tx_on && len < max_len) - { - len += fsk_tx(&s->v21tx, &[len], max_len - len); - if (len < max_len) - { - span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends (%d/%d) %d %d\n", len, max_len, s->fsk_tx_on, s->state); - s->fsk_tx_on = false; - //s->state = V8_PARKED; - } - /*endif*/ - } - /*endif*/ - if (s->state != V8_PARKED && len < max_len) - { - vec_zeroi16(&[len], max_len - len); - len = max_len; - } - /*endif*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void conditionally_send_v92(v8_state_t *s) -{ - int i; - uint8_t buf[2]; - - if (s->parms.v92 >= 0) - { - /* Send 2 V.92 packets */ - for (i = 0; i < 2; i++) - { - v8_put_preamble(s); - buf[0] = V8_V92_SYNC_OCTET; - buf[1] = s->parms.v92; - span_log_buf(&s->logging, SPAN_LOG_FLOW, "result.call_function << 5) | V8_CALL_FUNCTION_TAG; - span_log_buf(&s->logging, SPAN_LOG_FLOW, "result.modem_connect_tone = tone; - span_log(&s->logging, SPAN_LOG_FLOW, "'%s' recognised\n", modem_connect_tone_to_str(tone)); - if (tone == MODEM_CONNECT_TONES_ANSAM - || - tone == MODEM_CONNECT_TONES_ANSAM_PR) - { - /* Set the Te interval. The spec. says 500ms is the minimum, - but gives reasons why 1 second is a better value (V.8/8.1.1). */ - s->state = V8_HEARD_ANSAM; - s->ci_timer = milliseconds_to_samples(2*Te_TIMEOUT); - s->negotiation_timer = milliseconds_to_samples(5000); - v8_decode_init(s); - } - else - { - /* If we found a connect tone, and it isn't one of the modulated answer tones, - indicating V.8 startup, we are not going to do V.8 processing. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Non-V.8 modem connect tone detected\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_NON_V8_CALL; - report_event(s); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) -{ - int residual_samples; - int tone; - uint8_t buf[3]; - - //span_log(&s->logging, SPAN_LOG_FLOW, "v8_rx state %d\n", s->state); - residual_samples = 0; - switch (s->state) - { - case V8_WAIT_1S: - residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); - /* Wait 1 second before sending the first CI packet */ - if ((s->negotiation_timer -= len) > 0) - break; - /*endif*/ - fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); - send_ci(s); - s->state = V8_CI_ON; - s->fsk_tx_on = true; - break; - case V8_CI_ON: - residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); - /* Check if an ANSam or ANSam/ tone has been detected */ - if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) - { - handle_modem_connect_tone(s, tone); - break; - } - /*endif*/ - if (!s->fsk_tx_on) - { - s->state = V8_CI_OFF; - s->ci_timer = milliseconds_to_samples(Te_TIMEOUT); - s->negotiation_timer = milliseconds_to_samples(5000); - break; - } - /*endif*/ - break; - case V8_CI_OFF: - residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); - /* Check if an ANSam or ANSam/ tone has been detected */ - if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) - { - handle_modem_connect_tone(s, tone); - break; - } - /*endif*/ - if ((s->ci_timer -= len) <= 0) - { - if (++s->ci_count >= 10) - { - /* The spec says we should give up now. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for modem connect tone\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_FAILED; - report_event(s); - } - else - { - /* Try again */ - fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); - send_ci(s); - s->state = V8_CI_ON; - s->fsk_tx_on = true; - } - /*endif*/ - } - /*endif*/ - break; - case V8_AWAIT_ANSAM: - residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); - /* Check if an ANSam or ANSam/ tone has been detected */ - if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) - handle_modem_connect_tone(s, tone); - /*endif*/ - break; - case V8_HEARD_ANSAM: - /* We have heard the ANSam or ANSam/ signal, but we still need to wait for the - end of the Te timeout period to comply with the spec. */ - if ((s->ci_timer -= len) <= 0) - { - fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); - conditionally_send_v92(s); - send_cm_jm(s); - s->fsk_tx_on = true; - s->state = V8_CM_ON; - } - /*endif*/ - /* Fall through */ - case V8_CM_ON: - residual_samples = fsk_rx(&s->v21rx, amp, len); - if (s->got_cm_jm) - { - span_log(&s->logging, SPAN_LOG_FLOW, "JM recognised\n"); - /* Now JM has been detected, we send CJ and wait for 75 ms - before finishing the V.8 analysis. */ - fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); - memset(buf, 0, 3); - v8_put_bytes(s, buf, 3); - span_log_buf(&s->logging, SPAN_LOG_FLOW, "state = V8_CJ_ON; - s->fsk_tx_on = true; - break; - } - /*endif*/ - if ((s->negotiation_timer -= len) <= 0) - { - /* Timeout */ - span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for JM\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_FAILED; - report_event(s); - } - /*endif*/ - if (queue_contents(s->tx_queue) < 10) - { - /* Send CM again */ - send_cm_jm(s); - } - /*endif*/ - break; - case V8_CJ_ON: - residual_samples = fsk_rx(&s->v21rx, amp, len); - if (!s->fsk_tx_on) - { -#if 0 - s->negotiation_timer = milliseconds_to_samples(75); - s->state = V8_SIGC; - } - /*endif*/ - break; - case V8_SIGC: - if ((s->negotiation_timer -= len) <= 0) - { -#endif - /* The V.8 negotiation has succeeded. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_V8_CALL; - report_event(s); - } - /*endif*/ - break; - case V8_CM_WAIT: - residual_samples = fsk_rx(&s->v21rx, amp, len); - if (s->got_cm_jm) - { - span_log(&s->logging, SPAN_LOG_FLOW, "CM recognised\n"); - - s->result.status = V8_STATUS_V8_OFFERED; - report_event(s); - - /* Stop sending ANSam or ANSam/ and send JM instead */ - fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH2], get_bit, s); - /* Set the timeout for JM */ - s->negotiation_timer = milliseconds_to_samples(5000); - s->state = V8_JM_ON; - send_cm_jm(s); - s->modem_connect_tone_tx_on = milliseconds_to_samples(75); - s->fsk_tx_on = true; - break; - } - /*endif*/ - if ((s->negotiation_timer -= len) <= 0) - { - /* Timeout */ - span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CM\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_FAILED; - report_event(s); - } - /*endif*/ - break; - case V8_JM_ON: - residual_samples = fsk_rx(&s->v21rx, amp, len); - if (s->got_cj) - { - span_log(&s->logging, SPAN_LOG_FLOW, "CJ recognised\n"); - /* Stop sending JM, flushing anything left in the buffer, and wait 75 ms */ - queue_flush(s->tx_queue); - s->negotiation_timer = milliseconds_to_samples(75); - s->state = V8_SIGA; - break; - } - /*endif*/ - if ((s->negotiation_timer -= len) <= 0) - { - /* Timeout */ - span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CJ\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_FAILED; - report_event(s); - break; - } - /*endif*/ - if (queue_contents(s->tx_queue) < 10) - { - /* Send JM */ - send_cm_jm(s); - } - /*endif*/ - break; - case V8_SIGA: - if (!s->fsk_tx_on) - //if ((s->negotiation_timer -= len) <= 0) - { - /* The V.8 negotiation has succeeded. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n"); - s->state = V8_PARKED; - s->result.status = V8_STATUS_V8_CALL; - report_event(s); - } - /*endif*/ - break; - case V8_PARKED: - residual_samples = len; - break; - } - /*endswitch*/ - return residual_samples; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -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)); - - s->result.status = V8_STATUS_IN_PROGRESS; - s->result.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - s->result.modulations = s->parms.modulations; - s->result.call_function = s->parms.call_function; - s->result.nsf = -1; - s->result.t66 = -1; - - s->modulation_bytes = 3; - - s->ci_timer = 0; - s->calling_party = calling_party; - if (s->calling_party) - { - if (s->result.send_ci) - { - s->state = V8_WAIT_1S; - s->negotiation_timer = milliseconds_to_samples(1000); - s->ci_count = 0; - } - else - { - s->state = V8_AWAIT_ANSAM; - } - /*endif*/ - modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); - fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s); - s->modem_connect_tone_tx_on = milliseconds_to_samples(75) + 2; - } - else - { - /* Send the ANSam or ANSam/ tone */ - s->state = V8_CM_WAIT; - s->negotiation_timer = milliseconds_to_samples(200 + 5000); - v8_decode_init(s); - modem_connect_tones_tx_init(&s->ansam_tx, s->parms.modem_connect_tone); - s->modem_connect_tone_tx_on = milliseconds_to_samples(75) + 1; - } - /*endif*/ - if (s->tx_queue) - queue_free(s->tx_queue); - /*endif*/ - if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL) - return -1; - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, - bool calling_party, - v8_parms_t *parms, - v8_result_handler_t result_handler, - void *user_data) -{ - if (s == NULL) - { - if ((s = (v8_state_t *) span_alloc(sizeof(*s))) == NULL) - return NULL; - /*endif*/ - } - /*endif*/ - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "V.8"); - s->result_handler = result_handler; - s->result_handler_user_data = user_data; - - v8_restart(s, calling_party, parms); - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v8_release(v8_state_t *s) -{ - return queue_free(s->tx_queue); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v8_free(v8_state_t *s) -{ - int ret; - - ret = v8_release(s); - span_free(s); - return ret; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/vector_float.c b/libs/spandsp/src/vector_float.c deleted file mode 100644 index b02e4288a9..0000000000 --- a/libs/spandsp/src/vector_float.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * vector_float.c - Floating vector arithmetic routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 -#include - -#include "floating_fudge.h" -#include "mmx_sse_decs.h" - -#include "spandsp/telephony.h" -#include "spandsp/vector_float.h" - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_copyf(float z[], const float x[], int n) -{ - int i; - __m128 n1; - - if ((i = n & ~3)) - { - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - _mm_storeu_ps(z + i, n1); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3]; - case 2: - z[n - 2] = x[n - 2]; - case 1: - z[n - 1] = x[n - 1]; - } -} -#else -SPAN_DECLARE(void) vec_copyf(float z[], const float x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_copy(double z[], const double x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_copyl(long double z[], const long double x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n) -{ - int i; - static const uint32_t mask = 0x80000000; - static const float *fmask = (float *) &mask; - __m128 n1; - __m128 n2; - - if ((i = n & ~3)) - { - n2 = _mm_set1_ps(*fmask); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n1 = _mm_xor_ps(n1, n2); - _mm_storeu_ps(z + i, n1); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = -x[n - 3]; - case 2: - z[n - 2] = -x[n - 2]; - case 1: - z[n - 1] = -x[n - 1]; - } -} -#else -SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = -x[i]; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_negate(double z[], const double x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = -x[i]; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_negatel(long double z[], const long double x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = -x[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_zerof(float z[], int n) -{ - int i; - __m128 n1; - - if ((i = n & ~3)) - { - n1 = _mm_setzero_ps(); - for (i -= 4; i >= 0; i -= 4) - _mm_storeu_ps(z + i, n1); - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = 0; - case 2: - z[n - 2] = 0; - case 1: - z[n - 1] = 0; - } -} -#else -SPAN_DECLARE(void) vec_zerof(float z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = 0.0f; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_zero(double z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = 0.0; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_zerol(long double z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = 0.0L; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_setf(float z[], float x, int n) -{ - int i; - __m128 n1; - - if ((i = n & ~3)) - { - n1 = _mm_set1_ps(x); - for (i -= 4; i >= 0; i -= 4) - _mm_storeu_ps(z + i, n1); - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x; - case 2: - z[n - 2] = x; - case 1: - z[n - 1] = x; - } -} -#else -SPAN_DECLARE(void) vec_setf(float z[], float x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_set(double z[], double x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_setl(long double z[], long double x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_addf(float z[], const float x[], const float y[], int n) -{ - int i; - __m128 n1; - __m128 n2; - - if ((i = n & ~3)) - { - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n2 = _mm_add_ps(n1, n2); - _mm_storeu_ps(z + i, n2); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3] + y[n - 3]; - case 2: - z[n - 2] = x[n - 2] + y[n - 2]; - case 1: - z[n - 1] = x[n - 1] + y[n - 1]; - } -} -#else -SPAN_DECLARE(void) vec_addf(float z[], const float x[], const float y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_add(double z[], const double x[], const double y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_addl(long double z[], const long double x[], const long double y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_scaledxy_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n) -{ - int i; - __m128 n1; - __m128 n2; - __m128 n3; - __m128 n4; - - if ((i = n & ~3)) - { - n3 = _mm_set1_ps(x_scale); - n4 = _mm_set1_ps(y_scale); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n1 = _mm_mul_ps(n1, n3); - n2 = _mm_mul_ps(n2, n4); - n2 = _mm_add_ps(n1, n2); - _mm_storeu_ps(z + i, n2); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3]*x_scale + y[n - 3]*y_scale; - case 2: - z[n - 2] = x[n - 2]*x_scale + y[n - 2]*y_scale; - case 1: - z[n - 1] = x[n - 1]*x_scale + y[n - 1]*y_scale; - } -} -#else -SPAN_DECLARE(void) vec_scaledxy_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale + y[i]*y_scale; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_scaledxy_add(double z[], const double x[], double x_scale, const double y[], double y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale + y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledxy_addl(long double z[], const long double x[], long double x_scale, const long double y[], long double y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale + y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_scaledy_addf(float z[], const float x[], const float y[], float y_scale, int n) -{ - int i; - __m128 n1; - __m128 n2; - __m128 n3; - - if ((i = n & ~3)) - { - n3 = _mm_set1_ps(y_scale); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n2 = _mm_mul_ps(n2, n3); - n2 = _mm_add_ps(n1, n2); - _mm_storeu_ps(z + i, n2); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3] + y[n - 3]*y_scale; - case 2: - z[n - 2] = x[n - 2] + y[n - 2]*y_scale; - case 1: - z[n - 1] = x[n - 1] + y[n - 1]*y_scale; - } -} -#else -SPAN_DECLARE(void) vec_scaledy_addf(float z[], const float x[], const float y[], float y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]*y_scale; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_scaledy_add(double z[], const double x[], const double y[], double y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledy_addl(long double z[], const long double x[], const long double y[], long double y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_subf(float z[], const float x[], const float y[], int n) -{ - int i; - __m128 n1; - __m128 n2; - - if ((i = n & ~3)) - { - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n2 = _mm_sub_ps(n1, n2); - _mm_storeu_ps(z + i, n2); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3] - y[n - 3]; - case 2: - z[n - 2] = x[n - 2] - y[n - 2]; - case 1: - z[n - 1] = x[n - 1] - y[n - 1]; - } -} -#else -SPAN_DECLARE(void) vec_subf(float z[], const float x[], const float y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y[i]; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_sub(double z[], const double x[], const double y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y[i]; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_subl(long double z[], const long double x[], const long double y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(void) vec_scaledxy_subf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale - y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_scaledxy_sub(double z[], const double x[], double x_scale, const double y[], double y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale - y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scaledxy_subl(long double z[], const long double x[], long double x_scale, const long double y[], long double y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale - y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_scalar_mulf(float z[], const float x[], float y, int n) -{ - int i; - __m128 n1; - __m128 n2; - - if ((i = n & ~3)) - { - n2 = _mm_set1_ps(y); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n1 = _mm_mul_ps(n1, n2); - _mm_storeu_ps(z + i, n1); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3]*y; - case 2: - z[n - 2] = x[n - 2]*y; - case 1: - z[n - 1] = x[n - 1]*y; - } -} -#else -SPAN_DECLARE(void) vec_scalar_mulf(float z[], const float x[], float y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*y; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_scalar_mul(double z[], const double x[], double y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*y; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_scalar_addf(float z[], const float x[], float y, int n) -{ - int i; - __m128 n1; - __m128 n2; - - if ((i = n & ~3)) - { - n2 = _mm_set1_ps(y); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n1 = _mm_add_ps(n1, n2); - _mm_storeu_ps(z + i, n1); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3] + y; - case 2: - z[n - 2] = x[n - 2] + y; - case 1: - z[n - 1] = x[n - 1] + y; - } -} -#else -SPAN_DECLARE(void) vec_scalar_addf(float z[], const float x[], float y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_scalar_add(double z[], const double x[], double y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scalar_addl(long double z[], const long double x[], long double y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_scalar_subf(float z[], const float x[], float y, int n) -{ - int i; - __m128 n1; - __m128 n2; - - if ((i = n & ~3)) - { - n2 = _mm_set1_ps(y); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n1 = _mm_sub_ps(n1, n2); - _mm_storeu_ps(z + i, n1); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3] - y; - case 2: - z[n - 2] = x[n - 2] - y; - case 1: - z[n - 1] = x[n - 1] - y; - } -} -#else -SPAN_DECLARE(void) vec_scalar_subf(float z[], const float x[], float y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y; -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_scalar_sub(double z[], const double x[], double y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_scalar_subl(long double z[], const long double x[], long double y, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_mulf(float z[], const float x[], const float y[], int n) -{ - int i; - __m128 n1; - __m128 n2; - __m128 n3; - - if ((i = n & ~3)) - { - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n3 = _mm_mul_ps(n1, n2); - _mm_storeu_ps(z + i, n3); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z[n - 3] = x[n - 3]*y[n - 3]; - case 2: - z[n - 2] = x[n - 2]*y[n - 2]; - case 1: - z[n - 1] = x[n - 1]*y[n - 1]; - } -} -#else -SPAN_DECLARE(void) vec_mulf(float z[], const float x[], const float y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*y[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(void) vec_mul(double z[], const double x[], const double y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*y[i]; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(void) vec_mull(long double z[], const long double x[], const long double y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*y[i]; -} -/*- End of function --------------------------------------------------------*/ -#endif - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(float) vec_dot_prodf(const float x[], const float y[], int n) -{ - int i; - float z; - __m128 n1; - __m128 n2; - __m128 n3; - __m128 n4; - - z = 0.0f; - if ((i = n & ~3)) - { - n4 = _mm_setzero_ps(); //sets sum to zero - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n3 = _mm_mul_ps(n1, n2); - n4 = _mm_add_ps(n4, n3); - } - n4 = _mm_add_ps(_mm_movehl_ps(n4, n4), n4); - n4 = _mm_add_ss(_mm_shuffle_ps(n4, n4, 1), n4); - _mm_store_ss(&z, n4); - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - z += x[n - 3]*y[n - 3]; - case 2: - z += x[n - 2]*y[n - 2]; - case 1: - z += x[n - 1]*y[n - 1]; - } - return z; -} -#else -SPAN_DECLARE(float) vec_dot_prodf(const float x[], const float y[], int n) -{ - int i; - float z; - - z = 0.0f; - for (i = 0; i < n; i++) - z += x[i]*y[i]; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(double) vec_dot_prod(const double x[], const double y[], int n) -{ - int i; - double z; - - z = 0.0; - for (i = 0; i < n; i++) - z += x[i]*y[i]; - return z; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_LONG_DOUBLE) -SPAN_DECLARE(long double) vec_dot_prodl(const long double x[], const long double y[], int n) -{ - int i; - long double z; - - z = 0.0L; - for (i = 0; i < n; i++) - z += x[i]*y[i]; - return z; -} -/*- End of function --------------------------------------------------------*/ -#endif - -SPAN_DECLARE(float) vec_circular_dot_prodf(const float x[], const float y[], int n, int pos) -{ - float z; - - z = vec_dot_prodf(&x[pos], &y[0], n - pos); - z += vec_dot_prodf(&x[0], &y[n - pos], pos); - return z; -} -/*- End of function --------------------------------------------------------*/ - -#define LMS_LEAK_RATE 0.9999f - -#if defined(__GNUC__) && defined(SPANDSP_USE_SSE2) -SPAN_DECLARE(void) vec_lmsf(const float x[], float y[], int n, float error) -{ - int i; - __m128 n1; - __m128 n2; - __m128 n3; - __m128 n4; - - if ((i = n & ~3)) - { - n3 = _mm_set1_ps(error); - n4 = _mm_set1_ps(LMS_LEAK_RATE); - for (i -= 4; i >= 0; i -= 4) - { - n1 = _mm_loadu_ps(x + i); - n2 = _mm_loadu_ps(y + i); - n1 = _mm_mul_ps(n1, n3); - n2 = _mm_mul_ps(n2, n4); - n1 = _mm_add_ps(n1, n2); - _mm_storeu_ps(y + i, n1); - } - } - /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ - switch (n & 3) - { - case 3: - y[n - 3] = y[n - 3]*LMS_LEAK_RATE + x[n - 3]*error; - case 2: - y[n - 2] = y[n - 2]*LMS_LEAK_RATE + x[n - 2]*error; - case 1: - y[n - 1] = y[n - 1]*LMS_LEAK_RATE + x[n - 1]*error; - } -} -#else -SPAN_DECLARE(void) vec_lmsf(const float x[], float y[], int n, float error) -{ - int i; - - for (i = 0; i < n; i++) - { - /* Leak a little to tame uncontrolled wandering */ - y[i] = y[i]*LMS_LEAK_RATE + x[i]*error; - } -} -#endif -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_circular_lmsf(const float x[], float y[], int n, int pos, float error) -{ - vec_lmsf(&x[pos], &y[0], n - pos, error); - vec_lmsf(&x[0], &y[n - pos], pos, error); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/vector_int.c b/libs/spandsp/src/vector_int.c deleted file mode 100644 index c2ed12f98e..0000000000 --- a/libs/spandsp/src/vector_int.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * vector_int.c - Integer vector arithmetic - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 -#include - -#include "floating_fudge.h" -#include "mmx_sse_decs.h" - -#include "spandsp/telephony.h" -#include "spandsp/vector_int.h" - -SPAN_DECLARE(int32_t) vec_dot_prodi16(const int16_t x[], const int16_t y[], int n) -{ - int32_t z; - -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__x86_64__) - __asm__ __volatile__( - " emms;\n" - " pxor %%mm0,%%mm0;\n" - " leaq -32(%%rsi,%%rax,2),%%rdx;\n" /* rdx = top - 32 */ - - " cmpq %%rdx,%%rsi;\n" - " ja 1f;\n" - - /* Work in blocks of 16 int16_t's until we are near the end */ - " .p2align 2;\n" - "2:\n" - " movq (%%rdi),%%mm1;\n" - " movq (%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 8(%%rdi),%%mm1;\n" - " movq 8(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 16(%%rdi),%%mm1;\n" - " movq 16(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 24(%%rdi),%%mm1;\n" - " movq 24(%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " addq $32,%%rsi;\n" - " addq $32,%%rdi;\n" - " cmpq %%rdx,%%rsi;\n" - " jbe 2b;\n" - - " .p2align 2;\n" - "1:\n" - " addq $24,%%rdx;\n" /* Now edx = top - 8 */ - " cmpq %%rdx,%%rsi;\n" - " ja 3f;\n" - - /* Work in blocks of 4 int16_t's until we are near the end */ - " .p2align 2;\n" - "4:\n" - " movq (%%rdi),%%mm1;\n" - " movq (%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " addq $8,%%rsi;\n" - " addq $8,%%rdi;\n" - " cmpq %%rdx,%%rsi;" - " jbe 4b;\n" - - " .p2align 2;\n" - "3:\n" - " addq $4,%%rdx;\n" /* Now edx = top - 4 */ - " cmpq %%rdx,%%rsi;\n" - " ja 5f;\n" - - /* Work in a block of 2 int16_t's */ - " movd (%%rdi),%%mm1;\n" - " movd (%%rsi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " addq $4,%%rsi;\n" - " addq $4,%%rdi;\n" - - " .p2align 2;\n" - "5:\n" - " addq $2,%%rdx;\n" /* Now edx = top - 2 */ - " cmpq %%rdx,%%rsi;\n" - " ja 6f;\n" - - /* Deal with the very last int16_t, when n is odd */ - " movswl (%%rdi),%%eax;\n" - " andl $65535,%%eax;\n" - " movd %%eax,%%mm1;\n" - " movswl (%%rsi),%%eax;\n" - " andl $65535,%%eax;\n" - " movd %%eax,%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " .p2align 2;\n" - "6:\n" - /* Merge the pieces of the answer */ - " movq %%mm0,%%mm1;\n" - " punpckhdq %%mm0,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - /* Et voila, eax has the final result */ - " movd %%mm0,%%eax;\n" - - " emms;\n" - : "=a" (z) - : "S" (x), "D" (y), "a" (n) - : "cc", "rdx", "mm0", "mm1", "mm2" - ); -#elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) - __asm__ __volatile__( - " emms;\n" - " pxor %%mm0,%%mm0;\n" - " leal -32(%%esi,%%eax,2),%%edx;\n" /* edx = top - 32 */ - - " cmpl %%edx,%%esi;\n" - " ja 1f;\n" - - /* Work in blocks of 16 int16_t's until we are near the end */ - " .p2align 2;\n" - "2:\n" - " movq (%%edi),%%mm1;\n" - " movq (%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 8(%%edi),%%mm1;\n" - " movq 8(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 16(%%edi),%%mm1;\n" - " movq 16(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - " movq 24(%%edi),%%mm1;\n" - " movq 24(%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " addl $32,%%esi;\n" - " addl $32,%%edi;\n" - " cmpl %%edx,%%esi;\n" - " jbe 2b;\n" - - " .p2align 2;\n" - "1:\n" - " addl $24,%%edx;\n" /* Now edx = top - 8 */ - " cmpl %%edx,%%esi;\n" - " ja 3f;\n" - - /* Work in blocks of 4 int16_t's until we are near the end */ - " .p2align 2;\n" - "4:\n" - " movq (%%edi),%%mm1;\n" - " movq (%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " addl $8,%%esi;\n" - " addl $8,%%edi;\n" - " cmpl %%edx,%%esi;" - " jbe 4b;\n" - - " .p2align 2;\n" - "3:\n" - " addl $4,%%edx;\n" /* Now edx = top - 4 */ - " cmpl %%edx,%%esi;\n" - " ja 5f;\n" - - /* Work in a block of 2 int16_t's */ - " movd (%%edi),%%mm1;\n" - " movd (%%esi),%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " addl $4,%%esi;\n" - " addl $4,%%edi;\n" - - " .p2align 2;\n" - "5:\n" - " addl $2,%%edx;\n" /* Now edx = top - 2 */ - " cmpl %%edx,%%esi;\n" - " ja 6f;\n" - - /* Deal with the very last int16_t, when n is odd */ - " movswl (%%edi),%%eax;\n" - " andl $65535,%%eax;\n" - " movd %%eax,%%mm1;\n" - " movswl (%%esi),%%eax;\n" - " andl $65535,%%eax;\n" - " movd %%eax,%%mm2;\n" - " pmaddwd %%mm2,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - - " .p2align 2;\n" - "6:\n" - /* Merge the pieces of the answer */ - " movq %%mm0,%%mm1;\n" - " punpckhdq %%mm0,%%mm1;\n" - " paddd %%mm1,%%mm0;\n" - /* Et voila, eax has the final result */ - " movd %%mm0,%%eax;\n" - - " emms;\n" - : "=a" (z) - : "S" (x), "D" (y), "a" (n) - : "cc", "edx", "mm0", "mm1", "mm2" - ); -#else - int i; - - z = 0; - for (i = 0; i < n; i++) - z += (int32_t) x[i]*(int32_t) y[i]; -#endif - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) vec_circular_dot_prodi16(const int16_t x[], const int16_t y[], int n, int pos) -{ - int32_t z; - - z = vec_dot_prodi16(&x[pos], &y[0], n - pos); - z += vec_dot_prodi16(&x[0], &y[n - pos], pos); - return z; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_lmsi16(const int16_t x[], int16_t y[], int n, int16_t error) -{ - int i; - - for (i = 0; i < n; i++) - y[i] += (int16_t) (((int32_t) x[i]*(int32_t) error) >> 15); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) vec_circular_lmsi16(const int16_t x[], int16_t y[], int n, int pos, int16_t error) -{ - vec_lmsi16(&x[pos], &y[0], n - pos, error); - vec_lmsi16(&x[0], &y[n - pos], pos, error); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int32_t) vec_min_maxi16(const int16_t x[], int n, int16_t out[]) -{ -#if defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__x86_64__) - static const int32_t lower_bound = 0x80008000; - static const int32_t upper_bound = 0x7FFF7FFF; - int32_t max; - - __asm__ __volatile__( - " emms;\n" - " pushq %%rdx;\n" - " leaq -8(%%rsi,%%rax,2),%%rdx;\n" - - " cmpq %%rdx,%%rsi;\n" - " jbe 2f;\n" - " movd %[lower],%%mm0;\n" - " movd %[upper],%%mm1;\n" - " jmp 1f;\n" - - " .p2align 2;\n" - "2:\n" - " movq (%%rsi),%%mm0;\n" /* mm0 will be max's */ - " movq %%mm0,%%mm1;\n" /* mm1 will be min's */ - " addq $8,%%rsi;\n" - " cmpq %%rdx,%%rsi;\n" - " ja 4f;\n" - - "3:\n" - " movq (%%rsi),%%mm2;\n" - - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " movq %%mm3,%%mm4;\n" - " pand %%mm2,%%mm3;\n" /* mm3 is mm2 masked to new max's */ - " pandn %%mm0,%%mm4;\n" /* mm4 is mm0 masked to its max's */ - " por %%mm3,%%mm4;\n" - " movq %%mm4,%%mm0;\n" /* Now mm0 is updated max's */ - - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ - - " addq $8,%%rsi;\n" - " cmpq %%rdx,%%rsi;\n" - " jbe 3b;\n" - - " .p2align 2;\n" - "4:\n" - /* Merge down the 4-word max/mins to lower 2 words */ - " movq %%mm0,%%mm2;\n" - " psrlq $32,%%mm2;\n" - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new max's */ - " pandn %%mm0,%%mm3;\n" /* mm3 is mm0 masked to its max's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm0;\n" /* now mm0 is updated max's */ - - " movq %%mm1,%%mm2;\n" - " psrlq $32,%%mm2;\n" - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ - - " .p2align 2;\n" - "1:\n" - " addq $4,%%rdx;\n" /* now dx = top-4 */ - " cmpq %%rdx,%%rsi;\n" - " ja 5f;\n" - /* Here, there are >= 2 words of input remaining */ - " movd (%%rsi),%%mm2;\n" - - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " movq %%mm3,%%mm4;\n" - " pand %%mm2,%%mm3;\n" /* mm3 is mm2 masked to new max's */ - " pandn %%mm0,%%mm4;\n" /* mm4 is mm0 masked to its max's */ - " por %%mm3,%%mm4;\n" - " movq %%mm4,%%mm0;\n" /* now mm0 is updated max's */ - - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ - - " addq $4,%%rsi;\n" - - " .p2align 2;\n" - "5:\n" - /* Merge down the 2-word max/mins to 1 word */ - " movq %%mm0,%%mm2;\n" - " psrlq $16,%%mm2;\n" - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new max's */ - " pandn %%mm0,%%mm3;\n" /* mm3 is mm0 masked to its max's */ - " por %%mm3,%%mm2;\n" - " movd %%mm2,%%ecx;\n" /* cx is max so far */ - - " movq %%mm1,%%mm2;\n" - " psrlq $16,%%mm2;\n" - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movd %%mm2,%%eax;\n" /* ax is min so far */ - - " addq $2,%%rdx;\n" /* now dx = top-2 */ - " cmpq %%rdx,%%rsi;\n" - " ja 6f;\n" - - /* Here, there is one word of input left */ - " cmpw (%%rsi),%%cx;\n" - " jge 9f;\n" - " movw (%%rsi),%%cx;\n" - " .p2align 2;\n" - "9:\n" - " cmpw (%%rsi),%%ax;\n" - " jle 6f;\n" - " movw (%%rsi),%%ax;\n" - - " .p2align 2;\n" - "6:\n" - /* (finally!) cx is the max, ax the min */ - " movswl %%cx,%%ecx;\n" - " movswl %%ax,%%eax;\n" - - " popq %%rdx;\n" /* ptr to output max,min vals */ - " andq %%rdx,%%rdx;\n" - " jz 7f;\n" - " movw %%cx,(%%rdx);\n" /* max */ - " movw %%ax,2(%%rdx);\n" /* min */ - " .p2align 2;\n" - "7:\n" - /* Now calculate max absolute value */ - " negl %%eax;\n" - " cmpl %%ecx,%%eax;\n" - " jge 8f;\n" - " movl %%ecx,%%eax;\n" - " .p2align 2;\n" - "8:\n" - " emms;\n" - : "=a" (max) - : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) - : "ecx", "mm0", "mm1", "mm2", "mm3", "mm4" - ); -#elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) - static const int32_t lower_bound = 0x80008000; - static const int32_t upper_bound = 0x7FFF7FFF; - int32_t max; - - __asm__ __volatile__( - " emms;\n" - " pushl %%edx;\n" - " leal -8(%%esi,%%eax,2),%%edx;\n" - - " cmpl %%edx,%%esi;\n" - " jbe 2f;\n" - " movd %[lower],%%mm0;\n" - " movd %[upper],%%mm1;\n" - " jmp 1f;\n" - - " .p2align 2;\n" - "2:\n" - " movq (%%esi),%%mm0;\n" /* mm0 will be max's */ - " movq %%mm0,%%mm1;\n" /* mm1 will be min's */ - " addl $8,%%esi;\n" - " cmpl %%edx,%%esi;\n" - " ja 4f;\n" - - " .p2align 2;\n" - "3:\n" - " movq (%%esi),%%mm2;\n" - - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " movq %%mm3,%%mm4;\n" - " pand %%mm2,%%mm3;\n" /* mm3 is mm2 masked to new max's */ - " pandn %%mm0,%%mm4;\n" /* mm4 is mm0 masked to its max's */ - " por %%mm3,%%mm4;\n" - " movq %%mm4,%%mm0;\n" /* Now mm0 is updated max's */ - - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ - - " addl $8,%%esi;\n" - " cmpl %%edx,%%esi;\n" - " jbe 3b;\n" - - " .p2align 2;\n" - "4:\n" - /* Merge down the 4-word max/mins to lower 2 words */ - " movq %%mm0,%%mm2;\n" - " psrlq $32,%%mm2;\n" - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new max's */ - " pandn %%mm0,%%mm3;\n" /* mm3 is mm0 masked to its max's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm0;\n" /* now mm0 is updated max's */ - - " movq %%mm1,%%mm2;\n" - " psrlq $32,%%mm2;\n" - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ - - " .p2align 2;\n" - "1:\n" - " addl $4,%%edx;\n" /* now dx = top-4 */ - " cmpl %%edx,%%esi;\n" - " ja 5f;\n" - /* Here, there are >= 2 words of input remaining */ - " movd (%%esi),%%mm2;\n" - - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " movq %%mm3,%%mm4;\n" - " pand %%mm2,%%mm3;\n" /* mm3 is mm2 masked to new max's */ - " pandn %%mm0,%%mm4;\n" /* mm4 is mm0 masked to its max's */ - " por %%mm3,%%mm4;\n" - " movq %%mm4,%%mm0;\n" /* now mm0 is updated max's */ - - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movq %%mm2,%%mm1;\n" /* now mm1 is updated min's */ - - " addl $4,%%esi;\n" - - " .p2align 2;\n" - "5:\n" - /* Merge down the 2-word max/mins to 1 word */ - " movq %%mm0,%%mm2;\n" - " psrlq $16,%%mm2;\n" - " movq %%mm2,%%mm3;\n" - " pcmpgtw %%mm0,%%mm3;\n" /* mm3 is bitmask for words where mm2 > mm0 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new max's */ - " pandn %%mm0,%%mm3;\n" /* mm3 is mm0 masked to its max's */ - " por %%mm3,%%mm2;\n" - " movd %%mm2,%%ecx;\n" /* cx is max so far */ - - " movq %%mm1,%%mm2;\n" - " psrlq $16,%%mm2;\n" - " movq %%mm1,%%mm3;\n" - " pcmpgtw %%mm2,%%mm3;\n" /* mm3 is bitmask for words where mm2 < mm1 */ - " pand %%mm3,%%mm2;\n" /* mm2 is mm2 masked to new min's */ - " pandn %%mm1,%%mm3;\n" /* mm3 is mm1 masked to its min's */ - " por %%mm3,%%mm2;\n" - " movd %%mm2,%%eax;\n" /* ax is min so far */ - - " addl $2,%%edx;\n" /* now dx = top-2 */ - " cmpl %%edx,%%esi;\n" - " ja 6f;\n" - - /* Here, there is one word of input left */ - " cmpw (%%esi),%%cx;\n" - " jge 9f;\n" - " movw (%%esi),%%cx;\n" - " .p2align 2;\n" - "9:\n" - " cmpw (%%esi),%%ax;\n" - " jle 6f;\n" - " movw (%%esi),%%ax;\n" - - " .p2align 2;\n" - "6:\n" - /* (finally!) cx is the max, ax the min */ - " movswl %%cx,%%ecx;\n" - " movswl %%ax,%%eax;\n" - - " popl %%edx;\n" /* ptr to output max,min vals */ - " andl %%edx,%%edx;\n" - " jz 7f;\n" - " movw %%cx,(%%edx);\n" /* max */ - " movw %%ax,2(%%edx);\n" /* min */ - " .p2align 2;\n" - "7:\n" - /* Now calculate max absolute value */ - " negl %%eax;\n" - " cmpl %%ecx,%%eax;\n" - " jge 8f;\n" - " movl %%ecx,%%eax;\n" - " .p2align 2;\n" - "8:\n" - " emms;\n" - : "=a" (max) - : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) - : "ecx", "mm0", "mm1", "mm2", "mm3", "mm4" - ); -#else - int i; - int16_t min; - int16_t max; - int16_t temp; - int32_t z; - - max = INT16_MIN; - min = INT16_MAX; - for (i = 0; i < n; i++) - { - temp = x[i]; - if (temp > max) - max = temp; - /*endif*/ - if (temp < min) - min = temp; - /*endif*/ - } - /*endfor*/ - if (out) - { - out[0] = max; - out[1] = min; - } - z = abs(min); - if (z > max) - return z; -#endif - return max; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/test-data/Makefile.am b/libs/spandsp/test-data/Makefile.am deleted file mode 100644 index dab5d61751..0000000000 --- a/libs/spandsp/test-data/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -SUBDIRS = itu etsi - -DIST_SUBDIRS = itu etsi local - -all: - -clean: - diff --git a/libs/spandsp/test-data/etsi/Makefile.am b/libs/spandsp/test-data/etsi/Makefile.am deleted file mode 100644 index f220bb29c3..0000000000 --- a/libs/spandsp/test-data/etsi/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am -- Process this file with automake to produce Makefile.in -## -## 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. - -SUBDIRS = fax - -DIST_SUBDIRS = fax - -all: - -clean: - diff --git a/libs/spandsp/test-data/etsi/fax/Makefile.am b/libs/spandsp/test-data/etsi/fax/Makefile.am deleted file mode 100644 index 9b31fea137..0000000000 --- a/libs/spandsp/test-data/etsi/fax/Makefile.am +++ /dev/null @@ -1,59 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am -- Process this file with automake to produce Makefile.in -## -## 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. - -AM_CFLAGS = $(COMP_VENDOR_CFLAGS) - -PBM2G3 = pbmtog3 -FAX2TIFF = fax2tiff -TIFFCP = tiffcp - -ETSI_TEST_PAGES = etsi_300_242_a4_diago1.tif \ - etsi_300_242_a4_diago2.tif \ - etsi_300_242_a4_duration1.tif \ - etsi_300_242_a4_duration2.tif \ - etsi_300_242_a4_error.tif \ - etsi_300_242_a4_impress.tif \ - etsi_300_242_a4_impress_white.tif \ - etsi_300_242_a4_stairstep.tif \ - etsi_300_242_a4_white.tif \ - etsi_300_242_a4_white_2p.tif - -EXTRA_DIST = - -MAINTAINERCLEANFILES = Makefile.in - -LIBDIR = -L$(top_builddir)/src - -nobase_data_DATA = ${ETSI_TEST_PAGES} - -noinst_PROGRAMS = generate_etsi_300_242_pages - -generate_etsi_300_242_pages_SOURCES = generate_etsi_300_242_pages.c -generate_etsi_300_242_pages_LDADD = $(LIBDIR) -lspandsp -ltiff - -clean: - rm -f *.tif *.g3 - -.g3.tif: - ${FAX2TIFF} -M -o $*.tif $*.g3 - -.pbm.g3: - ${PBM2G3} $*.pbm >$*.g3 - -${ETSI_TEST_PAGES}: generate_etsi_300_242_pages$(EXEEXT) - ./generate_etsi_300_242_pages$(EXEEXT) 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 deleted file mode 100644 index be425bb765..0000000000 --- a/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * generate_etsi_300_242_pages.c - Create the test pages defined in ETSI ETS 300 242. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif - -#include "spandsp.h" - -struct -{ - const char *name; - int x_res; - int y_res; - int width; - int length; - int compression; - int type; -} sequence[] = -{ - { - "etsi_300_242_a4_diago1.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1002, - COMPRESSION_CCITT_T4, - 0 - }, - { - "etsi_300_242_a4_diago2.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1002, - COMPRESSION_CCITT_T4, - 1 - }, - { - "etsi_300_242_a4_duration1.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 237, - COMPRESSION_CCITT_T4, - 2 - }, - { - "etsi_300_242_a4_duration2.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 237, - COMPRESSION_CCITT_T4, - 3 - }, - { - "etsi_300_242_a4_error.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 400, - COMPRESSION_CCITT_T4, - 4 - }, - { - "etsi_300_242_a4_impress.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1079, - COMPRESSION_CCITT_T4, - 5 - }, - { - "etsi_300_242_a4_stairstep.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1728, - COMPRESSION_CCITT_T4, - 6 - }, - { - "etsi_300_242_a4_white.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1100, - COMPRESSION_CCITT_T4, - 7 - }, - { - "etsi_300_242_a4_white_2p.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1100, - COMPRESSION_CCITT_T4, - 7 - }, - { /* Second page of the above file */ - "", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1100, - COMPRESSION_CCITT_T4, - 7 - }, - { - "etsi_300_242_a4_impress_white.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1079, - COMPRESSION_CCITT_T4, - 5 - }, - { /* Second page of the above file */ - "", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1100, - COMPRESSION_CCITT_T4, - 7 - }, - { - NULL, - 0, - 0, - 0, - 0 - }, -}; - -int photo_metric = PHOTOMETRIC_MINISWHITE; -int fill_order = FILLORDER_LSB2MSB; - -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 --------------------------------------------------------*/ - -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 --------------------------------------------------------*/ - -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]; - int row; - - /* TSB-85 WHITE page. */ - for (row = 0; row < 1100; row++) - { - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - return 1100; -} -/*- End of function --------------------------------------------------------*/ - -static int create_stairstep_page(TIFF *tiff_file) -{ - uint8_t image_buffer[8192]; - int row; - int start_pixel; - int i; - - /* TSB-85 STAIRSTEP page. */ - start_pixel = 0; - for (row = 0; row < 1728; row++) - { - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, start_pixel, start_pixel + 63); - if (photo_metric != PHOTOMETRIC_MINISWHITE) - { - for (i = 0; i < 1728/8; i++) - image_buffer[i] = ~image_buffer[i]; - } -#if 0 - if (fill_order != FILLORDER_LSB2MSB) - bit_reverse(image_buffer, image_buffer, 1728/8); -#endif - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - start_pixel += 64; - if (start_pixel >= 1728) - start_pixel = 0; - } - return 1728; -} -/*- End of function --------------------------------------------------------*/ - -static int create_diago1_page(TIFF *tiff_file) -{ - uint8_t image_buffer[1728/8 + 1]; - int row; - - /* ETSI ETS 300 242 B.5.1 One dimensional coding test chart - the DIAGO1 page. */ - for (row = 0; row < 1001; row++) - { - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, row, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - return 1002; -} -/*- End of function --------------------------------------------------------*/ - -static int create_diago2_page(TIFF *tiff_file) -{ - uint8_t image_buffer[1728/8 + 1]; - int row; - - /* ETSI ETS 300 242 B.5.1 One dimensional coding test chart - the DIAGO2 page. */ - for (row = 0; row < 1001; row++) - { - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, row + 728, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - return 1002; -} -/*- End of function --------------------------------------------------------*/ - -static int create_impress_page(TIFF *tiff_file) -{ - int j; - int row; - uint8_t *page; - - /* ETSI ETS 300 242 B.5.2 Printing resolution - the IMPRESS page */ - if ((page = malloc(1079*1728/8)) == NULL) - return 0; - memset(page, 0, 1079*1728/8); - - set_pixel_range(page, 1, 0, 1727); - for (row = 2; row <= 78; row++) - { - set_pixel_range(page, row, 850, 850 + 27); - set_pixel_range(page, row, 850 + 27 + 745, 850 + 27 + 745 + 26); - } - for (row = 80; row <= 117; row++) - { - for (j = 0; j < 1728; j += 2) - set_pixel(page, row, j); - } - for (row = 118; row <= 155; row++) - { - for (j = 1; j < 1728; j += 2) - set_pixel(page, row, j); - } - for (row = 194; row <= 231; row += 2) - set_pixel_range(page, row, 0, 1727); - for (row = 270; row <= 276; row++) - set_pixel_range(page, row, 60, 60 + 1607); - for (j = 0; j < 1728; j += 27) - set_pixel(page, 315, j); - for (row = 354; row <= 480; row++) - set_pixel_range(page, row, 209, 768); - for (row = 358; row <= 476; row++) - clear_pixel_range(page, row, 488, 489); - clear_pixel_range(page, 417, 217, 760); - - for (row = 354; row <= 357; row++) - set_pixel_range(page, row, 962, 1521); - for (row = 477; row <= 480; row++) - set_pixel_range(page, row, 962, 1521); - for (row = 358; row <= 476; row++) - set_pixel_range(page, row, 962, 969); - for (row = 358; row <= 476; row++) - set_pixel_range(page, row, 1514, 1521); - for (row = 358; row <= 476; row++) - set_pixel(page, row, 1241); - set_pixel_range(page, 417, 970, 1513); - - for (row = 354; row <= 1079; row++) - set_pixel(page, row, 864); - for (row = 157; row <= 926; row++) - set_pixel_range(page, row, 884, 899); - for (row = 0; row < 1079; row++) - { - if (TIFFWriteScanline(tiff_file, page + row*1728/8, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - free(page); - return 1079; -} -/*- End of function --------------------------------------------------------*/ - -static int create_duration1_page(TIFF *tiff_file) -{ - uint8_t image_buffer[1728/8 + 1]; - int row; - int i; - - /* ETSI ETS 300 242 B.5.3 Acceptance of total coded scan line duration - the DURATION1 page */ - row = 0; - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - for ( ; row < 117; row++) - { - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - clear_row(image_buffer, 1728); - for (i = 1; i < 1728; i += 2) - set_pixel(image_buffer, 1, i); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - for ( ; row < 236; row++) - { - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - return 237; -} -/*- End of function --------------------------------------------------------*/ - -static int create_duration2_page(TIFF *tiff_file) -{ - return create_duration1_page(tiff_file); -} -/*- End of function --------------------------------------------------------*/ - -static int create_error_page(TIFF *tiff_file) -{ - uint8_t image_buffer[1728/8 + 1]; - int row; - int start_pixel; - int i; - - /* ETSI ETS 300 242 B.5.4 Copy quality criteria - the ERROR page. */ - for (row = 0; row < 68; row++) - { - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - - for (i = 0; i < 10; i++) - { - for (start_pixel = 16; start_pixel <= 1616; start_pixel += 64) - { - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, start_pixel, start_pixel + 63); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - row++; - } - } - - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - - clear_row(image_buffer, 1728); - set_pixel_range(image_buffer, 1, 0, 1727); - if (TIFFWriteScanline(tiff_file, image_buffer, row++, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - - for (row = 332; row < 400; row++) - { - clear_row(image_buffer, 1728); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - - return 400; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - TIFF *tiff_file; - struct tm *tm; - time_t now; - char buf[133]; - float x_resolution; - float y_resolution; - int i; - int image_length; - int opt; - - photo_metric = PHOTOMETRIC_MINISWHITE; - fill_order = FILLORDER_LSB2MSB; - while ((opt = getopt(argc, argv, "ir")) != -1) - { - switch (opt) - { - case 'i': - photo_metric = PHOTOMETRIC_MINISBLACK; - break; - case 'r': - fill_order = FILLORDER_MSB2LSB; - break; - default: - //usage(); - exit(2); - break; - } - } - - tiff_file = NULL; - for (i = 0; sequence[i].name; i++) - { - if (sequence[i].name[0]) - { - if (tiff_file) - TIFFClose(tiff_file); - if ((tiff_file = TIFFOpen(sequence[i].name, "w")) == NULL) - exit(2); - } - /* Prepare the directory entry fully before writing the image, or libtiff complains */ - TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, sequence[i].compression); - if (sequence[i].compression == COMPRESSION_CCITT_T4) - { - TIFFSetField(tiff_file, TIFFTAG_T4OPTIONS, GROUP3OPT_FILLBITS); // | GROUP3OPT_2DENCODING); - 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_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, photo_metric); - TIFFSetField(tiff_file, TIFFTAG_FILLORDER, fill_order); - x_resolution = sequence[i].x_res/100.0f; - y_resolution = sequence[i].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)); - 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_MAKE, "soft-switch.org"); - TIFFSetField(tiff_file, TIFFTAG_MODEL, "test data"); - - time(&now); - tm = localtime(&now); - sprintf(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(tiff_file, TIFFTAG_DATETIME, buf); - 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); - - /* Write the image first.... */ - switch (sequence[i].type) - { - case 0: - /* The DIAGO1 page */ - image_length = create_diago1_page(tiff_file); - break; - case 1: - /* The DIAGO2 page */ - image_length = create_diago2_page(tiff_file); - break; - case 2: - /* The DURATION1 page */ - image_length = create_duration1_page(tiff_file); - break; - case 3: - /* The DURATION2 page */ - image_length = create_duration2_page(tiff_file); - break; - case 4: - /* The ERROR page */ - image_length = create_error_page(tiff_file); - break; - case 5: - /* The IMPRESS page */ - image_length = create_impress_page(tiff_file); - break; - case 6: - /* A stairstep of 64 pixel dashes */ - image_length = create_stairstep_page(tiff_file); - break; - case 7: - /* A white A4 page */ - image_length = create_white_page(tiff_file); - break; - } - /* ....then the directory entry, and libtiff is happy. */ - 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); - } - if (tiff_file) - TIFFClose(tiff_file); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/test-data/itu/Makefile.am b/libs/spandsp/test-data/itu/Makefile.am deleted file mode 100644 index 9e262c2d8e..0000000000 --- a/libs/spandsp/test-data/itu/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -SUBDIRS = fax - -DIST_SUBDIRS = fax - -all: - -clean: - diff --git a/libs/spandsp/test-data/itu/fax/Makefile.am b/libs/spandsp/test-data/itu/fax/Makefile.am deleted file mode 100644 index bc8234f66b..0000000000 --- a/libs/spandsp/test-data/itu/fax/Makefile.am +++ /dev/null @@ -1,167 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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 -## 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 -## License along with this program; if not, write to the Free Software -## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -AM_CFLAGS = $(COMP_VENDOR_CFLAGS) -AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) - -PBM2G3 = pbmtog3 -FAX2TIFF = fax2tiff -TIFFCP = tiffcp - -ITU_TEST_PAGES_PBM = itu1.pbm \ - itu2.pbm \ - itu3.pbm \ - itu4.pbm \ - itu5.pbm \ - itu6.pbm \ - itu7.pbm \ - itu8.pbm \ - test1.pbm \ - test2.pbm \ - test3.pbm \ - test4.pbm - -ITU_TEST_PAGES_G3 = itu1.g3 \ - itu2.g3 \ - itu3.g3 \ - itu4.g3 \ - itu5.g3 \ - itu6.g3 \ - itu7.g3 \ - itu8.g3 \ - test1.g3 \ - test2.g3 \ - test3.g3 \ - test4.g3 - -ITU_TEST_PAGES = itu1.tif \ - itu2.tif \ - itu3.tif \ - itu4.tif \ - itu5.tif \ - itu6.tif \ - itu7.tif \ - itu8.tif \ - test1.tif \ - test2.tif \ - test3.tif \ - test4.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} - -MAINTAINERCLEANFILES = Makefile.in - -nobase_data_DATA = 100pages.tif \ - dithered.tif \ - itutests.tif \ - ${ITU_TEST_PAGES} \ - ${MIXED_SIZE_PAGES} \ - mixed_size_pages.tif \ - striped.tif - -noinst_PROGRAMS = generate_dithered_tif \ - generate_sized_pages \ - generate_striped_pages - -generate_dithered_tif_SOURCES = generate_dithered_tif.c -generate_dithered_tif_LDADD = -ltiff - -generate_sized_pages_SOURCES = generate_sized_pages.c -generate_sized_pages_LDADD = -ltiff - -generate_striped_pages_SOURCES = generate_striped_pages.c -generate_striped_pages_LDADD = -ltiff - -clean: - rm -f *.tif *.g3 - -itutests.tif: ${ITU_TEST_PAGES_G3} - $(FAX2TIFF) -M -o $@ ${ITU_TEST_PAGES_G3} - -100pages.tif: ${ITU_TEST_PAGES_G3} - $(FAX2TIFF) -M -o $@ \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - ${ITU_TEST_PAGES_G3} \ - itu1.g3 itu2.g3 itu3.g3 itu4.g3 - -.g3.tif: - ${FAX2TIFF} -M -o $*.tif $*.g3 - -.pbm.g3: - ${PBM2G3} $*.pbm >$*.g3 - -dithered.tif: generate_dithered_tif$(EXEEXT) - ./generate_dithered_tif$(EXEEXT) - -${MIXED_SIZE_PAGES}: generate_sized_pages$(EXEEXT) - ./generate_sized_pages$(EXEEXT) - -mixed_size_pages.tif: ${MIXED_SIZE_PAGES} - $(TIFFCP) ${MIXED_SIZE_PAGES} $@ - -striped.tif: generate_striped_pages$(EXEEXT) - ./generate_striped_pages$(EXEEXT) diff --git a/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c b/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c deleted file mode 100644 index 857ccbee72..0000000000 --- a/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * generate_dithered_tif.c - Create a fine checkerboard TIFF file for test purposes. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 */ - -/* - This program generates an A4 sized FAX image of a fine checkerboard. This doesn't - compress well, so it results in a rather large file for a single page. This is - good for testing the handling of extreme pages. - - Note that due to a bug in FAX image handling, versions of libtiff up to 3.8.2 fail - to handle this complex image properly, if 2-D compression is used. The bug should - be fixed in CVS at the time of writing, and so should be fixed in released versions - after 3.8.2. This code uses 1-D compression to avoid the issue. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include - -#include "spandsp.h" - -int main(int argc, char *argv[]) -{ - int image_width; - int row; - int output_compression; - int output_t4_options; - uint8_t image_buffer[1024]; - TIFF *tiff_file; - struct tm *tm; - time_t now; - char buf[133]; - float x_resolution; - float y_resolution; - int x_res; - int y_res; - int image_length; - - if ((tiff_file = TIFFOpen("dithered.tif", "w")) == NULL) - exit(2); - - output_compression = COMPRESSION_CCITT_T4; - /* Use 1-D compression until a fixed libtiff is the norm. */ - //output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; - output_t4_options = GROUP3OPT_FILLBITS; - - x_res = T4_X_RESOLUTION_R8; - y_res = T4_Y_RESOLUTION_FINE; - image_width = 1728; - image_length = 2200; - - /* 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_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_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); - TIFFSetField(tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); - - x_resolution = x_res/100.0f; - 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)); - TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - - 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, "testy"); - - time(&now); - tm = localtime(&now); - sprintf(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(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); - TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, image_width); - TIFFCheckpointDirectory(tiff_file); - - /* Write the image first.... */ - for (row = 0; row < image_length; row++) - { - if ((row & 1) == 0) - memset(image_buffer, 0xAA, image_width/8 + 1); - else - memset(image_buffer, 0x55, image_width/8 + 1); - if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) - { - printf("Write error at row %d.\n", row); - exit(2); - } - } - /* ....then the directory entry, and libtiff is happy. */ - TIFFWriteDirectory(tiff_file); - TIFFClose(tiff_file); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/test-data/itu/fax/generate_sized_pages.c b/libs/spandsp/test-data/itu/fax/generate_sized_pages.c deleted file mode 100644 index dcede55457..0000000000 --- a/libs/spandsp/test-data/itu/fax/generate_sized_pages.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - * 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. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif - -#include "spandsp.h" - -struct -{ - const char *name; - int x_res; - int y_res; - int width; - int length; - int squashing_factor; -} sequence[] = -{ - { - "bilevel_R8_385_A4.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A4, - 1100, - 1 - }, - { - "bilevel_R8_385_B4.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_B4, - 1200, - 1 - }, - { - "bilevel_R8_385_A3.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_STANDARD, - T4_WIDTH_R8_A3, - 1556, - 1 - }, - { - "bilevel_R8_77_A4.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_FINE, - T4_WIDTH_R8_A4, - 1100*2, - 1 - }, - { - "bilevel_R8_77_B4.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_FINE, - T4_WIDTH_R8_B4, - 1200*2, - 1 - }, - { - "bilevel_R8_77_A3.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_FINE, - T4_WIDTH_R8_A3, - 1556*2, - 1 - }, - { - "bilevel_R8_154_A4.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_SUPERFINE, - T4_WIDTH_R8_A4, - 1100*4, - 1 - }, - { - "bilevel_R8_154_B4.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_SUPERFINE, - T4_WIDTH_R8_B4, - 1200*4, - 1 - }, - { - "bilevel_R8_154_A3.tif", - T4_X_RESOLUTION_R8, - T4_Y_RESOLUTION_SUPERFINE, - T4_WIDTH_R8_A3, - 1556*4, - 1 - }, - { - "bilevel_R16_154_A4.tif", - T4_X_RESOLUTION_R16, - T4_Y_RESOLUTION_SUPERFINE, - T4_WIDTH_R16_A4, - 1100*4, - 1 - }, - { - "bilevel_R16_154_B4.tif", - T4_X_RESOLUTION_R16, - T4_Y_RESOLUTION_SUPERFINE, - T4_WIDTH_R16_B4, - 1200*4, - 1 - }, - { - "bilevel_R16_154_A3.tif", - T4_X_RESOLUTION_R16, - T4_Y_RESOLUTION_SUPERFINE, - T4_WIDTH_R16_A3, - 1556*4, - 1 - }, - { - "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_400_A4, - 1100*8, - 1 - }, - { - "bilevel_400_800_B4.tif", - T4_X_RESOLUTION_400, - T4_Y_RESOLUTION_800, - T4_WIDTH_400_B4, - 1200*8, - 1 - }, - { - "bilevel_400_800_A3.tif", - T4_X_RESOLUTION_400, - T4_Y_RESOLUTION_800, - T4_WIDTH_400_A3, - 1556*8, - 1 - }, - { - "bilevel_600_600_A4.tif", - T4_X_RESOLUTION_600, - T4_Y_RESOLUTION_600, - T4_WIDTH_600_A4, - 1100*6, - 1 - }, - { - "bilevel_600_600_B4.tif", - T4_X_RESOLUTION_600, - T4_Y_RESOLUTION_600, - T4_WIDTH_600_B4, - 1200*6, - 1 - }, - { - "bilevel_600_600_A3.tif", - T4_X_RESOLUTION_600, - T4_Y_RESOLUTION_600, - T4_WIDTH_600_A3, - 1556*6, - 1 - }, - { - "bilevel_600_1200_A4.tif", - T4_X_RESOLUTION_600, - T4_Y_RESOLUTION_1200, - T4_WIDTH_600_A4, - 1100*12, - 1 - }, - { - "bilevel_600_1200_B4.tif", - T4_X_RESOLUTION_600, - T4_Y_RESOLUTION_1200, - T4_WIDTH_600_B4, - 1200*12, - 1 - }, - { - "bilevel_600_1200_A3.tif", - T4_X_RESOLUTION_600, - T4_Y_RESOLUTION_1200, - T4_WIDTH_600_A3, - 1556*12, - 1 - }, - { - "bilevel_1200_1200_A4.tif", - T4_X_RESOLUTION_1200, - T4_Y_RESOLUTION_1200, - T4_WIDTH_1200_A4, - 1100*12, - 1 - }, - { - "bilevel_1200_1200_B4.tif", - T4_X_RESOLUTION_1200, - T4_Y_RESOLUTION_1200, - T4_WIDTH_1200_B4, - 1200*12, - 1 - }, - { - "bilevel_1200_1200_A3.tif", - T4_X_RESOLUTION_1200, - T4_Y_RESOLUTION_1200, - T4_WIDTH_1200_A3, - 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; - uint8_t image_buffer[8192]; - TIFF *tiff_file; - struct tm *tm; - time_t now; - char buf[133]; - 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 = COMPRESSION_CCITT_T6; - output_t4_options = 0; - photo_metric = PHOTOMETRIC_MINISWHITE; - fill_order = FILLORDER_LSB2MSB; - while ((opt = getopt(argc, argv, "126ir")) != -1) - { - switch (opt) - { - case '1': - compression = COMPRESSION_CCITT_T4; - output_t4_options = GROUP3OPT_FILLBITS; - break; - case '2': - compression = COMPRESSION_CCITT_T4; - output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; - break; - case '6': - compression = COMPRESSION_CCITT_T6; - output_t4_options = 0; - break; - case 'i': - photo_metric = PHOTOMETRIC_MINISBLACK; - break; - case 'r': - fill_order = FILLORDER_MSB2LSB; - break; - default: - //usage(); - exit(2); - break; - } - } - - for (i = 0; sequence[i].name; i++) - { - if ((tiff_file = TIFFOpen(sequence[i].name, "w")) == NULL) - exit(2); - - /* 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_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, photo_metric); - TIFFSetField(tiff_file, TIFFTAG_FILLORDER, fill_order); - - x_resolution = sequence[i].x_res/100.0f; - y_resolution = sequence[i].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)); - TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - - if (gethostname(buf, sizeof(buf)) == 0) - TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, buf); - - 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, "testy"); - - time(&now); - tm = localtime(&now); - sprintf(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(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); - TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, sequence[i].width); - TIFFCheckpointDirectory(tiff_file); - - /* Write the image first.... */ - /* Produce a pattern of diagonal bands */ - for (row = 0; row < sequence[i].length; row++) - { - 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); - exit(2); - } - } - /* ....then the directory entry, and libtiff is happy. */ - TIFFWriteDirectory(tiff_file); - TIFFClose(tiff_file); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/test-data/itu/fax/generate_striped_pages.c b/libs/spandsp/test-data/itu/fax/generate_striped_pages.c deleted file mode 100644 index 8ad5098ca4..0000000000 --- a/libs/spandsp/test-data/itu/fax/generate_striped_pages.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * generate_striped_pages.c - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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 */ - -/* - This program generates an TIFF image as a number of small image striped, rather than - the usual all in one page FAX images usually consist of in TIFF files. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include - -#include "spandsp.h" - -#define IMAGE_WIDTH 1728 -#define IMAGE_LENGTH 2600 -#define ROWS_PER_STRIPE 37 - -int main(int argc, char *argv[]) -{ - TIFF *tiff_file; - uint8_t image_buffer[10000]; - int image_size; - time_t now; - struct tm *tm; - char buf[256 + 1]; - int i; - - if ((tiff_file = TIFFOpen("striped.tif", "w")) == NULL) - return -1; - - TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, COMPRESSION_CCITT_T6); - TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, 1); - TIFFSetField(tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, (int32_t) ROWS_PER_STRIPE); - TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); - TIFFSetField(tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); - 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_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, "soft-switch.org"); - TIFFSetField(tiff_file, TIFFTAG_MODEL, "testy"); - - time(&now); - tm = localtime(&now); - sprintf(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(tiff_file, TIFFTAG_DATETIME, buf); - TIFFSetField(tiff_file, TIFFTAG_FAXRECVTIME, 10); - TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, IMAGE_WIDTH); - TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, IMAGE_LENGTH); - TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); - TIFFCheckpointDirectory(tiff_file); - - image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8; - memset(image_buffer, 0x18, image_size); - - 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; - else - image_size = IMAGE_WIDTH*(IMAGE_LENGTH - i*ROWS_PER_STRIPE)/8; - if (TIFFWriteEncodedStrip(tiff_file, i, image_buffer, image_size) < 0) - return -1; - } - - TIFFWriteDirectory(tiff_file); - TIFFClose(tiff_file); - return 0; -} diff --git a/libs/spandsp/test-data/itu/fax/itu1.pbm b/libs/spandsp/test-data/itu/fax/itu1.pbm deleted file mode 100644 index 4c1ae4093d558f40b0eecf09640a89e1d93a0da3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513229 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

|Zzo+AIDTG$w`Zf<4d?nbW*&zWUi-yBJ`-$=Z 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 Ef5uO`cmMzZ diff --git a/libs/spandsp/test-data/itu/fax/itu4.pbm b/libs/spandsp/test-data/itu/fax/itu4.pbm deleted file mode 100644 index 0af83cfee12d017f94d2268fad4d7453965a13b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513229 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

p^jxW?tJ zJ`#6Rnr$c*V7SFKcnlA6@BNLRJ^_-Ivp0NEUxDCf(x&v>19@wJv_5Q{5b>- zjtAM%sHDCW81JqL?wL&Szxz3r1XJMUCW3~<&kfl|h2S!FD1L>G{J~^iNtcUD z(9lP&A-IaXfDFTBf|?_-DMeq)O!PHOuU2q13xmNrqz0q;xDAaLpFdoicE2kHZ~i>X zWAR6X`RhR*1;IbbVOX3@eveJI=odsT&D%I)=!_!b7fc^o#ChudRk2_snU9k{~ zdhiSulY(ZwxZm&SUy9?N_EUq4l{mV3S#Ga{3MhNShuMXdl=nAyTxz-;u|c?*Xf?GC#r0doGx6jRWI%-RwvFr_S>d1zvjlti74 zscg`S;L&u{Rexyme$fu14W$coitm?mA@nmW^oFjjXf^Pc+UZNDR3iFAofWEIcS4DR9{8!k<;X<_6nz;i(3{E+OngTv1^uDJ1sA3>9N46NiM~2Sv{VF* zRWY<#+;`<|1{wD6N?)`u32&Klf^H*o=a2kD&Tt%}FWxU{M3t)aRkYEURB;#7RjX*L zFL8hC1W8Hhc(7*{W@!Ykk#L&vzp8MFzFHK-AL9ANcti9hxI|w~PJoNcX_v9L2A3O! zG=qsDaN@pw;kPGHv`^P_LW))Y!JidQUv`-O8RI3VFQz3m+wglbmKA*=SK%9X`ua|W zQchnIC|Pk6!iQqTi5D&tLE}K?bNO`YaQSKOFQ#Vk8}!veBCSea@n^9|zacXnsE71g zKUs*rm;ljlg}7r;AMhKaZJdx|>OvmVAGV|gP(8rKf3oTxGc1rTR5Q3>QF?6(nxd~> zC+K`!wJ)_;7;zzFUD@IR{YJOj2;la>1uX~iDZHj{OFhLu9g?YpR_cayub%0Dv&j2j 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

XEs#FI772mK#p`*C*0KZCE6pzPsD*Bsr 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 *O|f(tglCX5k@;Ob*(I6O05 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 F{{aAOI9UJy diff --git a/libs/spandsp/test-data/itu/fax/itu5.pbm b/libs/spandsp/test-data/itu/fax/itu5.pbm deleted file mode 100644 index 876cbc056165c9ec27bf9802720e4bb832a6f2dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513229 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

-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 Iyo40^e-Z0hUH||9 diff --git a/libs/spandsp/test-data/itu/fax/itu6.pbm b/libs/spandsp/test-data/itu/fax/itu6.pbm deleted file mode 100644 index 8b3564eb32bfddbaa6d1bb0dd48d02fb4d1c19db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513229 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�>~D~nZ|#wUYobt+52N7X`n54% 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 IKvx;~e@3P1L;wH) diff --git a/libs/spandsp/test-data/itu/fax/itu7.pbm b/libs/spandsp/test-data/itu/fax/itu7.pbm deleted file mode 100644 index 5bf38edeed561141bbd2b38b417109da5d7774cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513229 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

pyfZAgkkzuummWxe#~ zk)36I)$5v&x*=m!-Z;q2)DI$r$N5T@w#?N|5d^o=OW`BV;wt22LpV}Jd zjqmK&qCIBd8J)e#E z#wR;dxXzy6nsxTO_09|)g(tH6Zu9#G_kPefYtxu}_SDvM*}d$U9~{}dvL0J~w(e%% z>h&kG-doRR-&^ze!FX?so86Q6Y~jJ;3A;JRY+erM@qhll(Z1DZ3)Za18zZ^b-^$r9|2zyJN%2;JBf*+;tZhaCTSxl(x^rA-tqJ-jXcPEVI8(2m zWq8@bL-w7WXLH>8q?>1NKwvlTW$XinrDD2(M8%-n!6x7H-Xa{!(L`q<4ksnHgXVZH$)!1&Q#fOQlH**U zjc=Zj9L;UPmeEAmgl%h<*_Z-v&Hm!ZjWW2*NZ`zk)JSf^Mu^{R-&)BOux!DR%{h?l zT_#8KEHCmtZ}To6^0bf?Jg!vU;7IXtIG5MI?})+!>nYE;H|E}ilLa4NST#G znN?IJR#-JuWHqUZDzCDtt%wS%MBGctuH;Lq#7Z3Bv~0`1l2kaJ@VT(c7fEE-*d=wD zUWwtGXJiqDE@8ZW^RT+M?~6s-D(-g_KRv z6hxlpJn$Dr0;|UJx(==3rHe6lQV@=g$P1jkIHgplVSmw9Q zW%-&7;+!}oPx;g7S@NpANUw)mazU=p4c{jtP;5>VV#!ofjOiM_5iv4t%T8?5j%tyH zsQMBqra3?|WCPtdeL4t3MQkoDh>|a-RlK_qnzSuC5{GXG%*D5OJ789-<(i^No1(3{ zo+cGNp!fVOb%6)=sywZand9MPIKfWa3-)TbsTSN?+INFwBrtcEkENs*Y8t6|q6JHmksA07v0?jsC@`P2NXxDwYDvR2({|`s>Zzix!vLFW$ChrX zHpLjaDO$3dOd1*s$%a~@SHszG#+{Cbl@~|i5q~H>$zQXV*tM`A*5rm5@J)JF1yLn+ z0?fy{uK7mV7F2fAp6kjs&9GmMMN&v}amf1`aG4D@0N><&L6v1SsoREb>5k~?Ug)tN z?V3&k*i731Zwi}7s{9hP4B8rSLuZ)$n!y4fk#OO1#R4 z1Q7T^vYxJ!4YR_phaf|8DcqFzSdKU1xZ2Jb+fFAjXDS<{4k{fat9;E4Qotd=N>4$z&qwI&fXACS_6y zbwUMjrN`q`I-|GQS+b2z$r-*aog~xZ$KsP>fqC_<@GbrK;?wq%;+y)OZmM?Dq77Z5 zLw(D=Y`^c0uoK~gIv?(+J{?c)3p@P0oaf`AEJ#?<%dStssbY+cvpTJXLLdp&l|sI_ z08|RymVv}_bbpTT|7T=j(RO_4z1)j`bBoX)mFw!@3&Wp=+uxsq2Og@2M$3GDD}$jNVS?%`D%> z=Jb!ncl!l$guN_ZRDUZzLjFpBl`lemuG5Ct9;cvFZpEYgI6Ws`@z3#->Ta?|ifkgz z+xzMLa$3}V)#uV>vP{=aIg<~h?rX9MJd?EG3o$PSewdchnrS2r-3DEc^Nwt|PVAXZ zX!)+3vNK{zP9?K^hnjcW(pk5YypO(z-4&9XpWo#cUZkD2vTa?;ksl3UPgdX=oo4VI^nKDwmxvcVdX@V+Ff z45|k`iH;dhI-;i9Zi0?mDtl}j*{-MQgq`u*>2^J*=GlY#--UzW*8%dw$!aaV+AC2D)2iR-rS$a$_(+SG_eSVkR@AkVnQ}zQl@GI_) zzOC2g$me1XIBHW$>X5D#UlT=@BLxL1k=AIs&aiY1oF=KA*9jbS++HubGSb z96e~CcNgh^4}5`ar;qZ7*j_U2ru?`b=sR+WZty$FRkNV`F3$hrJ$QH>4Sy5}E z&L;wNhn;ZKa$HnJKGb0p z!;SQcyB+U}+j^0d9ko3SWNmj@$bvilX&bdqUlDe6U=#1QE zrYU3lf#-4Xa9tPls=Xy|B)5~h;x1h?WkFp}Ot@`sn;xTGGG@9I`h>MLCEd^ir_Vvs z?q*LW{~LLdlt_<`@yqPv^zYIyxzCBusDDz2=moP77RVq>nYq}NCGc%iEV~QttO3s_ zmvjbcQ+CZnm?b;u4mYDFla4Qufm@=t^$mGTM|#hVk{Y3OoKI=!{B$y%q+^=eu7O-+ zUE4FT2HYHffc_k$O&1ci$%*(@{H(L?^ZX0$%jS9W3OysDSW|gX)nj4I^hnPY?Ml1_ zdby#l$XjYfj7%YEs4f||lV--u*dA~4YMS$FaWP#`3x1jR!O>OG5ji6o?kXAY@H7@tPNe_b>8%_C_#%Y-|!V$fPLF{8@!*wx-~^zrH#;3I7nuX zwG8Y<+H?&HdzLqJJ*g8=Y3RyraoTreF$~BGiRpEEiM^^%_+$E{KFb5S$ga`bbkVNU zkp zYvErCcy+c2xS_KY{4-aD6;h?O2xvsr!-t9$56_L2Gtb5k^+sH!D`A-~iG}1Yk4d!A zN4ek^=#pH9u3EKg8diK926!eGwlXhaovO5|;Q=yOi3xndq?8s@tZ&%#pB>@wvK{nR zlGpHPlLGF+*W{bNquBH|Io3P?Mq2S@4}Vf`;@al)$n@>HSOqSYMHa<(OAPx5hz5D(XA*j=zlq)RQj8C3laldf-KG(0FC0Tp|5fFiOA@J=TXjlL~4orB=SirBAWm8JZ3V5Jp3oj(p zRYQRO(i(%rkkhbJrej+Z7X3vL#Cdm#TnpFqHGa+9q>JF$LIR3)B}sH&ZpgkKhymM> zD`wfiKGsB6SvzTpip~o_<4FqMA|!y@^}rHRk#*TnH3zD4@Eb#ew+MW3NC0?up`&_s zBHiJCl>cOScX(J;$XW5v3hV3zQLnA zOHY#HtpMMkG2b-5F z*fSi~C~MKG%JE@JXe~_JC*^O14~Y-@N7cIjhW=CYhyKI<3-VdK=cGEXu9E`WDc+g< zYyIQlVbi47_{-rL`z&v94fpJ;VJ4)y3hO^|My&`KM^O@asF}fyW;oMC&)LG zv*b#+>F=0T($xFpyXa5Z_lo_pNKgCk>aUuowdb$-8$Oyvy+$i!mOaMa!`{z+Bw>D} z0(*%)>tAAL%&O0gkPmAcEb%wk@oan|5)-4`iR|5H`tl*UG)v|9e0Rd3QK+{^Qsb? z=?vdP9&u0TM9$HYxk?Y~=hX}3guf0+*iGl;jxaB#)i^X-)7O06fL?7m79~8RP@`SG zo4?NqCg{85oW9AwK|XH(#D3g-Ngk!w$%Y<967r(1ru^=h=!eB#-Ab3jiS+yad-Ub> zjK6J%w34=DTfo~_+x>37FSF=)p59DOu|wfV`kG!M6*D1W=ZC3CRU?6%cbT?nr%hjp z1)5g{TZ`N56Xd<_{rX4Myk6!n=+CAfm7fq_bO*vEvYtXVU?qtyE2`(s9<@)+`FgSl zAK(@HVmK6oT+~FiOxN`Sd_+ezY$4WjZC51g{IAGB^cV%QtY=ahPllA;K8;>-! z(gw|9LbU`js{joM3D$};a-Vs~KkWAS4qJ>z6%9E>ccy#OeSV&`!##CQK1aUJzrvh5K!aEa15xzFm_^X? zs%#L&5@Vt#8#d>b{q=BxUJzH4yKEpUNyoy{ByCkQ@K^Qg_K6t9p@NTZbG*nZ3>FsX zv&j+n(=Cb>0xn=ds0yHO$R6Krck#V^ryrw4U*(6`cgQz|OJ7dTy4z~qf@@+<5KBbK z)oIU7&`H&CCCI(o=8CyQud@Zww?zp%GBkP36=~ih)~CUh7B)c&`y@i+s61ASEL29(D^GQzUR6&+?O~Q)x z`0!?eC|3lf8c>MDcg7X0rfalm;oZxwXathnO)l``?4UmAj>Ky;nfWtBjB(JaoLwZK1( zh@HlAD3KD+D_EidRzjLrn^X>249imz+NbM&IYxV1-ePyef?u*LDQq`)FI}OlW?c?E zY!Ev#$PL(mg{|*kM|xODqQDCg7EgjGx`DNoz~&+)4;w__T@kjMz=y-$YAom6^b5pjb@}3y&a+U`HNV1wqJ2!DkSdEgvL9y~_J^=!+a2L6El*$Xa+% zkcOoxhkOM3&O1QKh#T;s&r6~SFDmFXfzjD8VsWG)R5*WFz5kk1`{0_LWTy^ z${@O(n^3 zK;!aB#SA0*_`XIS#}AXdgv1KKml>s4$4F$}KqrZj9i*G@jIh%f-l_>8hMgfckIWSvCYX;0g#cf`AaDmiNM-mUY((+ygd|0Wb!SC21eOpV22PRh;v)-g z(uC$1q1pOicC@c^z-cjH)f7CPkaMFXr-&Vjyu!US=Zh@Q`y!VT2D%UEO8`4Y8p;CC zGFezH*Y|iM#aes78_>r33eoF`Hn&boYE>60@;e^T+q~I?K^It`;67$oumq57xLiWw zFc6QtlLjUN)}M~VkmW7zDk8EO4s4waTrmMOSoskxbI_T>YG`Bx9Wcv)O9Kh0Kwk;G zk_bP8qa}r$5d+99q6TOi+Jb;D9udLhSqvR(D@h8@6BvubcC}c2g;4-A;6N*=g=h2x zT!>LxpsPGju{Kx{+!2MW-527z2ktx(eP52iIwh6}T-%}mJ<_2nrUL;g(*vwRMrG*9 zp#?=>f^IbM8o@)L#=e7JU`Grv1iaM_Tn_X%qyq`QBZxqRJTH0JCZ4DY8PL9{`XQbK z=6sG0Ntupxncvd|mC?qAD~k)Hds52RT4wDuF7GJ=6sc|`hr|bTVze-S>Kcy z@Ffa%petnER^&)m^s+Ad4FMVrgM`=;@K>g=u0`ME0x@}yyR;NBS6y^D(PzV$7bVpP zG#hrLNV>tnNgQ!^O=Jahw93n&Pb&h~cygffY1x)l0l(mJ10T_>Vcd}`V}zW~WA=oW zSf5u-(U)j}ZkQ73C(SsrpoUOl#G!}9+d(fSy%9>uhA5kXLgdI6ftQ>sVs=F{QiTLk zP*(jK%TeH!4U!6Q4D5+z+X@>Z#~=fEUfxQV329zWxN|Lye$V*_2)=b|N+y=vZ^&qXQk*V<^u!I>3MEvng--9Z7DP2!X z7X0bpGpK^ZjDfL1+Mq;K)ICw-Bil^+rWjXaKJD8w-|)F~jhE=E&B+a{JJFC4W}ry` z9ynId5uec;s9i&^21pz|@>nqqIC(*0bqygzfT}#WCdC_5aE-|NW^0TLrNwu4M}Tfj zF#+WVx^&lJn_hzi;>KMZUF@YToSyB zW2EyD9OXxwxJMrkP8N8lLNAdMkYkt?V9ee`3Syu@k0K8^kfro_Ixrax6vMhHO3cyX z*=$BMNASGD6$6YWdmo^}Ga1e?dIp2S*bY}dg9+=aa23GS0`au8;6W=KtDE9(cFzL} ziyo9v;E?9!>n$Fw5+8-P81%_LZu5=VuiCtm-BoDk_{hy3;`J6_3T@d_>E^H6yf5*c zwZ3szqqo@{A#2M<$`13toNu*k-PwX8Yf163oBguB|7)MEQ4H?B(e7}T^~&a$eKh80 zfyeCdpa+MxY+fF?%f<{i^Jod1XAwO!IX zKbT+kj;wv_dke2`^nc@-?7n*albvs^=++b2{I)(B1v{K)Jq55yUmr8O&afeHo%P75 zDSI|+f8&|#I^DbiO=DdoMorP?Hd{Te46d?oxB0Bi;W{UT=%ML?cZP*f7Hzfh-oWLSegP2)4(8eBz99Y^MDTKEJvjT@gAC0Heyw71S`H(kxR?vkMF+#}7VuC0kfhQG; zCToGeE?}dl1&^pOsmQX2{T^$qn~aHZGNE&Jk==|J*;#T_9gHuLqdxen^tM}LdEN}; zZdy<3aX%?&0$kHUyeDtctKv#>gD;VFHS{IcOOd^&+w_#2K;8j)P`1gt;NBdAhwj>L zTuid*WLC|k^I^AoSMuxhAyQ>4?t(g_zwe$3zwiHt{t9`4zM?MD+rAPWAa4!(=yrjq zAM3D@yC4q4gX{!34%+sDlHo@K&NBQ^T0egyH)vLT1 zdTMukGvXyXH1b7BQN zx02r!|1o()P=8NcN)L)}&<|5Z{w#bsd^bJJu9J1XjXx>hO%wGX*-t02$_weS_+9o) z{62r49;BC(WnXhU$iwz6?(y)XeXHA}r?67j<8l2mIglRK7s-Mhq55D?d_dfv?z7C# zBohQV#sGRHLp$X8SmrG`<##0L6W^|W%lwj>H+gm0oDkoQUl6}fmHP<&MtGK=^U>wh zF2dD&_(SRaVLsGppIrAZ$#3d!i|5l9(v$v1T;*-OPrp?>F5XJtO5V)&+Zi`Z&hvxx zWpzNF29}2go6JKHla- zH>(r#n0Z9Jl|2fG=52$l_}9WgdO*M8Pa^|#FRh`^e)6EWU+>2Jw{hgG38YAbGzfr6 zmw1~_i+O{Hh})MuDt=9T(9ZA`dDb7a-xXg}e*`@J1^c#sS)5Zh#fF@9Z=>%G4>Fd{ z#HPrT#pDQe;c4|sJY-I?%jQlfiTmgy;?ek+d5d_6?sK!WB^SeKeJC7er^tDG-QNp! zwlmx>_sczU7rjriFzG8EHbhdSu;KVH&FeNt9-r<=?-RTA-tZ*-W%f>04Y%D1eV9Hc zo>G65{MYm|$+PaDd=)XAHMY$>?w(}3>AaW{RMy3Ma)!NVUXI7~33HZS(APO(+tPjf z0rQ}I6MwUQKZCbHzHL9DKB}K`&-ugr9DR-55+#DHF(kp1 z>QbtDv=)}#WqpBP5!X;za09X0Wl|Jf!~m!KbTUVGN~X4vjwNJWc zBxGJPX{O_xoK;i0El{{BIG+Q8dOOHME?@h7$Txm^)*lZn5pRvayMKDo-U_n z_2GEH9}*|Sxp=``a#!hHi);!(Zp@a_lBj}W${ZFc^am_Cn@@5KK2IpBszWrCRbxeF z(W08DI7GT!rZ3^22*kfEsx)F*A{H8}s)h(%Jw-fJR%JyY3aH_qxKf1YiV&5}gC*KJ^Ju9xtJ8FrK zL`Q6M+vzqk78;>uD$w4G>bkq^u8HWE>1ya>=It=8cNkEXnW0m$r-_b6657)9_ea?7Q?S_DTO)`W(F=H+0pPK`T4xo8p6dhpzbraZOw&m*mNK5P7OIe8H4e*H1a{ zq)GUr$pdc2HCRQB#9ed2A4Rq+qzj+|$alR%?2-G_&U8|=k`m2@%s|Aa_ogQ>ffIp1jOn(nrlrS`YWB`^Eiok7el&NcFm3 zNpJA$bO~~%roojC6`!(`*3zL^40q|OBd#vnv85214ybJ8s1N~%R$`r@ZYUi$Jw-*w zbj^gGisPz&djnJYq`bW}tm}!1ReH4U|6dd#-bx1{TOFMBV4%vSxg{J&Aff17+ETvCmI>L6ZC z2V#S+>O1jN`kel@f1bS>*ERLibS!N;P`sYDGb!Z+d8s>YgLdqWu$#=0x>?tYW*suT zl;*^`T$O!R4X6jAGo~dF{nCZdpxqQzl8_`7-GOe}neO0|4%Nc6DqFEfkp1HISP?VH z6Z$bfCeDVBXRMnN^ZcCIafc?4-}73#dZ6OV?9KYk@ivU6Cz=N?J)pErGS9ilUJs6G++`*^{K_ zQ4K)0ArIOTRf62KYFp&H0%d#5+ttIOK@X-M$)IDOre}3a?@ssNEgSS^dO=;_=i(9O z{VVE}zAegXI?l^kK5m*4)gipfifZ82VVhOSxZZBCM!W<{ylWQhhC_99CWOJNYo=8Xd`{+idVo-f3i>%~ovFpYx^%VoZ(&l+Rp$z#`1wEOJ>lrl*F6@y8*0ZJ|_sDoU zH3{l;NK>Fbj*Qz`^;Z6NwnwaouZKUyy8eOqiofNi;$F3vcKBMn>d(7Z zktaQ3ygba#$wg76({w(}3GkS%D8x6_h;4**#1QLz%J0-nkLdzkQa9P1u&NN@G+0>= zA6z!sSTbf>s^sCnCPiK69Y#HNHn^Ug5;I}ijfW0zn3`+wHti+AT==o%32@7+=CkVe z_-}LLUx8gQBX{!|Rq%`Inz-VFJLL~22l)|tfv?88LA72$eI}^0X3H$^2MX2r(5Uq= z>9?bPaYEJPhP}ma@SARlZ{SWfG<`4jBK37!(D2tIA*Hk-Xy}RYFwQ0ns^F8J>4H;n zq%_i`N9U5q#oOh+I7pt+A7#HI|JZzmT_sJrUCgN}a%R`F8X9@oy&8^(L;RS&l&ptl zx=k^@olcmRuhMdw7qIBUh!$L(jfojM8Je2Vr5MGM=rdF_xdJq7J}FC7Du<3~q-B{; z^QP<@8uis4+QIbXIGrF90U71fAH=?BwC$u3HgL*aAbkKaH|5>-e3DtR@WKsDX9bdA=@m!{Yo;@4z99SKCY4Xk9qR8A1zNGd7z@EBMz6#G*&bbf^N zOS_^gQI8pD?1+x1=@iR!NQtf`SNtLRQanhH!VV4eReQ=E7bpE|>2117kS9!scG=y9 zj9BpNq#&!1#IWf-YE=JAQ~|xh1~_> zUbt)TYVbzLyBclLrmlvvE0Y>&8Pu%C4sDBOs1sz{Lp#CV3^u00J+h-)u@$;*j%^oh zmJf^MoPu|34zZ)|R6IqG$3y<0J|Qk!RA(zxVUi8EWKf-IRxPT?bY0Xm5A$ORZq^IOjeGs)($M{9F z;QPA3kWnd+hOGoOm9HB9FU5$zDa;IQ&E_7ohDX?5bd@UlwDei$*?}VkK zPf!^X8WNssf@)3ONIImeD4{8It;XS-tj#+TyMjE0B!q?R8?1@*X+L2rYJ=a7C*{lH z6?VuRktgZNaKs)YhyAJas#qpN2gyd)>=LNxp6Z99ugQ9>I(P}9D%yNX&wHkKxGCS# zl~9n#=u&98ulrpA4eRcWwuUk&=dS+L;(-dBl<)<;ow`P$MiXWUEbr!8EfRo!m?eqD-@Y+yeF#` zDO1P?N&Qrc-Be^=Oj1}?v0&g4`WzV~D|XQ?dQ^*;oPlg4wNT+zQ6o*&_8r#t*nbm2 zk+hw3eA_|y3fS-nwK0|gGM40p#X)(m%Y%b&^VH@TiUG~d#!yw0( zpw3hvHX$0MsT;t5#bJM(Z`e-gnK2KWU&F2oV|>Dl*`Du^mTt;1y*qgjx^+dq6h2Eo zX0VfkAM;mqB*-TwBqFNdH_S~R%xQI&Uh+5SUA3GHd^Jq#-F|=AC9u=Wzjw>G*J@(PC zldYxC)4$iB3jZj+qffA_>JDEMRXQ1_OwBHkv;2@cOalDHMSoXCx*{rkHof0J=ywLH zbACgDN*Sbz-i${C*uk>xsv%D{=(0ey3(I4j`esOqEZa>B57v|wyuqX%nn{~M1AABk z0uowuXj4H;3+QAIYG9DHvB&q3M;U{B`;PmJ{j{|78FE%du>w0K$HAkl<2T4pk?%{C+zZ8)kt1>wySRE-CU#$kwV(%PwzFA4L0XkPHacn!%1q zQ5l^!9B45`9F0}6-l*U5uoq;uGpYmrfQAB{p`MI4RKwLxLyv`B`oXwO+!ar!e{25M zf7w5e`0H)ICI$+X8y@>DWHnt1fu5kJ;d$KT_xKwc(K{i+}E z0)usKU~e(RRdhWRQ$*AhDxO4^&%q9BLK4V$4_Z_$K!FNkSK}?$vZ$aWsMFSsfE^2} zZfgdyLjx(`tFrDp$*kU&?1@czUVnvtTKv8HhCU=O`9<2tm^gGHZRlpq%NWj?|rs`o4yvQ-;P|$E?T$e_&=$?j33rEJ>(h zc9(xZ@1R5XqWo+1-^7Q>S6Og6oj@kzUfb^v(2cTr;R=qZNTjv&pH7X~{0{@G8yGzV8Q;LZ>9Kz-UJ| z(rQw3uy7=N7TaW?Yh5z%W)%KMfvB4?wJSUn_q&=tV*fh*9s7Uj&(qU#5Nf)pvG*}W zTvoIsV#uUn)}b2@v6uW&eKV=(Ikih}mxx2LF+OLI?O>C(XqWhPb`{?KlEA)HiXA+< zkRnr?AdjHOcqbJ3K&_bpDKSXzNF_9&LS8_(Q)mOHSGTe9!-Ps?z@+zQ%7_)adE~tiI@mv@5p9Ie4)Hb=e&;FX=<+B|a3`N6BYm$2HwJ zcHKRs-jvR!d2vf!ve(6`Mb;qZ(}7(T_mcHULeox2WLRJe4C1;T33#KX8Edfux!Iy) zae__6POQ0-D1~YQt(`^20;ZgTa^QL6ge=dt8aqV8zLr)EX2YOyD`5t?~ zzKPEGb#{&(urGwe@?u!!RohW5@MuHNBoCP%)law`>4;oP&xspm6sxjGR`?yV=m{`2 zEyh`m$(~**t{+4rsxDz+S*z&#gg=0 z^sOex{~?1h{JwZW4n@C5s)T0vC)QNNc~*kye{Kf|AANBK1~Fd204V&V)kg*c8UqwN~Y-j`ce5X+2N}i)*LxP zE~G=bP2Yz+M>ENEUqh7Kvb{xb$9||g?4V4ueTXGnQdQqEJ&XT<;E`2ITeeHV&1p+R zD>B6U3mhFPneE8{#ishwtltNzAA>nY{{riJD=%V9y*fe_{Vm`CIrHZT<&Dn6y-<3^{yg1*% zx*BzyJWuMTDXP5a5n)nY#BERsVcQPbyV$1iqeGL{0%8Ga-S6NZ5FZLZZZ2=Zhq&g` zwkzM`-o=O?HPFV_zw>9 z-Tp`HPD0F8debb?m|jjUh$Vvk_1Jy7&rgdSUDEdg(G7>Vs%RuNS9iU*P0qNn2u~5T z(+cqaX~#DttRgo{e}exO`(w)=`@{I zW4xk?SSJIPlU31-4GOPMc0KH02|A=5nn}pIgS4a2+N2Y^Y>vE>{3rh*y({_R7KH3~ z!y5nD@E`mK;+w&*clc#{);-PsGWk9Fk@$kA?&tXb5q>4^19lFY1LmAq)`$n1RX!qP z;z9m)#7g)1d~#mmf0y`WlQ+PNDwzr`vxY&%J0L{1f)-pYWY$+^MI!#6Aom4offnSo zr0(hxo>5W@_0YCGGm&oRkF$TTf7R{v-`;{!{a3nRenNc6{2TR%uKFAHHF-)p`myjw z;jfYx!Erw;((o(E11kEL;xpugUP=(zqWPp~sossci6{7Omk$@>5qH`zh&G$|lSzwi zxOER(IFx-(6f`V8$f8PuodOCw^GsWh%c*4CwnW*&=CD=PWNp_1Up0BlX8)yRyLf{9 z2llJ!y!hJd6#2)l?|w4;M*JD}7Ewjq_yRfR{w4e+{}c6TchWKStL}eKe^$=P3+5U3 zj6X{@L}ou1LPd>}{qk}CNIGlR_&IizhGa!|5mT8BEt==3@{j8lQDr`$gjH3;!;(y3 zx%o;!jS!hgXsjlgZ&?Ob5#csL)su8OoeIqUbo%S`-N{Y*CtHx(XXAtMgXCA$ zyZN+O2^a0D@E!AM_2=rZ=`*sxf1LkE@oOQ`EBb)?9zPoHhKg+4DlhvMMQsd!l8#JA+%$dB;9V~1T& z{j~p0{c~ZbzR6xP-$>mDRzGB~=zZw@W1~A#;4-13AtDTQMy?Bga*Z7DBgnvh-)kucbdq zFMH(As7n3|KZD(UA0$679*?bbnO$KgwF6c^693K}SJUBV>~E3}kXdory~th;=R-d< zOq~{z5*ed={Ub>drq!xCCytx*dX=}#lo_|w^irw|8nQ!N=hy5l10TdgPsf(5V+|@6 zF^#0EiUzd}x*{3`Ubg_B!Tv`cL5wBTWL9uT?$iI){DR!)U)jQ|{-j%X?=U~l-j5oW zl3bLRlOyJ9^i$gCubI26v)MzABb9qNc7G^S(i6)qeS4oM$C5? z{P!w))vapm(lTSB>5C$7^9*~;p?%;TN8$<&*ydFQ=tEh-YnPC)q2%E4i;`)Q3B6tI zS5NpyMI*ivKjwc&{E_-vvMToTxBDm9eWFH}lZ(k=_C5Pm`%QUF49$M>uJm1gzbLvZ zW9$XQGM`kuY0fC1236U`QGCo<)JXbW+ayy=uQ} zC1>$JIX1&*Bk9&9(%YvMkFj8L}nWmWQAtwH-U{^s&>OpZ!lvZrtMTSh}aS9u;OenS`FB1g_;qw83|>`T^+8` z1NnIPllTYh3;D3>iEH@vXh&x`v|@zU__HzA_lL*$S-mUVl5TSc+0bD3q6iabiMZe^f&&9s@HgF{)rVcNVbsO0K&#%)s{SFkr1sRH(QA z_v^l6dCbNE`~A!e#|W2G9W#>aV#Kh9%_`m(Lx*t(%EgSq{&2IRHUieVBh48MBc%xY z$V8PfZ^tTzHj7Qw7)@KuWi|M^(!lp^FQL4NKF8XU!7dhu{eiCH>lh24R~O@@aFLzk zr<#-etXdVLxSm(!CB72Y!bpwz2E+MGzad$|PCt%1ob{T%8j2}HH6Exj)aYt9K|e?w z$5pg}%%eW9F;mC;3MbCMWnWbuwY|jYVKe0h^*|2tpq|p0=ZZs(Z`Hz<2C^S}Vi2do z4u%zov?mVYtNMxXsCv3SUZ272IZhDy*|fvqOtU*Fj=2}9CJdVar+8GK57SU%&AZ0R zv0{19U^dte8_X?8jF}tMfo5PC!}&#zadDvh=tazYWwdDtvbLxn4N40eX<#Ut?Z!Nt zLz@*Uv+1y}3cW@uZXY$YFu_7~`x) zmrmm;@u%1nxQeJzQpNC1rYhhcD~0{|v1fY9@T4}@!g$C^!-d)wb`OjQjEoS3Wl57L@)6${{1n{e8-ShQ zLl^;1-sUuiq{xum8su7yzicI_5IeyPo+Md`f7;BTl|YRHPvc(<$(%3^OW>G7*!E4S z3a#BCbpbBO4mgxzf+R+A&P+fatg0c~8a577L(&;JK=#mL1>lirXrr9pW_LN%`Rc3GLg%mtYjG*yu?V%bTD? zvAo}i+rci!EU*&4*`j(mUPq~U1Kon(;gR1PAsvUr8TpiV!S5(a0+S}^r!F?j{YUr3!ZI#J3GZ* z(qZs!TJFeJ3{faH(^4c%qDF?^6iZ1F;Sr>h1I0*wM3b;}`z&^nooU^KLlU6S6qcS% zE0JxtZ{a1Dj()+UXW^jGYufk<4e}#i3V-EEkOD2?33J;`*ktN0SlHsca7#WNG4gyZpR!w7KYuB4aOXCfI1PJ@u3;o9!eQ%UAu{v7TOZ?xIzC( zRSjd{sYY#?NmB!QeHy3I7;0&%y{WF3;8lZbs-YF^RJ%L)lKfrkvZzC2>koHT(oD4| z)yTRc8zfMX91=6|r*Hx-n5;+!5pW9_L#sx$w?_R<^{;{v!1hQ1Lv8E^fM7>iJ+YGp z?FiyQTNuzfQj8AqC(uHB1)HxVLe#f%w3>Cr8TB;sK^8 zZ_p~nP2F;2fI)^*%t6)SPi_l5ijP9L7DCY2hS5lkY5hF>e2eY2{5;$Ne~K%#PkK}O z9R5vMgBsJIC8_*{^!9x3P(0d_V;)bOE|fVsX(yK?ZG+6IWynNgZL8gE3z;MRl^Pr+tBFs0MA1L^eseM zBL_x8FGzt;)j~r{TYyK(34((IaHv}fk@|NnUmmuM5Ek)r^c)-3Kr5W6Ob>rx1i%^m z1N4+Y8t4gXP?Y$BAm3g_s#ve?*Odb_14f)vT*MQ}gRsHdqyZhu4UBrwgL4FNqEHez4R9p*6t9OQE{Kl^KLw}< z9~Sl+2Dw;KEEES(urLmJky>|gQS5|IKCE(}L68W0;fCxU5TX)V>O`&JyRF!W0{IgS z!X@L89=Qb}m}%|AE&1}+Pq$$xcGW^DMg?h73=(CT!R^7X0WAhdNd>uxnr}msEg^r9 z%PoJ%^D4m};o`_CUO8Y87KI?`5OsnS81YR1k`@nMI(OKLq4*M%Y(ydBPjQe5t({k) zwZ$#^9Sz@xD&Y#9ZHQ^96}sftw73mY=Rk{MqY}wbCuzW_eAxD1d;}m8ZjuH0bZI0R zQC^pSN#}N2OHTV1yThQIqI4H5)6yb(BrkfBkHX)?o9jA<0rMh8By`TIdzG*>V*QIzMt1E)8-iBP>xOliGGcqMT6KPWWON z>>fT;Dk%2c{u6v7N)D?8usG~Qg|%+thH#0VZ+W99*$b@m2`!AU2tsny_!>p~MG~|a zi=0Ib2>Ety!qJRMx@v6-VLPLMr|~B@W1epFHv=nw`$3m%1`dc(CCO$#Ua zkgd=m?uw1LOsxzEyMt3MP$_3sKpUq}HPeUE>@lUxN703nL>Ck*;`lzod&kmhwLQF3sbEli?AVG9P? zx<6qOCA0OXczN4HEK(>ukUvq_rbl^7utJkU6HVVf$=;bR1i8C72vfnOT5O^l@h4h^ zFG>-);$`$GzX{g;3tiKO*^Yy#5)NT?F?Mf)`YkxYI!a*+lR|c;Y5nP0xPIfil-Ytq z_VO<{#ZDY;bER9Zia&)aeiV*sui~QEi;dn*%V~j82!a*(F;7tjGHtjtiz zj+RHvtjfUgTQL^??A9t%3EOPZD_oSYg??y568{lt?EVBLJB2Q5m$XtxF*JC)mRd=Z z1GI2oQbjS5F^~ao-xQmITea(3C2o3p{I^Y6A0v2&;aVJeHZ5NBdc4HbHk@2FVxu>O zb?vjfi7ManqqrzkdHdE?RuDOMh|sDrttOIGD6K^nW#0hp6Ci02MpKT*|HLViTp2#2s^>*HY$ZJb1(I4L<+Vk38G`7Saqu5CZENf`aQ6gl>l@OEdF z!WTz-Mr6A$g;HAsn^I0YNEn`~O*2V{jDpd?rKf2z30mAF{RY?_rUo?z7lm;xv|tn( zC5|FblKghwk&FIBi_+HlG+UHAKl15JXYa6eOQD1&=@mRmRnyX=w`pxeecMK^<}z*z z-{fD)D$yZVF$M0neEsY2&Ywa>#2#CWQff(R6oPUvwswM02-oH{<#=rUiZ4BjuLUIv z+Zm!kTopXu(j-5!nHGz}z0ovVZr$ce#FHQf|Ij|)D2qaed<&eUQRor<4&H3p3YKdz z%99|4OX7-Pov+`bQ(*L@5>8lY3&#LPy!kdgUC0tUxe6t66IMxe!74r_#?Xc)TJ+yG z6s9v8HmY%`#8a8A@vK|Pc=$A+%}~NA1eIltXQ5Xhg-U@DMkzl8Em$Ne*TM;=x1a^H z@LMQ!AqYDHv!p!29su!hlaIr@X?+QUa0;B>M3d4>u@yYxfJ_OuO@Vw12ZT{l)wG-` zJPVB85{7uDCsA#XeuC1oP^NF0T+No7pbc=zO>Ym53an5ddoff?6@RjoGVfZy4qD!< z^1zGu7h_v{YQL4xrnaM4c%t|Sv&e!<5Ajf*g#ytdL*cq-d3Th$caeo{Q@f4PK?!bJ zD&={3DBZ#dgG!8oYa6o*)!`RE)AHi}7QF)L_@yu%q}V$-60}PfrLd%$-lYVQ3Y?0aD{H6Pj=Jtvd!iHo9*9+_x&(Ra|3!*T6AkG)C$zSK{{`Yr=#S)kDCtO zVHbaTzVRQB;@E~II7xsoI-D-F`93)Lcjj_?2ity^6p-7z9-_Fm^SRi%=QbvVAZYQ~ zws-Clb4S-*hPfSo!TH-MA~@wfF|`Gtf%60$R3vu(%U*+> zuK_0w3{3f&C_b{0e5vg!=_MF(sqi%DU-9;|DxFdFIFW(VsJPh{Cn|7SmCm?ooav!m z?hT9venVk#dW7`?o(kt{@y01?j&s(jZ*dBo4I?y^1ZW3T&}=GjD~ThGyQjnP_#%5* zoQSW=)8djE;~YrOObO^;u+tuA+GAhhJW0T*BnLf@61sQ74u`wK+3pCvdt%uysd+ao zhY4rt*)kUn`ZxKko=WHCi#Ej&L_@sr$)^^G#0Ug&}g#DRD6hh zIGzv3r_vGegnX18wI|h?e9l%8I+x@^1KsFphwbZ4HCDNK1?fEzUSucP#W>b|i`y{t zJ`SyQw>g`E8KvVpanZZOG93iyA!n0vfb*Yc&EP_S{8QY8U6}?%0Fu#OW(2g z$0wU(>{vQw`*AMK=$+|6+RK*`v|z?6Uyx^2b}u)Hop2}fX@YZynfh6Cj33VT#RuGD@~AvopWtH) zZ2)P>9#DHDGz8X5;CWrGnM>|fdyLWD3@7wigIgcXv|46+^X>*33B#hEcKzH(Io(7_ z9dc-?Rts_2?luR^_2$-aV_Hu8)DpkIU&TE!N16xIqxLZija~c|M)w6*YRT=bciG)} zZ{~3(_HYtsU7fWj<*EE?jk|6%&i?yK?cm%mi(P&f$DPv9Q!u5g#5hjf$6h^Saf<`n zBd(Iynd{Y6Vwc{l`szH-^~>=He;l_pJgJU0FT~UJMKdx34;|lm$?Oi$L1(7;;2U)bQw6DUBH(Q`W8<wMk7fHJTmL%leZ z&?Xw7qg74SeP7`#A4|lGTwNo)X3Rh>^fI(h#eqQ06DmWe`dU2>5t@J_YV-`LMdINwdt98ahz$kh&c;>weuq{{$NgE<=S?Xqh0jKabQrphw>6|`Y(ZM z4J{ECdM7o?jD;TL2$?gqn+mOR0*?WlX_QWc!D-$G<;kEFHfZ$}+FS!Hk2XndE zNeCM%hmsnB3vA?nfo& zZa|^lOe2j}l2T;aK0(H8O+b5HBV>Yf$OmcY>s}2Xi<+=ODkAu3K+iK*c}QPEmz;$@ zY{$fUSj($+Rj=6%HZeT~y~|>{!57)!6m(dtSHz0gXz-N^v{P}~O!Wnyw zxaZsst%q@24IK=&lQ+1dSv$G@pb)>>HHcJZYeDh>tkVf!6&z;Dd<#RXwB; zH%`ZKo&=_$k%c2y^&t0}iCWVu&?&RdSfVnC(pwL0PcbvnYkEx~?gl<)kcV=}@rA^R zAK48tGGpLCVixC@0$T_or#ijXTuEX_bce_rZoluilVQG96o5@ppe zUl}TWGYzx}H5Fge7tk_YQWFDCLS=@ieWvT4Uw3EuS-v8n2Oq8BbVO(>Yba@uRqC^0 zgB($idjQuOWx`etY11fQ9Br7dkZS0gmUCjEnT{iO#=eG@Z^NMMIK%`WXrB?#xSv*# z29ynl+cC@>#|;r2wI1lgh+Y`7Y1h`?oO+iPdNj*?!A?>R8*affe?~oHpGwci&2&W# z&DseXdhDuzJ}12rkENsPq}*&4^M12XZ`P=rLnWa3s2PU7pSHN2A?%3ren;M6p?N9n zF?*V;*<0h4{AKgS{CWEg+?;kO-f6Efi+oB|pnFCfjSu2RwF_#Wxih?#?e~}T(ezk+ z+`S-I?W{hSuC1?dxFJ-ZN$coG?B#pXfOm9vG1hV|54c?oZXk-Mv z%`$(V|8#S!euDp|{qN-OyYv2o@x$)6I2}%j<5X_=OZ9`zL(Plzti40MUGCPe)!#D@ zspsShhkjNDXUx0I87oSkvQ`h@!V$DL9l-ecd|u=Ke9mW}GwFieYf+3#(ZBx}yaY}UiFxy9TRmi@?`7wcik-lT5f zd-J^fZ1d~xo$(QhA^lT(G5m+kXN*KSe_B3lFY+n#y!xAbuRS7W><`3`@GI?$?3?+k z@d>`3aT{Q~0{!bLo73@lR!sXFO>M6d47V?x$G3JRyFK0*7ns!lRsLi=um35<5x%KD zYJNrkIJ-(7S5dv_XY#rFJN!%hyU=rWTUPuoNcp?|%kqA6T+X>Y?h0`zEbvS6CHY#~ z^oPvb>Ko&fIHOLPjj-3==5JvK^xMOK9)31YmAlK-pM|$UkLgcA>+M;8SU($CT#b*2 z5bnnaLYR-_x2K7J)ZS|zU@yt3dLO?s9ZHM-qB|x|>Yf+jE_b~irqlVfn1sFRc6E!o zQU0g;@5h_tUsDSBZ`H%_i}l|%?+E>P%pHm7$IBy-$ye=jf@`TinD&Sl)VG>%pd73~ z(g&bh@QS=?UNkStqPzK4H{YC;TPRSHvg-}ug^b}KiB*tb;$n#(bm5& z4np#uuJ3RIae-spm|l_h#?RYtvWt-EkLdS=dHzDa&wRr?#7@M4yqevbui_JXEW8|g z^)>uvw_mVu5%v9IbIANc{+#>8yrw}J=HdJ!;phF2sjGEAjC~bX+7um61Djhzs}uccbQAj3wOaSh3mv2KW|5VUC*IJeIS2M{6pwY#XZ5e z6YWp+&F0hW@8moD-Y{KHPw|Ob9wS#!ZJrkn&UY-1Evp-!gu8>tc zXD*6aeU-(%jL4&jn$f$}ZTWNNzm9LWUnI)xchqeCW8wquoy{%&3d=>W`L_E*^~dqP zaLEY%UU6&KBR1nP`$)LYJ(*9ToL}dz3Nvvntk{0q<@Po_qED*l61P|9&!LpuqwXil z@?Y4Id>6kxye-u3c6E)Mv)>WFZ~rL#O`Z8JeP_NIcPlNqi_H`6+bY@@e2*W92kjCc z@QLm#&X@TPe6Q&9i~aH{{fYd!`setngHHMSAM=OO!Fa8@-My8))7`^@s{RlD zCHs`w(1*-T=0GYEGeNp=bD9!W~)a3VjVae!p&S6VKQGqxo;lAM&Geoo(;~{BH4H{=s-{ z&f$UZHTg~TU5k4~^kTRJt>qzIspItSwEbK&+{kb;q-WY#GZCL?7n(0+9Reh z2NTYx^XP5%#2i~JA=pWgBK=03^=jGNJ+EatVi?@Gw3VaCoGVzfK*tF!0cFF44ZCNRCdj7%0&;YsA&iKFw;mu zpY5=>sJDonmdOkGcymf$5-%Ifa;Q^$j2_7{pH+RkBXPB0tNJ{DCA`+0ji_(UDS07m zO5CmMcgPvEv(p-UyRl$#;AYYS$2~-0(e4rl(lz-#^5gvOwB{dEUw8M$2kJ-N{przW zg&%Bg=e4{MeWlqn-K^Q8?0)$-&G-0e+vCvtt!E?dHpE;9W2^ZR_(ATt%`maUxMXo# zDdxX+Dcl+x4)BBSF8e9_p0Hj&%D%?G!XHdet0(kh&4q9kzf;`BZf$m2jBnzqN%DUE zP5F>IZW-TW4%!2JH($ssUaU{)SLKdJ6z5=cK zFEr2B52Yh+PQJz6ZEj~*gr0()a(CVyRv~^PJnhbhS+m#e5&OkW$W?A%Wsf!wnrG|< zlvd2+=tZ%|?&Le?VnOp40vIzWj__wYaH7FPdF> zuiulQrJUgwu{uzILI+VrzXZ-JKd z>->&1Q5*ieIjX;#zr!EpFX6k`?J!ryg}DiB`d+^39!q~CALXz4O_Wy5|E6WLC*wBr zjIjs4&UueHRE&=*J>{3u!St^53Gu_ta(vm|Z@(7FPMTzRk zQ9c)s`6D^<2kRs8Ts^IJ$t%rO;*h;g-Qbqvsql!sPdthltbty3bSEOT>PLJDw$CxE zVP^zSsGXWY9H6D#Z*HxB$o#0h*-qk9=Ii#$;r{TXdc1xzzJhV@PJWB7<#iHw9_Uqn zvU%A)7oOmc=j6|_itS8S`m6jQeMn;_GM-k?`6K4}bWT(X_pj6oaR*z7ixT?2QL?5J zY4)DC&~6*2*bcEvigdSnKfgH->zC4Z*jLs4;;=blpK&ka3+~GU>85a<-Dl?fh@EXt zIg2-l2BdYvS9|TbjLkBOguo@%!>){F(G@{Srnt=WO57ece~3Jt+Sh>|%W`ootTB zm*R{36?-xC<&xRU_Oo4l2Omn@=%iQc6@Q7X)wqM)57}&*t7#O68x7)O#&?1`60?AA zilLosxVr|oQiwF4F2tw9L*cRJsD8e|9hvM^d!F|jx)*mpa%`x^dCgwZ=jt;GH)iUS z_7Y=u)-HM60>&|;A$kroAz>^w#D*K!(AV5dgWp+>aim@3xZ_Gge=phx%m>7&dM57V z*QM*4J$#T(xu@6@>L`1`;vRd6nbmM94%m|1m2snN-A73si*<(k@yuy^(r2?8HW}&K zo{pr87Ac9S^EG-w7CKWcQ>eo=)=9z+zo==|U_sz6C<5^d|%(`f4wwCSq8 z#>|k$%!0toT!XZ^S&7>X6lQY8Y=riBHN$WRmBt)zT=x4o4+DM4oUqTkm%=ORwfdww znNF&6a%B2$%F!%sPgZr0SM)8L6^%JiG0GE#IfjH)91Y1rhPX|T4>j6giFrPS850BD z#tl|V_`F41#b+|wLNiy-r6~@rzif}+Bj$Bw&Wq#WWyE(nzGhy_uewuc^%?JT%xEQ~ zK|vR_=EG+KV&%Wc`}M+K$CNv<`D25xok9c{4dkC_ibeCJ}36 zYRoW;!*MsDW}%-*m+-Wtdj^IM+#+7w^p#0>F!I1+ek@^rxQ3?W24$N~$$>>5!_7o! zL$?)M_ZR#*i}@ULnw<)##kuB^!W?hFy~lCWR86m`AXiqS1oKUc8GDKOx-@aj_F~^a zQ+I=SB6=`v7^W2Fw%N4DEKMFbyBr7T0cK+{PLr@{dtqRy7ll$4P@)ap zyalbv3VE6^zt;>D`~^6GgobJ02Lb&a%OdDWmfG1*kM`eS?v{;f=o+?|OXip{N6on= zFe7In12zgHhxuWTSx!+!%pWQk*$b8KGt8TXfk5l$dtqAj)X<`&A(cJX%YBr)Uc|gs z>NP#n_xLtk6kc=s$BF^B-fWAS*Ar5>cs8Z)lEZ<*?8v{M@2hwLZZ|EE~fL)q*__*lxX3B!yW2M&W2 z6w62nBmx=BiRjhP7w39utOt7B3}7E1FcX@`p7*Kc5s`nYXGw<8O&IzT zrO1vLWE)2Ysj--6wJ2=@U#%I7K{GbEW7*GI++t!@#4wC4YTl-7Dl` zT^ZEkrjODA%3)yEnt_3wH6$kxx8C6Wysm~~q^9($p0#U!%Hpm-F$#kOZTp(|qfrDn z%%H}>ft>JOjeFGv?mV#Td!)$*PwLq zKHEfjf)pci)uH73J|w-VdXeJ9Dn~$WsVbu_R`@zBz8(ds`yR*F!+IID67qkTH;HGC z`X-NM5A`}EQA6TLBhA8tzCmtje5DL^jz^l}1oC1YxoAL-!!MvT5f>S2{0{Y!0Y3(@ z01ID@Y;6{Nd%(#z0GHko=?I|Qz~vYN-?sI!Erh5PS`-6?HZ7iOsS`a)H(_$yN+u6l{7Hc!6|bzdy`2&UOf*Wwt1F6gw)#r%)rDH=6H<6uA(z`@a$Y zjdZ%u-TQJ}_j*jkL2(ft*}Bv_NGY@~l9z971&6T6);$Yl3P(12`_@Kw3RnD#YujEZ z5VZU|A9}mCq>|0R-q9`gB8AJbJNxC*EU@jkyV$mQ_OJ6rxI~-Y^z7(d4(WI-{>6u2 z`m%5(PU4UJ&DQ^N>II`bw`mX^a&@7|zw@l~0j z-e&G%oX;10FRetZwkNb+O;4b9SLijMA5tmIZzR@KuF5@&`pvCz+@#G=^XR_8Y)dnn z(eKR^%ch}TD*EkeQln=C479rueGApL?H0QYJbIdGU0?<=uA?o({T2zUw>9;KFoq!x zIQEgm%Jl+x7*#S-r6k5)9P7y*gnpmsULI?#uO(JYZ+MM+voSW zD=UdSi;C@pB*`mV1~%X-fCELzHh-BLAXqSB(o4jyr(xl1emcjH^@ zQNB-nQGUsOD}T*=T|LX@*xmI#{GR4Eca>g@BlUFpiu^pgS3Fm5rakehe8?VB2i%On zEidK-KN~kh&thyFv7d`$e~a5y?@BuZW{TO{fc7^{!%`UyM>PBp16sB zn0=JLt69WY?{R&<_`0}Pe?vYU2IltqgZ78bZK98L+6VI2(tYMA+mHv-TiKoUmAs$N zhf8KdvpiKV);q;6%;Vfue^UOkeOr9V{dW2d^RLZ);U(NhGsAAmA9Fvg{*KAv`X<^Qt@Ihh&Ub9xVx{F-L9KH?6CQxY>L{3>-o z?Q{!nk9xoSW%;Y=hI}v0oU7l@N%Z41zgE24f6{!ies8^6|Ec?z;rHZM_;7{=J|37>KQ znR~Z=RQ_XbaC`6*X*W9*Z&i2W?#BlF4 zxA2?Hi{t7l_I@GlThjr%5uUEUtDe#$cD2M^x@@-{W4@x_+@3!j{|oc;dQSXyyDsv1 zHSl-k_lS49cdK{tyYf==K>io*pZPz~PqQn-`_231-R9*vM4rg-Wjc|K9vTIvTF`ACDia-=VHBJ#oQ2C;nRfVfwN<6>iY?$am+xVclhY z!oMQVvr6w$hx7qI8^&=(v$WIR*?ipnivQ(sv-nGjhyPFFME#-o3-ROPZQ)9}V0tda zKd}E?{VQ|7-K{@vf7X2fJLN8h=krroGx;+6TK%%!&);p|>8`LF@sv1|&NVB7`8h@_ z&vO!^4%T;z>FVY!=|fqI&tk>tFDRyDF_-=0;g{{F%>_&%}RyuuEP!_8y-e)(`b;}3|to45ESf03QRj1fk)q7qXacQ@DbV#xb$s21cQ zdxLvB`-uM)|DpPH!iqLl^S&r*`>XmF{SUeYiQQu6q-y{j9nxjhkcgm6Z7t{Ll5j<@cHm^@HZ;)Q`o3;x+yVdyGFXpLfsL z6S6O^MQnT3*qn`P8h1=Fj3G4R(`rFry}<9N=j5zgG6&){<_Fzpu)ccG{~^W2f47-q z|55%=?2qb&`bG9U%i*N{F8dSn=ke+Kp!@Okli{w+>cipT_;h-?c~QPpujZZX27Aa% zP%KaN%Nb3CSp?Q`jrKIKu9<|Ropjs1GXtaHpB@=*mwoEfP#v{RVRQJZpIVXtVwjn;8j zTC_8KAaQ?u+~cm(ABewXe#-7p?UyV+&u=ilrhiGkgRk==Iq6k(AwHb`g#SBsEC~DY zr2H-F5`Q#5B#wsD;e2yJPx!prD>?7EHMQXe4tr|M#H=vX=^pi7+G99UHi)R<dS11gZYE)`humcs>lr&hImKOV>L7o2{Au@@ z<`(@G%0Klx&Dj5Z`elAk8iwc6bLl+t=cxIT{R{S(nm5vaG~J~K@o4^Dd`7>f&Zmoc zgw}eu;-OcsHET#G_6-GAV?GOIW>#^z%PsT8h@F-iYiDU1^P|_x52Rnh-iJObcNKpb zYxw_h{xrW?oVQ0Mb|R!Z+m3)UE ziA#ATr#Nm8*PCHgZqz+7%W+q(#I2=vN5ssgtI&?@!Cj5-XP?y{wam9UX}&0LjGs+E zV{fP=YvmeywmE`I=v95TSx-~VF237Nt5tqpV+5%d z(`;Z4JIvyy7}h&17rX5)&eOEV_)QPoqTMTQl0WEv&VD#<*8e-&8`Jz%-p_xAe@foz zDs!A4_vh=A{?T}^{iZ!(_oer`_lXl(7k{V>fI;vRcT{Gk7tT+3%I*0{s}tPhJieS&{DUE{{$ zHFwIKQ^&*u&DT)FTvFH8KY;Rl(2e79mdp$BxI86st6a0s?J?70Eu6Ef7V9Ng0~_j| zWyn?Pdrj*lv4`!o%XucZbpxLbyX4hai~lk6A*@M$)BO+epYcCpXX>}rAJ*^XSKEF* zYtO}#>ZyER{q69SAGvGT+x?yPK;6?>zQm5@7u_rJVj7s8e2-s9y|m#mTdFV` zZ+t2Y0_`)z-g>h$FN;MnqkA0lk8C(0XVg#*H1@1!+~cR`yUSzq@|)lg5H3G|?CFZ2X3Q%_=jJYa@IVZO_ux1O;V)zeN<>?d^-hMl_{dv_CN zWF7WgTg<`o2}l1}qEDUCcNaahU_IZd;-L4ABy1@!kVjH7V? zi{Qb~+#qIUSuca11_ouZooNj17|Ly7Ta+DzIWFQW;_tAJ(1O2!RrdgU*!1AW14eL* zo_~!$N&rr;NSLPeA>54KJ)_yO)~Kzw#u%kRy1O@VY1+TRn{31}8R9*)@36&N0;dU5 z$Vd^{Jf4I_{v||7bKLT$cWnKA`}S?fh?$kx+7h6=N?Y?r^ycutWBYbTfn7D=G^7u?G+JNWm%|2F0}q_cHlw&@i} zC*LCFg59*dbeP*1#B=8={1aveC0nrr^^wp& z1lkEE3?A>p|YDVa)mxJ$j8*oZQY?>b6E8EUE*DYJ-1?om_zu!$z3b}1uOOM>X_1Sh4>~e}oaZCSl znqBOdV-mN8e)lGtU5uS?fpu`VB_{{Gj%J5R?`=EzQ>YGBD7Y5Z#cEnvc32&5p{tRG z5@wsDZCle)?%Wh|+x|wI`&&L8gu;-0```H#*c<7*(e?e9{<2s)dxvA-M^c~^byNse zpxv{$JO7fR67u_f-iT9ti3cVB-2LkQ4+f3Ml z*kE;8VZGU4Jv}frZE#jqRB;$9YK#N(_b=606kUb#Q*4L8Iq>^RQqkv+qo#=gF&Uvy7~ zqxH*tQ(sgS-w~Ge&U&}SUG5U+Q|twH(Vt`34P#z2xxN%u#mG<9b9P6)6qn*W#?FI? z(i}&8jgOEw%nl+>A~#$v8_xE+1OAHUK)O}!@mNW=EAe=I(jFGrfy@t^qw*wjd&Fiu z=X=fmushBO>?Gu?67vx1w0JeYYF{-MA@xbqvx{n3am(#eJ#VHp?ziLL!jtagW;VcGB0yUo6^KkvymnMJoAChC%Y!9STEcaJqMxMw_erRjlTW>)RQ{LDVH zv!3EpZXhqZQv$PE`Zab^;3jLvOwY~6opzVosh87ynvH!m64(u!R^m#+`mMytYrbfA zD(u!vJYnCJSysy&=@vJzzF5Va$%Xp4^i=&lepJ7tpEJkYdc@d7%xcVkvps4D@A)a! zix>16c2?w=&1rtN87Y+eW|}Q2?w8y=hfGZ0jU-N!>J5zGH*-(Vu=%i1^rj9TjJ*Jl3NOxlaNzlC~;!0UgsNj9TI1GkmuB*U6MN^PDOL<_ly|%+IhL? zmeuugS6-JauE*EZGwFzYEW8*~crL%nPzMN{{N+n-r`&C)EOsd&2hUUND#vr`th;D8 zW#0@e#*lK6Evh*_T@UfCVt`wDj340yPSd1E+^hBSlFJ>+F?5QQe)nbEmry)2Ta_s67%ks)*7-;o) ztWNt=@+f~fyewZ)FW58byu%qyJ^**v>u6^i>=mnf3R2?OWi8jjC9z`G6jrl!#Rv6_ zpG~t0J6#iY&>@ddA6nYM(vLXX#%QnYte&ZH=GzY=c3`PN9)=mkq?<64X9NES_6DLXdl!@!pYrcEv+`# zzb-JU*4RhI5u=4f3`VIED^LntH=w~mEn_4dU|i2*Jk7E41)0KVjH^Ry67X2-moOUV zh@a667Dm+?JV=ZjMU^lvATA&|%*F_eqz%T$g4Wq49<7C;J$raMyaU<}fsr$D!-1tRJmT&|w@+>wAQGA;At+(9dD&b0O+c6RSF3jbzy^)>+A6+~pEKw_ADRiOT zg}MAq*shI(Y$XJ_DTKpw+mGDaJ{>QBRg5W=ACL0FQ6@5MM2iej=}d|BjS%u{UdJf( zJA8Uyj(s_w1;@W0vh$-jil5thUoI8$qd2y)nijusMt&M@3R$R>r-r*}VPvC!!7sk# zL;ntH+td?A0~@{F)|0T@7AE1BP~}~4N~jKxa4EK8D2EI8zO~VFTVCYrTk5)vuY6a; zQ$Q#R*?^X7zqSU?(89<~euPJVqS;}WH*rL?SY`0N2GF2CVG7LPao8jLDXak&@zcN- z+c#=3_)COTz;J*ET5+$o!(^(Vu!b)y;v{3wQA8}hQV6H;lvRWIL%^zx7(J*^{1i{| zB|Z{rI9XxF4|oASj%rk3X5b~@d+dm!&=%A^$|-T`h!eaK3no{q^ ziC`M_IpXRyXe&ZRHDcY)B-D@xaS;%=sx12YsLiO)-xKYA%GmPi5njMofffgKd>uVI z4n3-sUC)d%cC*#J2p$4_sU`3ejh$DjuQnsNir|pyZriJw7zm^w_9S*;@pc~<(v4UH zYF~?VX6(+)6Wi{P1Z3=ne4;8bikm{-#xgNtFS<5`e4G!su*ojA+^G%63eGfhxq3=j0ql8^_4*8I<<1tcR z^!tQOa^QoFjDEL(v6$_m4GOKb%A>K%78i`@OYNnB6 zXdwbh8@L!#ihM5*1l$7hs4)gM15kj>RNI;~*rlj20z#Ux@4dl!fM&fOA}uToNIC($ zf;W^R-A7*rVJ%|QmEB1F8fQ-u=Kk0)BeujCYmf@`yL!B`J+@I#MeMHC6M_CYOdm8+ zUf4*02BkO6iZ$C$BMXTmA1aH~21rHq70cK`YA}9N@NH0fB*jYmfzemCo4TLdlB}4- zZd?VL4r}odITo;&GWOzT>cug`4o@AB@Yt8#VEr@W%gc;o zkFB1P8+urytZ?L-U>RS8#kUu*wxnUR=!e!5f!*5@dCse_+4Lg5RQOlqZcx8S$T3nV zNMFzwv>q#@0qaBxu>c!8rqxQA5+h(uAZuWYcEwI2#Q{5hE#r_~Lf=wD_F^;lHT?O8 z0!=kw%nguV`2P7urdbe_SI#8rTt5-Rh_VJrR=UT>38Qd}I@J$&<$(^*|si# z#>j}&SM#L?%KU<^6ZK%&0SQ2HYBG9w=w<|e6U#u}qWS4Gr*acCzNrC86P z)D9!|d-F-nnsMDrsErzYpB8)7IHY2cJ8>eh6Q1=N#9NPeUm=Zt5>U4%lvj`RIh1Nv zv57(1lfY}h3-5d6sKQvqjnz=&9k2^ngL6J{$WsSNH;|V{d5mL;l-7_y2GoIy#TO%c z7G*d=Qo0JrQw2ZUm#DcU$qHYKM(z+kY7@_Y@PR}r?;*>CoJDy2eFe^d>ru9J6~QHZ05PnYG^pbn)JG9x z4+?J}!v++I2jY!Ff_sF^c)Ci#m|jBe#vbVQAT8{3iPL_j-qGM3Tbg2c<*mKHE#va)(@qIPDjgY24q;DU7NO*44#Z z*g-z5*Vqb;)cv#kp?El)v}f2E?BN)(1$L#}C8qPVnyaT0lh}adq6B;cI>% zmn1j4>ivAToyUlFm?-@uv0<1)=w0e6b4z$f{l2(Q_ax4)LOJbGMpuCvA$4v#-m)YCfOtV<#haA;^8^dh>SmE_-7h)E9Af@u+#g zeM@~u9(5N3{KM{WO}?f+h*3Y}me;~*``?KztHHb#Uv|6V&VQ@*`&@rR0V0$voymOr1 zHz;X-n$6Vpl$UeeONyo{RhLccW)| z-kjkcl0(v@NP#A0MUH)jM-z`4L%n=lQGdS@ARbp96N+m0kO0{89d)`fC=&8|*Bb7GEiUK|UcLDCc4=omD?pe;>`#WaFd^SA;x!8kfL2jk9`n7YL( z=3PH=cfcQJPuMRM-(u6{dmb^CF}+~k^=ElMe6jdieoXDxeYvjArWfR26wm6DV$F@G z1MUg`x$v|VYMY-5DZa#BV;{R!KbM}2pEr-Vxm1UI%-L{Gl!|E%*}a42Ksl@WZcI$Z zdGTQR8TQrmP1Ce5n(yTw7C$Lo(I4jPai9DK`?@)5r)|St7st(yQh>DURogB0+K2sT zLt!2*rp+~-{Oj&bdz@d@?QleYE*0TGZmU&D!kv|u^fK$%1%22a;CtMRoIpO0@oB!_ zJ)%FaezSO(f9L}L%kszed3M5|ktv(Zl zop;@IRU8v9K{E47-j0)bzdC9k;`8`MYb~z2MY|)rY>MyE3u($vpwzU{Pju3_nO4&{ z`~8UgCi{nO+CCfpjs8DVG#`}L!Ywytzoq~4R53EB-vY7T0ozL6@cHV&HK4T0rJpL+adPWmiMW zJb?mHQ6+TYuzGz0Qj=GM(u7|^k z))J?LbK6dE5k4<}3o@`P#UI;$5&wk!%q;STtNH!v7uhf8r+hQKtN&8{ARogS@hi5b z4wugql6@{s$cxk-`s4OoT;?6K*FBt$`WefLTl|W;THMhX6QOQQYv@MJEsqf$tFy7x zQ{$qWIu2{BuB&=>Iv=!8tN%)W-7L!gL;iE?<8zFu*)*^R>=*3U%u}payraLPzXRO^ z7xT8835WIL>KRjr>3q?@te$hpUbo#e&ku?t;h^GXn_p9Biu3u7YPbnGC8ml2)~{RT zc7gq+SeHG9J(k!lvF41ji`DoD4H{}8Js$r{{zZR7eMkL)__y{YGnpRA``v!`VEMQ? zY9{3g{-@=CKr3_A@cd}`h(BZxbD^f}9rd=3@kM#jPWngGbtkXqv*r!x^7)Xn@KAb2e&FIn7O5RD3(9;W!i?-N8P2CL8YNxuQ&2ic{bS>nEZCkZcSC4aykWAM@8-#i$ z|B~C|PT248f04h#POHQI>GT9UprEnV^>{a3QZMB1@*jtD$muVIud0X33BBPL<1KZK zpT=I;X}1>lgr~}<*nYPiFRC;7vR+lqH0Gdjv>Y#ca@;n`O}?(T4dggcLfQc{30|{Z zH&F~?uju54uY2sgVqaj=>?^+@9~brfmi$xw$L?8k8@28U@tB|IZCA^6r1G+Ot9T*4 zk}k#x_f-5M@@g`y%Iofm!9E{+Z|HT~FAf$DxIMb5@02)$FSZ%Z?z6VWxHw@~EJI@f zYdVbOQX|l)5_1R1Y%}!oWSX#@0`q{fCY!mXIvkpC%18YX)Rj-{4|#Aul~?q%dNe$4 z_kx@2#j0H`Zp#ah>Hk1obUSXJeAFIgvynm8{-(OEm(_Ay%8+ACZ8jC>N?vsMcEoNg z<{?m7RH+YhZA3wA7RiDe7Dc>HR<5HIGN4jQP!Uii-XPTI6f`c7UnD?P-RZ0E5sE%p@Cy3Q_%W9$X?nmTKCiaq*)d_YeoW})pt-IArf#;*9Q`A%kr3+NIQ zQxPXK4g88lwW>Gb7H6iR$J8KkIiXq>=Pu+DUz4oFo@Lp0=3U7)Hc)y%%yod z;8YRnVN=!<%QRQSev!l3c8{GW4P7WjPt@4$n8k5>JZF7JwbFEiglo|?J8H$=F}JW= zUdCH_DQ$xHeLht{cH7Zu+Lg3~S@3$;Do|nsS~k&Fh3_NI?@!XGn3kmzUqc_qzLp>|n zzB&!na*bR!nAwXuugkiIq^)jCNZsY)GnK{ zQPy}ZBQB2Jxf1dDR>Cf1Y^H{(7j<2a(CN*a0gpr5>8Q+O1dRCVxf!4lA$E9^?eG;< zsw?gicG++6<%E@&2>lhQ3EW#|U9MslwW8L*1FBsZJu7H5uuW6fSP=`*kRZ1+)=UC? zbSpyVhi)0rhS;$er@z&>K2Rbr&9#EP+mDX~hy@Na7x#=vmQ+{;FW ztg>tcl=6&R(kSo5B>_V=fwIrgqG!zZ4MHc-!LV*nqV?dYs~jsn4)QJrs|E$u74$ZT z&Mv-g!5hA=HUgxUEp|2;R`fs}s7j!##CHiPVutVnMj}<9v0m0)gEdtnqC_()KMkT{ zNL9l^#@V5iMR3lbbBHY z1YH?Buo1hz3|uR>6INIpR*w>>vEZ9P>2Zij)lDOTmW&ndRF~ie_|YivE>Zsy=+;<4 zEt#%a)CLM2fhP@VbHlPFk=kNd9wJgLcfz)WtaOAC;3m;T6g${7t^I&%1FirE?KZ&G z4QUzD1w0nU;h}m|;>k>-rm31^sz%gj(Bi-m3y#p28`>Rg!pKJ(CaVmU;Vd^MM#0ppy%D^q7d}P2EC>IGPqI@Y(L$MGPg{1EQ3aVHs zc3#`XfV@NdKoACSaY)ZF9@s1%jg>4u{H`b_9@x8>htS}S!pa$80Cm7dz7et5VND=c z3PbUNZ&Y5vSKzIYd*v%@0se%8;w1MHYjT8vN-l$|L|*5ie}JEXj~LqcFeJs~v8oo3 zE5HsP3|a4(QP zHKb1u!}6K|9D{EjrkwsOj1D0gY{W<87GXpFQHeD*3!56oqVHnm!*IM-03Y#2AvDE_ z)Yj-7@FXgg_!6~p=u3Rf2w%W0qP-Bc2p3Ijtw<@aQCg{vm4Lz5&;-Ox-vzjaI*S%K zBj2dZRs3Mcrz-b|4@67GBT#!Pn)0xA$eOMZKMY|(2~a}{5%&;x2^)nZsv}%1{=v1O zamY_U#7QpXOK=e(k=9xX$_Sd=suV=T>uE+XjKhIes$&`kP~a9qAr>kn0zMQg*jM<=68^B~xr?5Am@a+IYJoMyN z=e0Zx0X)cofKVm;^bnJUEdU$Qp7G^}xG1CtB;lba1IoZyxL0louns+_gb%NQUX%p` zzYzw9@Cmhq(x%}W5LN?2LE5J1{E$wC zRw7ebsNoAf;Li|KL|BWbsOceH32(w6DIEym5IW%T_#)#0t7>i-w)zhUo8YS9N+~Oe zYEVPA-6sHoVg>)y`pTEtBJAPDOD{V-h?G?yry5jo=k zfzcGj0BCws`s~o=iSD5fxkY>>81f~%hMnB#o7@y!D0~8s%n&9F;lt3C{w+975CKmG zQDLJ0d^Z=<5KassDTD(w@txc~p2|?!-?e-A5cLF2R8hEqhg{>Qa2&kn;7|ILY6Cwq z6a(QSj1-!T9oonx48PK_q*Q*yGm2?MK^1f5NA*D>ht&`h*(xZ)MYJ#%*R`TyFQ0f(pN=o6^`upnh_+0vv+-}cST)=!3;6QyV$CjMXQ{Gk38eil}At~<+zA7wauiWULTq|?0t->+#t!!23(f^3%5sd#7PlXLl%l+Sd z4&3L!eGc5`zf34&3L!eGc5`zf34&3L!eGc5`zr-Cv=*UGj>K4wUK+}L$IUo zzxhRWGlU!AFn2N0yYj8xe>AvwSpVDQ3(3p{jZ?N#Sg<&?@>$@rIpPO zL+$#EzDBr4c7h{Q#Y0#}F60{S`c^OmReg{Y?OvaeTLpKo z55ZIIATy$7^fjXSUij*p{wpZ@8o`ZljNTPy!b&ccslx3-gkh`|uD==oD2{MXiYUHO zYO3#1sOnwun;^({7w-tRdRPCHDGG}o)HxzJk`4jOVIR1@FP>XkZlA*-y;a~Dcr7G z70U=>^d8~+n{PdglW^1X|7}LT6?StMvIS zN1-bWBM6G6k_4&3R=(s~nJ|oT6lUZ~Z$HF1!ZU&xVHsh#mr{Zu_j}(}n=ryfc+EXf zRXk=GieSvJERZWr`T=XWt-8b1rVXN5e(0;Gm2n)GY zzVzPxB5dX^9)j5oOFp~i=iM!Q=o!&o`I7DD;VAsQE~9wKHQdEcc+3zRxst8ILg6YH z`Z7a2BY%S0#Z{$<;;P(sLy;SWu1w`SvJ)3}{VUhXh5oCrQMl?&FqPjZ?#iWtC46M! zJy@%7KTp>PCxxw27(NX#!b=z{*NPkAZYruUR9i;WJH$uOBOVe&Wv4e8lAob}Ka`^( zSC5B6&^r$80sawENaRNt($K%+I>Bl@go|A6#ZX}x;i9*J#8X9cFfDu-AK@VX z(Z9i00SGyao8lmN@*TxS_K{Rp2}%RDI|%fh!7NS9%7>~0wZ!kd>BfV z3P|i3NFYkM6hlcwJ&Z3xR?C9^3>%q>D<$5L5vzfJH3La5lJjzSNScdcONfQevRI;Q zc(NeC-9pO*ha6i8$wI;foK$FNG}X88K<#C0~*h<8Zg2Q2<{=II-U*a!`alWGR%FL+DAhvPg}2Ic}73^d{}Xw=ACY!jy{w(?qDFV-YZ%jDa| ztyJ>c@lLtOmn}~3@J*7V2F8}8Tdc-aKleQhPG$8K?#lJOJf6pGPvI^4nlxMD)T10z zJ>M2>+!=xMs%cWU3+R)LWpOQ^XV98zPVf`?WAzC?Q(P*px{|LkXn??(59di!PvgGwH0$Tx0-l*LS4PVo=@yZrU^3V+kQq2A^nvD5C7xns9OL-hEJm@a1QwB~YLHxu-g+Eunv zE{o;3CJ=wXod|5YnCCdPU+&X;)gC!3royBib7QV)T52rdbQy<^iTGeKk8^g9gn?-z zUsl{j_Yr&FzvEsoFXp6P)o;sB)CGUl;zrHfx{ep|h$zHi=UFXG(whw?%`uWozXJtJr09{aGwUG#KHQnf7Z4$Y;w5wE9f;tIP{ ztmRGBMEY>THXTfd+yQm~r-$d*jGETngqv14PTRUpt|8BHZx`RPPszgtmAx%?-Fz57 z49EEE{`=xx^`d!6oN#B|d4`x{H&2PZ;vsb)98!mHGPert2kkP#$5I{{Vl)2 z8VMRx?R?(H!EKIP!^57mSIimiCwwo0cSR$P$9CGUpEfsxR5P(|+o(%dkgu8U%E{li zABX3~EB2&6tFyT2ksrlGnkkRU1%5Cdkp~qtvg$Tl=6BRJciEke7yT7+gDv5VQ^Sl| z+!w<4Ko9SMu#fH62O{pf7t^^faYwZ3N}Ocoz4VBl6C1eA3%EUWXBB76X?|M2SHA3@ zQzz|n<(ul1JEKqAJGRc5>c`o1Sk0=#;;>q9Q*1hR#U@+L&=o9k`FLmT3-%Xd{`dK zZ-f)#<@}!e#Gc0K=w${C(y|vP<1DZq)O+KspHR*h3xa#I``2e!S^%>Lj5rVzrVf=(}SqZMjXh z?KaVdZ!o$)do8TF)pEtHaTo&)uWmhWaGdm0I9(TU!a^dXMvucGL#;@jAN`-NXPi-0 zI9+IPzE9z-p~4AK1)Z{@>ENnh%6foyBS&ZK&}$ZTF*FQ09BUq}ct-CSVB}D)Uk^|7 zp~k?Vf5u6ra+~8pDT2v(lRe{MFdT;b_)zPsANJG=y%?b&@5whJv{AE!pDGSg3*YVYy?|{pntLj{QKdz|J2_M z?Uny17IGshM;OTWZ<`TCBa9yL`@5-5_^R9~oE?U);v@ zr!W*FnGyC1&)@#9=&vZPLR2^na&&};aE!i3Z$FHKLX%%*qj&XHz2h);awT36broGz z3}hpp%0^fSvVx#@SSEB`77Dz_?(y&ICknNM+yav}^} zhz<%*|08&VFN?Y|a;@wmNP?!=(QY&qbezi7w62+G7u^gUjcL>x5!AMY{v7bQDsF(9{@o6G&)d z;Fz5?R^v!F0#~^)a-S60%Xor@oD`;NPDC4G@y>9DGiF<`3N*YIgD`+xE zP1z1iu7~BYF2KJ8&RFPQOgOQQQm~b`8FCmr1AV-Xva-RJ{7T;7H8w7Ks%62cgtUe2 zh%=#y&JETzc+DE1dP8q$=%KVd*AKX1&u!Utwrv1mF{PA@p@hqs~k5>q~)}jR*TI7G$O>d z*-#rO%Z-R}Bge?ab_MSF2m_8AKN7yuq~&TNb!@}5Fa9HzHu<}T)zGjYL9 zOK5dVZ?I>}pYS)*MY-*Ieu6jj?QqVWvM0l-fZO)sx`z%xJD!>x+H^JUj%1iWdFWh$ z7ME@qH{8vIg|v|7ByP%-(`r%-(m+pn=xP&_=HKBpcF?|0}&E zYWX1FpSo%>p4P|3DSoCrCoi%q>_%Re4PIw7-h=i-jaddp>Fr{tTq}0in4fb8^bx&Z z&zOPeCDJ-MUDBN#a~RL!9?OVai<`WL`Rw0~-&S8MC&cUWUzY#O{BP+wwQ3KtNBn}S zsq6X^eNvq$Poxt*^Xq&=cNylYemkQa%66PACjFRTVnc4SX2IniexTUv=i-!~%oDaR z`jmD*V6%K7&O?7!*YD`b@HO0c{P)TO>OJ9bGw%Pw{|Y0$&x)_8hkf0j#(kOZiH}rv z=gp;btK8J%8S`wh6_+%$;L7Q8S`5mawCI-nwiu}W;Rrt{=RME8*wek-H@Nd9kBbRC zs}?NQAbguWDSnmzvioAbWB-J12F-uSPpL=QH_NZP1$Ldks$MehxRdG{yB2YqNNTdN z+)*`l$1UnD-}TdBrtBnW87gk)ojhZOe*ik(W3{Z0F8(C~IHe!ut=AH@ghHb<>T3pp+q!em(!7t8nADRoEB zx`)-Hmg^OB(LhgFIVT@+kGTD|r|O}hyTw$R1`l{KTPzfN^M3bjtKGMAA>LGffSZ5+ zNAnYYQ2*EIcg!yptM+^5-}yh$FZqkMr8aF{^?c9mEB2Rl@rgaI-gVc-0)LD>7N*Ra zJSVQ`Ej=lYLjM!=(3vKK?$3-HtrNHNmPvB0jF1>a-i zmKS@(Vg9iCb@xy8Z}ZRR7tQ~`t^A+(yY7p{f6IQi_(j}m`W^mn;-9)V<;}8b*L1C% z;(P7UxHl}>x80liZOk1P^aJb=?}?RsN#54mv8ASqso3Wealm>3`p3}rOky^DBs?zv zN%(#9_x(Zl?c6V~q9nMcdU*R}EZ+~iEVHZqO9!iH}FW?sY zROVGzN9))vC)Jdjh?55Qh`J`neaY;of6D(#`u*Z}{KN6b9Gpx4O06(i{8RTE?g6Yx z{8;}$yimO5j;AYp(NBpd(sHuPXGcs>7%Jd@=Cj zvT1f~Q*ymu9?egN-;KY=zmaSnNk8Tepsl^cPKA@u0g6!+ zgBC*BXKlo@EEoAE@0dwW?fjT;8;o82Se_NoF3Wz?{$usaqOX3S{viKL`EsbG$N87S zlYWot#@pymewKe6o=+$3Hs9}#WZ|aKqugK@iZlEY)^v9CSmfx#nrxG;$W_k#ILF;n z#UM;1=w!6GJ15RyW$%#xd+fK$Z-}0LP5!C<3wO-kaRWPR_Uiq9PVMk(@m>FlcrEAR zc3IDpagGlxY37C&IdP5MO6wdqjoZF!WoX71=&w~vkLk%0Yo%xtp#3oQBX=`qK71*C zD}6clMP@JN*VMb|T(M|LXX2Efm2{KT<>Hh-S)BLR?IK@en+lrL!J{qom>BQG25YgF z8IB?YMx_F6L6~sU9=&v$NE2wyJ7%neW+~Y$+N@JRS0BnfMtS8rhnA_lj4|=2TC$c5b8-B<}9nd5Oo=A~y23t+W%RBvQA(@0N4V)-xl|Bj3&0cbuJBSm zlz8aB%9E0@T851cQ=H+NL0uZY35E=XCp?6^qJiv{A-5`yT|fFF3hwsR?#ya}I%sbGl`!c0`qH&H-7RTw+OL;NIr_|%=g$c=m| zSC4S_!VtGA2*Ns|r^083kP-jnvx|woM|PrV_u?_bIQ1}| z-B?C&r;k_4|8HTRf6>_gIj&N5l6+a24 ziY)*xeTs!*)nu3*yV{BKRB#DVT8M_cOv#o(9740rfWn%Xslwnn%(hOZ*mw}G2B$cv8qPtE@-R; zItuVXVigMiz-kafz{r4FbkL0v3c}+XZGA0+;s6MZ-I)^DOPE}vlu*t07}pR4#Y-j8 zg3H7ShSfKQ(H(=0#$x2-hT}P;1z#EaJq!=W+M}ooV8NUA&*}wc@d-P77IDa0s=K;H z`QUKP*zqf|ju!!=F>aAGc57IyZYGQ_F{Ww+Ko^~2+D;;$m+Vb`gI`YP!bdLW8)02T zT0?Z*z|CgvItny1tXY~>20g!WRqo`axWbvnY{3ppSB;Bl(c=x2nU?OPaWTfbb`WRn zw7{Jb9GZvyAogQNj+;4gxZLNDl+sW7%js?Tp828pf%uE!KdO(h7T1@p{HS|aJfTEU z)2HM|;dFRGy=af+i+)S&i3gnEUk+ak53_!*>udTlR(6hKmwef`d^^qY1No4jX9Kkv zSLLcI<&CfePIUZ~=VH2?vkMxx$nw7FW!%RZ8@egSRXa6hCv$Z;9kB=bQU7=OWO~1R zUOexgmEVs)($BIDx5tTcG98F}MPDxKWBhsbDm&@k)92JSWE!5vT@DYjJ#3$-*$d_! zeS)8Lx6P*Ns7H!t{Aa?f8;{%Jntb0R^D$p4#`uIgP(H3dW&@bj_rm?4>EWkRQ-r6Jz#G zo$_1iMfctGe0~cvtA#wKYHq+g@gh4OpYz8|mbhz|ciqF`iQ*wY;9A$8y`>UYZ+ z-icS`3hwb3w~v~~)ZsX$a0{(k7w6Ndu&BoDRG88We4jt0=Ja;DT3#=&i_7V%-Sm@g zpV?PTr%5)*HM_)@E$R-R@Pjnt_m%U0%wRXbwk7U^)~(Pl=8KsEn#o149QT+LhP~of z(u{u7y=vdr@8-W&KZ!|Axc#b8EOD$^%X9G<`>8zP?#PXDwU}~Gs>jMbnr?<#lPl%f za8_^eX|WJy{Jh@7_PDmj9ABRIx7=;H;pG*fL$s z3}yL{-cwFm9E0o1L5n)c%n{X}f125LAYK>Q#NQWtd>YZn~SY2{ck z;Ra@c_4I`6n^vf!P3)CpX+n>w{q|S%oP1NiV3T`CzbsyMC-__`cs<`pw~FgnoqjVt z$IqlznqcE>AE?`3jZ5P>Zn%HVSB{4@`L(> zeVM)CkE_@COX+Ps#*g?0yPdAet2*cR$`{lLSvQk%qMS*Gi@oIpTXbjj4Ynay*=ic& zd&6PAklL07+&UN+#Y)^1jk0aAj|2*FTe!kbo9-CM^D$^H*FD~o(D}|FJL8}$KSL&n zPoyyki4=*usx5~rWC2kgn|XnK!ydv7RL|!Z*$2hj@s;?FYw^RZBk%BY_Dp%2e-vKU zAIds|w3D4z3w*{-+Esa$UGZxk_llKRlk*47zR*dKRPpO+)lgsCRFk$(H3GQ|DD>Dh z)k~A9S9U_%HBd7f2~epg>1GVvj>Ji7td|<8mb+Lfoeoos>Mymv---{Hr_2lad-_;7 zZr^fmr!7WnZ9B!s>9{)Sa(Gj}TdcWhtSlcwyNA-Ow!;N?E??I>Zam}8Z?#bFGXu-) zqQ#B#sqP_3Dri-A-|Z%ieBs( zxW#^&(&+6J?yr{5@L#fB_lEecdL@6v-`B73Q+%pCsHgaK^A>+UTudM5H~cBN%?_83 z%Yz*9L1J9sK5uhQ-mnb;Nx?K}X6#Hc8Eb0E-%hIqMoJ8K2TGK3H!kauQEAlBNw3hd znStxOj>63@x$DLX++58kG%qL1o`Lpt)pwBX3U9@)0XZEgnp$Eu~#MoNrlE%enJjA2WR zYe5l4m9CbWtiwC9>&GYt*pQO|BLb@XE6zdW94XApF_ABEy7T2>A z0wsx~msbOcyWru{OKn-_^?>`=^IEy;meq;?O=+E>zfg^YJ0xmO}I3zC}I4se( zvYB$m&gL06T~49C(d`)Em24-hUZ=ilhpmVmF}{_S&7!!T&)duPEI*+?bf2h?Wmae6 zd2`J|&em;kl&^raCgcJih(Q<#&QUTf=aXS9Q~7N~ND_**V%1=5?pERoc!s-qRl~JH zS0hw0>9B{Mri$q}<#0ohLVLj{%|wZQA-C0-oInm@UJ@H=m9NBG`EtG}F8N%Xh$q9x z;*>fq&!mg#reDmfX0zDg4LKgi9okwsFoSYZO=|2qiGfDFmTeAt6y1KbTCAznyed!z zOWZe_8?vp(B3c8>J$Az=&+LqvQBw-?u4z)^1`{*p#>1p;T1YpjrdUS_zQwPmOZu`r zBTj}->?wA}L1xrkD$0bLS?q=d<_P%&jdmvCRwGaIroKb2G3-&Omctx0Z>lxBsxU5M zYiwO?Vr{?9nxUP>L|Ei^x__O&ezv!;3JD?Qu66KC>JIJ3ZNKqu(i9=oX6S)^5FJH70X1m3f#C}Lg zW3+X@nYJVo4T=8Rjcb%M!!u{tJCDdIKc%NMcLPDQDxM)r?rN@uTCrKIhFj@Mx~eXz z)9PcF*=Yfu@C*DZzZI7Zc2nXu+KR5j?I*HdOc>NHJ>mPdUyMb_z%$(O8aM4)S}9ij zio^YmenUVCMmCC8Mu|x%#fq~jF>Pk@be<}v9A_xQa)9|$Ph)oHI$=j`l*{>sxSFoG z^TjEd`DuG5o%83_Wp&do>eaXrQJ-u_jS-&>YLl51lO;|k@P5E3s%Ut|u|FhMLZ#3LM7a>!@1#h+Rj99LQS)IK5GU7J(n3{xZ~EY+1u=vxREbLGT2h=a&A=4^QiWn(T)rwN9#F2-C#vy3w;L!mroNccF6S=G4iddN7H^^8+5Y7^A1r?t3>^0~^_J!GKWmfH!KBXG?2 z^qA=x^pF~}1wSdc}wAP1j>77sCqjYSW=r zjhNSR+$=P#=i_#aqc4*fM}$UMi;P2}&TpknyTLcYda+?P!Uo&4n`SFfu3$Va(9V!Wff zycKuKb-sq4chTLBOL;?K)e9*H6=B1yxJ9+7R_rGF`?|sSMxk#kuo~#L{SL}O4Y=C^ z<3HE7DBY9-lrEC7M9Z78cbhN|@Q|NlB!5{K%>?5hg@>^u(#&zcjK%(G#44VtX{1EL zEp1yEhB*eMi`5)BqcF$d*x9v&y8&!l9@6xA(_w$NU=}x9g?fqgM8^U+sZpyH#`_Ly zd=c@ox`t#{fXp1~VBO*_f|6*5T%$wJn=x|ee*QbY&`KZQnq7Lw#i%c}vt3+6LA29nlh)@0yLcVYWE9RY3C5wZH|GKTd7I zc4Qe+k+BshC$Y|Jw+tj+@l^*G8zneZFbP<*mC>VU%15l-D&p!;ij#7osOh?{C-4tx z9+oWyUNNk66?Iz+C|eQyu&#!9)zPQL?}krL#9 zXR@7Z3G$A9o!lkz%TYT@GNK!NTkTl5iiYasHm`G(0S1XwO}Mc>5}O+1a)vlctZ7R~ z;rdR|*35z{3iT^so){qe>k$s)tqq2{9HZ<#`a$ue?Ap`*19jeA zVmI}=>hlN6L%v7p>@`%rD#X6Q=l5Gov4NB zlj-(5}AeA9IGpd6^ZQlx|Fp!{_^C4T7toWD_?DKGI2)#9I5Uy?2N4%SZJ zDql|@XFQ9zFV}o1KIE6tH$B82k+>}vbG4oFtbRwFOpCcI=)}{0v7nmv z2Iez2*_LUU3AHC5Vtde=p+zfDV=V3w=hJ*%aW$O}tB1sw_^+u;=}*I-%a8bp;-cH( z`|~%{lkT>8MZGCs_b;mV(hajmf6+ZH1_kY1oKA104@`+%dyGBI4?qsEUtCge`eX52 z+zHcSFF))Kx$$%pqn-Cj0e-BMZx|HKT~|a z{A2Z;d?%lJQS({$=;m;#KjnY`7=&S8+?@SlEhJ{P8lCpZG0yC_ToH zrU&&Qw(j1IudomFE!~lGTBJwZKDC`Lq;v6x-pH*mWe=$b^WFk;E!&RhQ&L9`)NI%* zkyC7rA5M?CUy~21*V3QqpLoa!@=L{zf1H0Eaa^(Qnv|cH&#Pla8Ta#NipTU^99J9p zjD1HR=hs+IAL2*YXUa!hlb>d9YwTC>HH^d#swe!Bq9sasIbII8^mdv|N77@3a9C{( zHNM5`65~HJud$mVdc`0d(qAk7foa(9>Hj;w>0b%2np3gMf5Csf;Nb$+F5fR={JwiB z-I536Q@DBc5M=Gz@oaG{z2z@SR!q3P<>&b4>}0$qPsR^Jc31hPpI4s|5Ag}H#TNN> zeLXI@jyvQZbq|=mW?CX|#S+^0e%e<+UX;%%%)I@R#kX@Wzv+JBj*Dab4V(BPe@K2d zOrNjf|6g8Y49h zYzZ!^mS`lj#c|G|*bwVxtyp7g7+a&iHA`+uEU_iER4i-Erqnva7=-$%qV5`q8LLnU z@>XuomyXIw8~_(r)dVAmK;i%q>*;`AxU&Z$DL zCD7CPn!~DCf$@%SB>X${=B6PU5**O@7mWgTIs7isrx&1JLh_HkIq|3-uvcsAxn{tv zh~5+B0zF2tqqj9q1F>zyh8Q!>R2ua8emiYT^xYn#CyudE0eJnXaj;Pz?a&1{@P(nT ztJOb z>8izs!wf^zIcCSAfn;x+%k9}V0cjjr*p z2nHOA@J+CJs$GbO)dE_4f{7Kv)WdO#3?A4492(j5sNSV-s~Mo>;^F7fSY z%nh4HI74BF91?Y2&!Ag10-lVLR@9LP_zF#jeyqS6f23IxW)nnL*-%YZW1tlLK|6=s zBk7zShVyeM^Eh|MaFSDQ#5J*&*RU?R6qgxxB;ul5*2`>}uO_S|bIiX>m-bcafwrFMc1OIlidQlFb+MRZX5J>8B`?991`=Oh}Ha3SYjKl z6u7V5-$>`>IcQ3_A}_Mbwk&UJ>MO;O+p<^r7py>@I%oahM1b4F{zSJRoiR+i#@k=R*&x`f{E2HcYEQ z#_2pcR^ntIgB(#Yfl=vR3ArILmwN1yIAd<IDR$-)Xv5SDw`CfNW9h7_gT%0br?S-@tk~#onYt8Sy8H1+QaAh0(&q%#2&PJ z9hVJ<-Ny1P|Hz$SXUqk6*<<{d`*B_zk`Jf{)I;V-*z2b-W*lR6w^d?IpGubRhC!TT zLOv>gDgL4o<&5pAF@2uBqW>TE-u2nC+qx6Od7pEixP5PT-){B;e25e&QreSalg zY?nP&#)2Jd#?H%dCN-Jzq>^2!e93$fl9@@3YbF`k9@}MWrVQDZ$CfP#wj|4vCMiL$cW=1OF7X-L(z`C%@AGIMGf(>$?d80#d+MaRUEUe*D)07h zGNY_~DN!v7wBzGgrgMj&XcRPQxczgVa|A*=w_9!38t@wg@D1SEmj`$Du^Y%OT z3G)NHY39n?+5PG52g9_A04FPTrp-)CRokDD8E zT=0Z-X6$ZO@O#ptYRENpE@8G(KI5M-Px)8PYHCIvj>YA0ixKHeIIic*78{nB)e0D$ zw>x@2^~*(mM!zZCW$zaE=r^ak<@^1Qidz#CFQsqEFQ*6dU$ZaEujTK$^KlrDq&8 ziq7nUdd0mUUyK)uP0i4R1Bq2{nXKgex^F<&#Z*cq%A?eX%2UFIj^33XbZRYKkGK7bus zLXFiE;xqgc_A~fOzOT{8OGC3CXUy?*OBC$5W%8nbMn7qvQLp;UHjxL1C@Ba0NLpsc z;+)1fVB9Unsl_lZ?)$!l90OZUaY>#k&xTX-1Us%U%3@E6cNZU2@5m=z#u}(Uh|Yc9 zd^=s>sG$`ujj<qi@rQ%S_q(+40ps*wsN7&6WlfB7^1gW(RhA|DLDX?{cfd5nHlVGbl>+{p~gl0K17*nYUA9w|eB zWg@-#A8r}BP8sp~cihT7$rTH>?185CC!PjDL=v-{aw!(fj zyP#$QRxLp%^KK~~v6!*u7|DuDb~&AlZ)YFjKNatZTkIR*_uX&AKNgRt8>%7t7=6a- ziM*^%^VwpBKM}rRzM&sa*L=6&aaLhAT+NxO+>85SRnzR)j_UAvtel+| zn3*bOOYC!%%N%u(U$pm&e-M8rzZvTi|C0Z1{B`?Tj8W{0mc)1|#u}HEkY{;Uyv+aF zewBUCy<&Fwbexk|6CzQAiG{%84MEnua?wmQdp5(S!;G4Dvl8pGkn>u&FRA5t%q*3Q zCFaDe+ZyA}@Kg7dTc`rsMjA`w{+&_P-E9 zeAj=x_&xIl{jKm!x@31VR_Uf&%eU#I2`fluq- z(SN}nQBSHLU<`4e9}Q>C9VjvS@ltp^J&|6H7sG3)J62FpYIIX-+QMqio6YfW6#u+MxZ)m+X?C=L2(=%lv*muwUc9pa0fe zXV=-&`YE}Yjzd3fyOADG6@4tU zw9&?#LY_Dt`+QgIrna5&n6*I23&;;x8zj&wEK#zD<#g0c>rUu;)V9cVZ&hc)_4If8 zTjpGG$vmf@Vpn+A&V>DPRo;kK)n$J{UvsN`!)=xO4s^0

&TYi=LF~ns%`zFY#61 z;WWz2kk??7EHx5(q7o&%n&GI6+>FLL2#)olVNPOoh`=agn(?#6bZEF;Gb%9er6C;` z;*@Hbm-AD_Oa7cr>1BB}ZigY;Wm|HsxNfi58|Av*h^uD39O_0v^VC=i#+m`6Mn#La zMZ;rOh*Mm_(;(C^rBQPg(1t``Nllqv(c{yG=fz^t&L`MxkzIqiYt>Ed*pma@Q&>O+VNL9mdu&Hw3{vm;T9oh$S=+^bBST)&Qjn~tvq~79&+Dhvw%NxkMt4Kwx(<^o) z=C=)IUp2lBhTd_)$_mvLRQq6s4o6KDr`b%NkyxkAu$sWmDwNK-pZjuJp!W6X_r+dl zS_*Psm z*Tsh1c6(-{SPxqgsb%+bBcgxK(d#y?i1o(B0D8kJ)neNA{gj7&2QjCx(!ybtfSi(K zXRn{IJ|<#Ks(^+|%!2ubXh@9pI`p;0NMh}+hjkUbTZ|kFu$O6IK`(8qZH<)}<*wS1 zL%$)`?4};+p~AWowr;XsRb$!apm&?anp)T6fVzoebRf1$j9W2=Tnf7`YSv<2++%HZ zz`9t8?<~RcV>w7zi^XBBC3aFT^<0Nx#KL3TIkbxohu#y-?qU2u?Urk9mto`~4*8yI z<~_NVu7_1sS)j{fwNqlviX1~Dn5&FidcEA#>uksx65pL1VSE6-d0&srj^7U*;V zsitk{uI!g+HR*QQjOgKufkWDsSSzbrp(VPa%?B1M4g)mipfQe>X<;h%K#h1Cyc>+S z3fKWu`xf)GjMgl*tC862uh#fAD|8Gje7}uuhO=FRYNy) zz1-m}ZJRCc|xl^U^~vGzSq z>lu`aQ+8mmVwO+)S;8tsr+;aEtYc@yDsEhp7wYPSYZWeQL@Epc_dA{hHm(7nBtwdSBwf+Rx%@$ z-Pnhs_a#>9%7)z#SJ}nlGP_h>^jFGtXyAvL%64i5{_6XorS*J1v?Cz1ukA z`^7Ntt4?0ZXXS#({=4QI#Z&1@+7%p2H&$-cVgDe8prn|TLs4E zGLwBrD~9m(80-QNvm7a+dLH91nN}mt>UlY9`?_N>56TuxSm+HHBT`t`QMNoXjRMx%n%m~{5X0POKv{S zIE=2bPQrKY=gZ}AOwQy++_ppaA^Q*H(fHTdq~GA*M{ny4=O{fl#Yo+7-^+iIz7n5z z-6SwG-VQr{==LH;w)i!+t>)w{_PCtRE|GOjwSmi<1E>QC-tci6!(Wu(K#FO_s7KM(f^{Z-+WwsS8PzF2%}w|}^Y`K@ z_JDee?rQY=`8oGc{uA|C^;jCn2a0!!6LQ3^W?BJ#iCtowh}#|J&Hf}(?i#-Y{Go1@ zUB=nzuw+@jg#OcY-7r{poq2&)g6>9^N13H5yC7ggO7v|fcllJBHE7Y=nb^&3-nR>w z4?Y=T{l5Wd^)L8u+h>dj9|&*d zEspUn^hZ_~orAPCN$VCl4?HAN>b;>T=Ub#}f>|T-U#f-m2 z!}_qEhqhMCIkcEp#5BKE-ccUQ_^Qo@9dX!vG1zM&V0%TO$L5-o9-)i5hr};PC|LuM?1vl;9&EJKV=d0>5_9Rw~KNcR1Ps-KeRPlf)0xz!c zC;ZdqdV(btyJ)c%u{@&Zd?T#L3m$v#_@X_n&)6en!>y)^;i6b)o${zZX^z@~-gi53 zC+#EW&ASCiG>|Qhk|m?%j#fI>X=}7o9a;vtSIlITF9p`(m_=A9es4Ncyu|-7{G0S? zx#I7N5Aa*dHT|@BQao#)#s6t@&NSWaSW|MVXz6qIY4K{Yn`b!fft(6cY*x;&w%RJL z=asnc=k4j@bUEX<#6@=@u7{pkq&yb7kyhzp?V)F`!(o>u9B~8Hu$Ze6Q+a_era6ZF z61r1j6_ITklm%f*c1=h0)m(8>-)E1A7vrB5zhl0rGP^b3ABEk3ERVA9^B2u)>@|#1 zjq+l+UEIoNQ?@UPm-DLY^W}IPp>X56 zJFKg)`-`!1Cv1s*Gvki2`*CajTPExz7q$DYS7uxcTLvN zXzvQFkhZhA$C{8FGgk##@TP5%UjdsFx7s($Iq{15bMc4nOX<~kEZt{sFI({y{uqDM zJgYB@8#agS*hoi&aHmn~Z`fDut7<*>6UH#pq8j+7#!O%a&oC5dtMUO~XZ68fixyLK@`t9Bfk1y+q^wCn7&oRL$eQ=r9^+7dn4V$O9r^Fx8Wk*30Q(F=%$ z>f5FA&f*l`EgwmLW0$G?Bij-H>~kz{-LE8`&l7G=+9pPgnR2vs+A;SeeMUz#OE;yij1an%Cjz zQREpl74hZphG_AAfw>_zK)f-3RRY4g$PMU&ggJXM92ZUdD*qevm+2v!Ovej*R?eZW z{{ed}Jgv@~Rk15a0y_XQW)8%$JmbgZin}J(1=Di^HrMn#>){(^MFS-e`Z;>U8lk69 zizQ~ZORR!4EKUjRGGJ4&5n=OLvxFTiNL}=#C2DAkecdHm$Px3l8m&FnE841AHYG+H z%YK@6Xj_Y=665_m7f%?h!--F*H8;agsH3JCuN5!2AE+cR+trL!_jW(@#X>$Rm-w{V z59@A4Zs>hJDCgONK<>(I*-BWaP{3-Z+hZfaWY-*VM|eN)7FXP5#H{6xnp5#On=xaK zaR#<45Ti)F$U%VKiW!ue?Ti^jjTM`@Z!ojL(E@jEh4C|#5+}?Y+r`)XZIAt->_Qmv z88NTAc2{3xm(Y^AE>_CbVoh!8v4*Vas9Z$3)=+yKD@HlyZzFp6s;9aPPlk4|Xrj!) z%nH8orfA2eM@llxHW%H5IXT^>*r1hxo|K2y6k0UUW=CTm7Vk!^bdD{H^^DLa=7n_2 zqqoeP78h^pP62CG4!dbo+ii-MizjJ6ce=#(Oj~qSs~DOMwBB*ng4;CfaZPTzVS&AG zdEU>N>DVz1!35GiG$MEwXgN8w+WA1DttDEqVbP;2_Di&@12hdtk4+`?MM5jk3@pZp ze4{|W#FM;8`-n9;C1xoj`Y#es-jVIlNC+b`gqSzay{~C}RC+>;~)!VLji;E#0=A&@S4k$-&EmuS1JnbjyxH zcnWK0Q38w-dIbXI1qWP{-W!=Aotg^sBns=OJ?2y+WYq19kq6V#t+Ex7w|IkrD{ol* zHA-F4D4G^^32(ce#Rx?So1pBnya)X$78uh(>BheB)-9ujL!=dcc@Ru_d?Ejzdq7VHQ-6 z0#+qktSU;NDG=X`dfPXPmS~%f>X?o|np&i4YD>f*A_Z8-!7Y)SIdX}EW~`#_u|_+AW0i)%iW!SoGpw0M{I^3xZ~GqKGmQfIDmIa>7!i`Y9GcF| z4OLfS%wCUp&tUbA7>SMoAJ@$Ls+Y$RtJ7WEjS^ ze_3PXG>pVJwG*t2OXPRgO2BiBx5SQ^6>D*zHuNmtHodgVI}Bq|Xx$)(BTr*&F|uL+ z85-rb?U(EBh`OPt^(vc}SJJe>H=-dA@5aqUTJEY*iSaab=Yw>l)&7Ru}b9u)j z-#d)gMSLZC$D+3{264xA{g`89AYPC2X2s2!HQvl))hRKq9cN-z$I1JtYKHL&9W&m+Zu1g*@Sd( zYiZuJEXEg0Xjrz)p6balzLv4wa9y>{v9?c5@hyRz;#y*_z^)`cmIJmC2L`!Cj!Kj> zs;TzuEWaMQc|{N0wjJq?!1^k?r$%W;-YDkPhMhI*Wh3p&p>7wbEsE)gos+CytO55p5gC z?3NxXl!TI%D18LhO!I#4GhJY7d68pKm3`SM5yNWz+exn?qh|t45xVBfAl1`HpScT|S5T zsCm1Rr`V7W__a7F_EbaD4puIPdC6u!C9V`*oAsdB_ETZU&)aMEgt%r-*;Up<*r+{R z!_T;t)HC~`XNS&jLGDrud`-^S z%y_tDj>Q$fgfY~HzRCf&J$&=CYAsEP>#Ae+?I3Oio`xtLP)?b#YM5qfgt=lEX3S7c zyDi>PNd2@O`UW!@Vk@Gwm7TC#V22S>t`SiVLk}pO<-SF0Qx8)MIS%t49Ay!{hml12 z0)6)6er}b+(21z^QmnrYj&}~$^hF+n`~d9N5N3fhz&lF+Y-6N4E#ozDOVI~V$&{$rXdFg^}a@%)a|Qn zfsw?(BIkR2+GCWTH_Xs=!k%y0q3zf$H6QniX|*fSI^j4oBJCDUJ@nLSn=ZFQEADV= z4WaiH+X^B1bu;g`8CoT}4;^;wik>z5CF*9`a47FM`Ux5Ez2_M znuKq_psks=%O29R=SE>(udCT|Jr4YyM;#o73@x&_C&z9(Q;QR=Cb4Nz*DG$W6*J}v zKW4W~%OkJyYhqe#7QJ$uN6=V%2Cdr8Wenu|-#|^FfJqqXo*tqTzcU>$v59fi_d@p{AV$XBM_>Pwwbx zXc_Z01@vm?)MlQ^8<|>Aumhu3WZUnt8RY*Zb3@IDRe6MO<|FC4m~|J+qxota*j?Gm z)JAK&4c@c+vQv%~=bJ@8T(>CMkymz*>(?!JyS}Hl^;C(IJy2F5k0T7EhlNB6zEkcMuwGX5{Y7zHUJWPojWC~gW1qvSv>mEF-G-L>B~mF~ z^-Jl3=f!%OmTP<_V(c@*hDzMEQ)(!w)@ulsuoA~@E3{FO568M0(UME7Xz?*aTUucU zMB4TEE(+8EvK7(7VB4C?&o1KAR@m*U(3;URZeLCnnH`ZU#k5?BsO2MS9kW$5@R)A~$5yBNZh|xzuHQ2DO!8Wh1vCN0W`s zkfDAo_QQ@rZDvq2#UYzdD~ao?sULTW9^Xk_gVP>3+F7O_ZZO!M6LV@?4ES!G71*n& zw`JGvSoC`=`Wgz_acI}2rakvIMm!FYJiNiPpC;e z`U|R+S!f_daQb5E=CSGqN)OcbuBp)bNMtt#vXm^erLi}P=G@v(>t_5mj z*AVCltCmA)UQnMC`Y4-rPqxY(iDbQ}WC_5QsV9hWpnjS0XCDl_6%LGci3_Wq| z7KwWX?c30_Xuld}kun)HfjQJJ8PfQXX$AC!!hUYBmO(!%V-!k2F4q<)$pf&9R)9t| zbfM684@fnMHa~b(@iABn@32QiKpKbK8JVK~1hwZ-W_$Eb5nJ?a>^?(_%c9+4n;M!- z*u`KGE7vqAbxNdLi8@E)TM|vb7h7uILqgXuETA`0Vpb3FWCgxB106GrM9Q`uLTYH( zK}tpK^;Q}Ne3=~eY)0x7XqVgljI@&YJ7~oq4jOtw%#kxPc-!hOfsw&IfyUvfP|_su zAZp%_kb-!4;6Sqk8)@{$9C~Ju7$FJN{|4oS9}#DT??xeKF!Ue!C^ZZ8gCdI!k3KQ9 zf|xn91S5D6y+Y5ofFy!st3tO3!{S>jkS-;9;tW0#+R)IZ!u+E~7;#*pZD7fB0vs}ivh=hziBvNaMCeiZGq!ZhAH@zcq@@=0bdjYCj&fJK^dM7zVsKB z4^h&^tGfX%g;Qhr3P!vPbZ8Ma`Fmhk+zsyZMt_6`No{pe2*jUoCwB{9l3_wYPe@nc zn+i^}4v+}#IpESe(YxwiR__EQ7(weWChsHz!80_LU-z@%=MN|*RD@T{K@j3r{|QF_ z`XW~?{{)M)peyJEqsFeW%8IU*)f~8MN{U?_Ly}m7i>yK{kiIo0g;e72;U6JC#em#I ze{&c$KT1b}n%AibKGAQe+(bwI6P$^wgm2BU=0$gs${bLUoQM9kAK_4F_4DxVE6fRY zO*f$~flWR)|A}()Uh^|Q#FJzsf4XX)`c6D=#w0i4)|hlJD|Zc<_|nr=@YJwT2QkVb<7mFK^;OZd1M2Qq^xYgy_pkvO{Q%Px6%2zve~$hZp(Ov^8CQ zCx3$0Z*`1)_2zIdE1%l`@Lp3)D0LOagy)2YaB7SR|C+vjD=WW=&ksN8jcN%h0qXDx zLcAz;1gDE|=&tcE53V`{UqQ%kLQPMip-?BB=vn`X+8$gJ-t}{GpZFd=-2p8Ma1aios=3B#S?uVGQYw}J{l9pte z@UP{dJ6+`G58U)#he9FL|A`;HdBEzc_NA7F0|ntwEspjap2UUTCz!RH?i2U~LeCOV zQ{kG*pKxl|p}Z3;@|(n?rn;Gi+%>oQS!3(h`AsMZuckYssKc6+*B%&j)mXK=JcwoO z=MQ2-e)<5r*3Tqvu7Z}}LI0a|QDcza2&cZ+VNiJHAitA~Xz59Ra@B6SzwvuR18->H z4Gp}Zfj2bph6diyz#AHPLj!MU;0+DDp@BCv@P-E7(7+oSctZnkXy6SEyrF?NH1LK7 z-q67R-!wq$NlMIvOy)?!fm>IzB$Ig(nrW%$UuqZ4w~$|b(Tqwxt3ptZKl#@O*1=0b$AiC2|YbM-h9P>0yhU3^rSysKkTmOd)z@BUFBci zghSZnP0|~LG2vA6BaTEz&$4pWTxuv`*SC~kgIcm^x66wBDDr7#z!@m_~dZ>pjr>N*U1)|_e=g+Q)} zZ|(l!@Cn0JIQ6~8p;**cJ&PHuG_GSuaLNO$LFpbUJy<+rML|9!cfi}^KY1rg@~!D9 zJc1CccF~=rqdUc${79Y}YG04n_!3V`t2|!YTP>9|MX6N1aq(7Cmcf+i#kT+Cai!zt>CQR4(W)#j*YMU z$lp}18afHJhSS?5+!F4?x7uBECkzQcDj8&zo)Qqk&{fQ9si)#Gp62ZkD_DbqBCXe26#w>Ail^y_RB< zJ8DSHvHtc+ev&d)_k0ldP~`zvr8oH=YKE}m>kxuZxKYUUyQ!ogpAryXVbGheWV3(~ z237!!QT7nBDKE`rGeyhB=Y)oLL?-SbERo~44ltT3Q*SeTMYl=F=iJLGF{cG3ZJGG)+ z<*#4IDrw)q>u)t5qNx8A(+Nj%y90?RmN&Z(r6B0UkKE>mC~9BIE0Z`A?u3S15%}RI z*d%7;XDZA?j>LT;74f+Fnn-;p!OaljQPWPK6G;7ZmG2Mx9de(*2~y)vTsMbS>%jqs zVnuQC)jd=YiVyjb@8Q={>m>k^Zo(pI2(SJhhEdbkF*(eOWhHyf`A|~gaCi}X0wI^L z(pdwehEvHgao_wrw zb~lAc7)0aor?eo6=^pT;KV77O02uiZCTWMRh<^Dr)74=R<<0*Z{}7}0o4ntQJMnQ{$Ju-KQzn;LHpTx_LBkC^z8!yY(BJF@A7 zQiP3Na1GLCXiy7)xKKC&8m2fo?Czr&3vl4T06*p-4}~0%po84*4ZlEICj^O&V8c<9#XGaYan0;t3>LMG}tW+TLTJ~BO`Vui-rNd z#k(FC;G41An0tk4kt5qyZNgR}}9NLCIS4LK-f3g8px2v{C_#Lr+~Cg=d;NJBs>zPy<#dfS8) z2-kye0lDk6E$}4H89O8`Xau;kMyQ|~m=uBqJqJdKcom2#XAF{=Dh3vqyg_k_xEx|c zT!^;;FGvD=DX}4%x#3}1D`2;9LOPm;Y6a+9H$;Oqk=H@1nxu7ye*~ScLN?d~Z^s7q z&=_oH#XW^H0s|~(m9SMnnnN66lZjTTi`6Ha#1a3;pPjRt84ed)%*g^?s+DDzx*EizI;W$s;omVc>$ZVVOOn&tMZb(q%H)evH|;<3U+i$*yGBuFq2_D z+{1QfI&R+~9w_IsP)AiSUoD?gPZdw{Z}88>?}#Vl6Xv;il{fT2%$Rw7TRf9s+f&T( zsk|FnXh4YKsOFKE)1jFuzr$u9O0f>?JHVnITjr

I68JBcFTrQq2za1XIIWeEY$sUi`C+u_VT57;-%^Ew~lU$TEHzo8#dPrK)f71I^V#j*0ZzQ^3DP8sM<4)`cu zDbCBQ{9KXjE9J#|mo?&Wa=An7_rH z;CI;fN*RyqGmi6)yyza`f2$sjU$=kCA57mh&%~52>xMaIZV5~AR&i%OBNk;Zbo{=^ z>|A-lp2t~E=ha2FV)i)flEg)^ESHOu$T!Er5j9ivY&SL|lZ^!1OA1!>`FvO`j)ddt zq+WJ!iV`tej3;!PkK+sMJMN+IJ^mH`dHc;Gx|ij7Scz$}ll*vEvS-=Zd@9VzcG+P2 z{07b?y5wIIm-xkem2bweZ^%AhOiSr_d6XZGOJRY}lzrYa$l(sQ<6@6;bexw*%tCR@ z9ree+_kQ=TxFC;5*ceKe*pvF9{7Cs7@x}D@_-*~XJnt@vEk0vUM4pbt6UFJ`xP%Sf z04pA_hJ1xzwpY^?eHqp+b`^9h`gzVRn#GLs8wz|0VLHP~U>d-F04yk)sRHL0$k{v{ zVP6{-Cb&Mr-WuN(=FCw)V6!Hh7unyXr}Pu$SLD~tx7c&+6@N}%i7mIpX7qwvN~iTL z#aw~&h;>J9+7)#r-7q)U<$OtO!0G@jfT^zI8K>t&vaor);BhWYd(P)F&VMNfY}(_g zdVD_2xp_5LER@2%pPe)dnk!h;6c_WO_VM&0|J(32`wbgm0r(~PN`N(=2uuBOwmh!R z#-k2aUyE7MP`hTuuiA|wmsi|XzEQ$rW-(Ij0_QQsIkn)9iRE;R!~U(pnNg|7$?6_# z_4!unmNOA&0N7bItC#Hk<~BKFkGqzfaw{gu$M|c-_teA1x7c^W3+_en61yN#V!>Jv z?7WIw;hrMdEq&Px?b${Lt zIIoVw(xM#%*c!L6z@DbnoE7G7SX(&iTX8mRy6gN&`C5LCKURLveV0AQQ}Ht7+F;|d zrMpE}F1lj|C;aevIi03N!|e&!&Nmx=rChVCYFllTJ8D0)W8ZK=mTgZ$8%S}Bv#MYV zW?J+;Z0fpB*)W|1%a3uu`gS^W)v|tbn9U2Rn|iXzH{=WAwRk>0ZJx&IWVWIPA-_soXH#)XF`Scm32E#{JyRu$7z!aSAfb@Da=zG1dc=60mp;J#^w!Vyy3H!zn%BusI((rolJE#dtYgDbC@9vZrBT z_Ix-W&WWpXBaS@Pi2XS4=25owcrOlAOThv;+bhQ9PO%ks@))hWX3<72z?npdFLyI} z(adpJ`i9i=d>}gtxgm6Uv&1=AW!v{sGfWi?)8h@^360{2oGzQL6JbR`?1r`CBEKOo z+Vk-h{bIP_E~LxsvcSnfiZt3ry27%ngZ)X}C}FuJ;mq8)&qjXahYmJ0Ow*w>jB_4m z>hWG&D%&Wpns(ZCBR2yz!(M2f=3o;Sb@>oN{#->3{>YHg;w8Y4b6YO80 z&Ap$78LbhvgR)^$;;ae1?pE`f*)kh(yTF+Vex!HBQ0+sL`^YJ<4-;Tj#Ww_OiK(V- zO0-K5^PX;nen4wNObL7=1#HQQ${wuh=s||fI{`bIx@FPU*JwM5MnpT;BAx>6AGCGQ zHVUI+EMWW3jycXqwtE?;CkvcJ5pgOe$63!DXLp!gzRUI^EOl9&h+tufN5IyhXAJEw z4~;2U-Yi;E!s+~D|-fR*Kw!~W2fv|+&L_$nigVEwcZq3UJk9e08SR| zE`zkNuwCeJ3Pyl^)&kb~+(^L+7{hys_M3pMeUA1VhZWI0WFrmiG?I|YK&~+6u-3@Y z;UM%{*N9p!z(#89$S&{dj<4*w0t-1NLx#Z8!9{M3yigz)IO>D# zlfER*a!w--Yje5^E5T+XzMHXu>>ijLR|JHEMuXmhThU0U+sj5mk13%S;TjBAiKlFa zrhwLpmTsArYK3NOB1N0J$q(cqDPkp81gA<%;L4CY1zP6;Qt2v8hxn_pha?)X2x$ax zScT*9p3xhn_ki|oLfUJzuPyj;NP%w$DZm>UQX0H@q>O}w9<6By9EmnEYpNzv8hsZ5 zJP#;Rp0P&2-9pah$x62Gb(jL zQc!9!(j=e~+DH{|3b&*Zv%(dC5f_bk8pvM4Hd6pLM;WD?&`srAOCBqUGAkj!1w}@B zI8ZUrdq5*D-6#+@158il&6NYuYLXpd!gg+KhCj zl$KRUgfAgi!ker3*YZ)!$VGQwxg^qr@>7X7hj>v=;|J+au>bc(9Em4MP)k9SM4MTG z)MQ8vsjIgkANuIAi7&Dh z(89{lAv6md-*kvC@(sTF*bq2@+js4D*oo~t(p{txoel*FBYM;kVJ28~Do{6o?L9UYVr|h8j@*P{VB#pJB&4KHkGjO z=bCXhAU9FoFFR)Fnu1DiNR6viB0Sj=EVTvtqLO5Sohl2POco4O9NxQ5tKQ+(`O4)*+Po1;86Z99%#w-cId z*S1uH4Rf!A9b_@~@In5C)#Ka-cFW;JfkYN%dy--SjdIk-5z>1|D2KY~(eF>Notj4_ zW6)n@t{Fhh@%^y2fE6W<@5kb6Enw#t=>uEL;NQ|n7f3zeuuJBUUK$ox9n<>>mVYJc zUEZ)G;Ev)LzBoa)8(Y|P9#v0|ScuAh)SIu?zYPjKW)~&{Q6M4~}3CGYDn@fvfitX|(XaH6=p``&o zZkN?jds^MY{%iYB?cM2=xi8EWSL3JEC*tS$SJJPG|G=YMWw6KcI{6pl^~UQ+vc#a@rA$PK8+(cAu5{+RmlaN4ju5+N9zLG#bkH{E0M zY2^Q(X8&9G75k(4m_LQQ@-_W`iC>L>Rz7ULZ(p`&%+K48x}UZ0llK>IPJ8?z_ebFi z;z9qgdDf58J@W5?>${KwZ{bto27kdPdC6WE>#iN|&=2r;sGq7rerFuoub8ihU*iZl z{HnTaZejPjpJe|-{#fykR9C-l4cJM07MpM_F9 zT71&{Vf=jfUGvZFzl@KUKWG1|_)ag&4=Yukj9=x(TK7fy8S@v#6Hf4dRF=ih#`oJ( zX~CW6f5kqjKViS3Uo=DH!gtD#s=puJEtl*T`Yw;*%-hG=H9t^q4uyEP{{VZyy-DCq z57$rgh}DO10`J$&AFIEypH6?Ef8AXwKEkB^QF}YTPrWI1^cTv1DL&~RN{{Q8%1!-N z^$+7O#dqkl66av&XUv20&)w(jE3(IK=kI0zS@{9=c5|$_mS2p|s;BaWa;O&dJ;gi1 zJHlJl+w2{Bn(etAob~)M_qOm<{Ey|=<-_sM)UTS~3UlFC(vO=5+_CfkP7>Wzzs^ni zjD9@78eWkd^+EnC?!OGD#lT+;5jy;2bm7~k6Yn&IeV=+q_@KXCUMn9J&&Ue~r(zc~ z_IC5W@J@c8y)~W9M+(?H=Kmyr%uKnz4!@c`^a z{9=U7=+rT1?2qX87WW#QGNcxGFShxAhnU`(zsdhq{+#+!{H*#-`FU5^|H=G(dW%?4 z%e*h1DE^K9Km1qq<+AM?^49nv_6zL&yl zKE6=iD92{j9v5fDef}POk3Smca*v&%TpV}vpSh3wFZ(}9zb$@EJQ;o|{Ex*?XQA&9 zr_y%*3^(rA%E#iWfgRcWF7{FWi{W1TxO@aBzC0N}B_1rU+0*R3<}LO#PDy>M?Ae#& z^Zr`e7j4VR8GomG0A;`#y(nhIf1W>psUXslOI~VV}VIbBvb8+4r5l1ZYU_|Y&_A**I0i#I{<9gwwokyMbkMQ;1>z`KN zaj&s2soy~A#VqW5)U9zzz1_akbkk!vk@#VSFPT4^uZNTVZg#4ek6g~$y>tm96I*dr zUllnu`J$OYUEecD@*LmKJFekymQ#Y|<~$`9;t|f%z};g1vHf4vLU=x2XS?dJ%x}8S zrwan-$jL4{Ztl-_6}u^g3-*eCfk*yQh80kOR)CrdN0IhpwI$J?Rl`jE*=@mO+Ybe! zkptIJ?cDc0*^Z6W4j5+>82@z`?^8?ZBl2fiC$1Ll&|=@_f1&?QTtSO})vn9g@=ft5 zzUQ6XPGkRCe#u<7o8?xqf}Dyocnaiphx0R4Ghj?5b$#2y_Ik<6vED9rSd(L%HMU(} z_IXD&%C4L-gR&hu45L%F$)>|S<-KV}jeJ|S>;?Nwan7x$Rd!Xad0?x3w-=f0FqSvj zjzP?db+xI`LX)F3RygHDVwS|Ub333N?3x8eF*P$gcHg)2E;NDhvy65YT3aoN6HQc` zcO3fZ68+)WVyyzb<=o<(q8-tvksaHP`{hue9m#j?28VT3i&Inlo}}>zw96FQ;m9ZZ z3hg*P*3|1luU9iiy+O3!CECRXy#a^bfJ4i)XqD(isa9;3%?KF?9)KAcw1zfeiOaxE zS707)4_5{^YJED~9p=n9Xari5tWjeTrUQ?JXNkYXoufVOs1F4mxX^n<+T&f|O*3+9 za4m4BuqaH4e?+JTbol@l;I`lxai_2X?ubW)PY|Ni_!Ir)-5_*=)4jygzwUR4QB%-; zLQ5QOh917vR1`y!h5nQK;gev*p~jg!C%7K)`tJ{@YafaoxnlM7;1CbEP@IWN{Vxyj zC=|L(1t*OERQ{ST;SlHg%~vkMCJoY^p5=k74#8DC$%l9!K5PDmq165poSJ`)U&}I~ zG*#GyM>&F?6KN*lO{gejy6X3vIo4DYydQpQ;MX)nU-K+09yOG(UG<;%*Ut$TlCRDo zlrlBV&6E?jdEJllcZq!K(aVy6QhWkn3I9-qOyN)H>ToEG351^XHhI<wx@;EBz016}czZAzy;joF;LjcUNhP;I0av zU<5t9lZ&7=J^AUDqSYAVf=2N$k`gfD5*sB-d@A_~7j8f`<;_OfK%Ld7W8^>$cO#)z zFb$7%cNM;`xOr)2|s|+fGcq)m4fazQK8XA%($vp6&pG9v7l z@Rx~zBOG@48$S5M#C(DsF)<%(k1?Ln7NSO13#pYOkQ7CVOE-FB7kfo5U29eqGAq}Y zZ}IQko3FDN(qG`Hhq(7)IXE~t*bfeHhwcFPIoV%usn zZn1m*HoJ?jRowQ_-_TnTUwBtr8ee&5yM9mYo4rV14+Je}p^$h+>}vZ(w^$AMQW%tj z)R&;ac73<%1$^O-V=n9$1s^)M|4XuMRcgv3tb%N3$)QCBm*Ny^p*>WEy8r}=a4r}C#UXTR>h zt-izG(kZ?luE}gV?u6#xSQ)KWNLCLVu#h>J44T0*uj+pHt7r)5!-!(ute3yDgyYkIaH5XbRy)vWS0cOiY& z{XGAu+RERmzHGm)-^_1?RN{LD&C)^ra zHrQzogE)+$~VhP>XN?1-(&CT zYjMjKX~Csd!F9V*z;aC5Up{V0Du4 zrM5_UU(Un4DEqFH3Wt6#!m-Bi1wEcqmWqtuN%0JBi zF8{H)$Tl3lwQ8}yAJ4_M+|Y08H`KfOlDksfsP3^@;OtafH$%(Zez+g*#5-aqO!WZk z(Z|%|O31$2O}EVrwT&LQFNS$lt(moQId?d|JOFB1p>X&PSL%tOhjvS~7J0R#dZ{ps zb@;k`oIfum`-k?dy;AwF+)VwZ2FyF8-@n7O5J+C8ct^{4d-Mc-<=%HP*FOF;Y6{)ApFhi0HV9N*f}hrrse zsGsbiM9=c`c^$nLcJU>4^{Wo*=;P`I^-K1b(z1Fp{d@iILI}xbj(vQ7(m(0W)d=Mnnt95$+ZYM-|__vgZ6@o|3I4>1B{eD4_gJ8~A* z;#qe(uJI)cDS#Ux){J-AqUzgLXy+w%5)!hLdEmPOqh}&X|2lg{{e=Ig;#1J(_#^Xw z`U+Crdz!w*wk#hN7t(^e109u@<3)W%U-!4d7Mp3V&M16CInL}Zdd_?7Zn^DHdhs-S zEIo!4c<81Xzay@s>*Y3T(W&aJIGuQ0NVEfwb+=;}zn09R>ahjCRPt(_ucd*aKD{p% z#lWvuPrEOwUr^^%s{WJxkLK&;WxJ^kcw2M(cslE5=1PkBReVGBdc4W*qMdd434hA1 zm~K3@yVd=eRc3pZrDaH?9#x=94ABGJiyz1v>VC!IN;-)#VO_4op2hbo6(o<5>As>K zbs ztJk3~f^UYayLMD9np6CwTXeuLchaV~r|yM)+2L#99DmfEGp7T1qVBt^@p8Bwr)C&V zRQP7FSrY?Ql+g2G`wm|%;uzucLR`wriF(OZw^Vj38k3g8Iq@9(MfG3vCH^L4$-f!C z6K+V9UO9~C^GD1Xzg@oNUU5I9`lPR>+j%6G;wirt`>wDPvuC%;jeNV>3mw0z&+zl? zoPw@l=!zY2qrC3#nnT-FX!G%8S`SO2i2G_!Vsw^m^yScR@L zN@pOc{#ElimE~WUU(bIk-$f5_L(cS>>Y4Dg?V8Kg8|W|3s8-dPbXKfsl(*ki&XK47?X*sSAs)LgG9tWRtKQH*jJoGDQCqpr)I(#`n z!sSo1$K^-(Cp_oZ)A!tW(o6b>=8C4LHJsL`*wA$>G*|`l6ZaVAZs?2pcG321Q9>IikMx8=8_6wbjAEi+c1@vC%`~k*I=N>s%4v-Md=cYa z&vsC!+7+$SI=&|d61sjB7d&A;>Xzjx`$&E!epa2WHsufPtLkMH#p~v(pP~HL%0cRS zX7<<(`!;_oUiLTrowTiHc92&hzUgh+oW4!Gqwee7c&OTHDAxFTb&}(&)@tkz;>aD! zsbOWGFPAH97zfqB_EXDDK9t;u^3(dWu`g~xgZU!= zzWyuslDjUtZW(>ZVg>C)v^Z!G%lE^Tc!^!J=nd_nS@J`*B%r64piSj4A9o|!s`_bY zG0M3?)ypjp&GtCW*fFkpvF8`6C5G8v#2O^G3|3kOGf<9Mdc-W#t*B))Wb2B%#dsor z&i#FLlHZY6^X2q1|7!W4-8*`QRA+inolz%IPB+x$bVXiGZ~7m)+ZLaRgkay|F3 zCd1cx^}gFN6M=OBa?mf4bIc2{Qo+-%u=>j_2YsZ_$bU$%dszZ_nXH^RQZRkhg@{xRNX2YTYR z<+bt$_7#3vZTJnnsaxfV$kUJw{c?mRUp&zJY0vCHKXnAIpr_(%{**i=xL@@6qP1!% zNFBgitXy<248&@MS*}|_juv=ZW5tEk`rzZTd{%u?z3AKJmYS%W;v4Lb-1p>Vdn;eJ zSr5c{H`EhI&0Av6UPWEHgdN+PMbd@t?DvFo_SyvWxg zbfyg#&`&NGZMST>B6d{Avy@-FxQ6~=)fN5NlF%%%s4Zbxthm*PJ8*3{d2NA6?&G3F!8uf`5va&`M+gt22B#tG}v3UZf(Cqq*-L84H0Bw9A_ z+g`v*QDPqE7vmy>wr}qHexNmGPlEQ?m0baT>W=9c=u5^{hWrOPf_|N+(-zqAOb69o z-Yxh1uHB8h3X+Am=OAy4oi=v{O-p$>(%#_HY@B;a|QVU=rJ3No(*`BK1GVxZRp?n8b=Qa(Fn&~>zs z@|X$gBeWh9WIcLXLKDg1?WO^ou#l(;#N`-`4ABC7nMJI#T+2XCXP`l=pxYRr@hBkO zazzO{gCq>SViA$9t7TLk@nfB{h}OHlsHmgfCV)4^&C=+NKYef$r9cU zcEXgf?z1&53h6h^f1f_PNbse&r} zQ(g_ADNS;fu#+JSgkO^jw92FOImsd^6{JkGB)AB(0)zo<$wZ;xjz~ozgbYzhymCm( zA`XS6qfq1=ArUa42sJGhF)|?Lkh->!uSaS`RRI2sH~Bg6Qvw@7JCq?&OgWBqJ~L9G zG*wZej#8=yHUU$CN~F<}NLwIf4+g@}S>&3xh~5Abfit1iR7W%eGo@c-YGsg0tCj#Ixu(Pbb2)`Cc6bJqoBR z7X4TSeaeJ#A-~`I^p@yx z{1J57N_D;y%gBLl3A7(zhaA!ae@XO!kGzP;H3LMV2c;_U6-$TE3NC^{u37;xC>Eee zMh8Fi%q@%3VUWH@U?B_)dYcNEJw{Fq4MznnQ{LocDqE-}GtdW&7Ucu}Aa@?Uxp>r8;Gm3Zm4HqvM-4!JfzP6h6i&bjd?S}=576wVo--pHseu~g2UH|bl@aQ& z6V72YLLEYRLAYR_mf)Vnw?!?=%^{YfZ(pKJBOobn0Ts_oxAp@FHE0 z{TakYX;@%M_~!-q4PIAxOZb74bsP?Oz`^do8IRDig&0KurV73WkB0UwppeIe5vc+u z1%HWfUSwdC;0;k0;h*a~a`4WhPJ6(Vz~t~K)b0R!QVk7iVJwVCsHHZWCBmt! zC?>@rY=oca@SvFJkKi!jam2?Oj__7g6JQwfM{y}0y#+yI%;w+#tJ8~!rwfCY;Oly- z5sUH{5hLLtPEwBYEEW~qRI@es2)-AI(ntMK@P`|zfr~X=3_g?|K@fEsDXZG9Ye>pz zL`cTJskv6cMlmRjT-(S_Tp<4vk3>2iMidnwWFEwPTSnXYhD zU{E$Re{1EI!@4UM2J@y!9B*aRbMOEyE)~3`5aQ8dEK0P(BVo(vExj-qlJIDhl3}WiaxN0mP_43+I$O{ge24xm| zW*&XJLK!5`qrrz%w=htT^fhLr7)xe;T8#~6s7US5k0e%gavyJ;Ad=9;;^RCH&=o>W z=~Nw!vpsff+p#0C-t}0SN9+xzMX|2>tP>6@%(Wr0S#&E{v#q98xmLokb$OCsaF6j* zu8Z~Eo8i0Sd;U##rMm6zrYttaG%cFb?1DHWhZ=Gfd)I8bEqUK>rj2;d?FObGF?8p! zwp`|2RbZ|=)}s&Hx+`Yp ztoVq39umAqJU4x;Wp@0Ax@_JrKj1meO3u#-$i$$3d5)i!tFjj+VyE27+Z?AN;=pl* zv*gud@k#M<^#%2F>^bD>b^E3K>-kGAnAfWJ?6q*;t;MIsPo|$@&zGmgL3usCYu{!U z(<}D1^uut|xAmFyZ25fk5phAC$tV0`8Y`UX&e6WEuK3-m$4~Hc;N%nH33ef#jQwz^ z@4H-WmV5C4H1_3+I0s4l1$QAnZ9l31zWQ;y?l#>Yr{7?|r~h2Nq+Ye}r>n6DPqWYG zpH!dr>%5&e`8@~SL!2W1rh2)$D#q@FKj$8mkNU^$)9T4^*0tpw{;qhPy`?Ufw=_=1 zrzLmZe}q3*iRyHKTw6dI&-X%Rne8eTmq9%w!1i2tlD{Z_sr(1}q~6ot2w&lWf4llC z`4`nU&D&z+pH(kbpVZGHCnxv`yQri zIB(^oFP1+jFF}q{$W^l*PRqxTUm?yhK%^1dhr|i|kYm~MLvezg)#uYw@x}OGl|Pnv z*fFn}m(^?WW${h_N8(%dZM}n&BB3vr zu~Ygi{~7W5xTZULv%JGT@b89~-B;aT#viI{a?c;AnOI<_IBp4WCn2{e7*pebn#eEP zEAnQ%CvYwl{Z}_*Ur3(yC*(5ghmI=3L}LF-@92F$MlS_92*Y_|f&Eai?66OoA^%9- zjQ%3Fd?zg!I??)+|5)O=BPV8L?)#gl1&}@ZcjGm;0l7zxV_j(MUby8ri2ZWWFR&Jy zs{Op}cg&96m3Yjd!^vK@z<^)(16JC)XF638(DS1oE*$zq3wey|t62W zPR2gBuJ`;IR>Zm&m)yEq7S zVvfE(&@3C{nkXXX3=I8iz*rJ$6EUU)Xn3%xo~W_J2~9t;qY6@(1fvhphQ<;nIR$94 z=+gzL<-k;-uNE~Wob(^?DD>nGk7`T2OZ*GyekM@ish_7Yr|#K3(lr>D$aolsaRMBm zaSHwxM!`=qMzaUZ3mL|ej4=-5D{0!)kH#7Vbq6Ca`Bq1BQi2nRYk^DSpKJj&2qPOt z6%C3r#+M9!M3{s;5N9gPy)j~9yyGwuc`J*=8dKrlgI7dn1$^}HYs_R1M>bdIhv>HT z{KOx*i2{ko)NmH>=An0ksd?KY+yp-lAsDh(M?OthgTeg>e3RR<<{rgpAY~n|!D2yy zKJstEiOXd3^}h$z5jX>$=AZILu5=Va;qfRu!j}~d9|ABCjRZ@$8k!p_$fvdy89SeP z5AySg$EkeX2UnoigSe=p$P2WLP`WGw-qgGzdP>xIKdMMR)wX?%)GX|}JvWPx6l1ov zop&oH7xbcPWtx>^9zmRPm<1)wViQW%bvTQoxK|z;=z;JS)!xu@y@ZrB@}S!a^96y~ zg@aE(NudOb#B5vFE5xdZSaC?qYRa){l~d97hZ?&OvgIbSBc}n6N4*u0(^_iHz{A@L zbFw()t&Eu)W-o2z2&b#dLP5@&N2!%2yvMLA^K@o!np!1zsitM2yAgQ@4O381R4C0r zv&gO($8OjcT`?ZdSZu=1}fpdX=6uTT0dgP7)1IiQm((N>f%;9dNJdra~ zq={#oPM{xBZwC9JL4Hk}wLBANr@Fdj&P!T5%YmGduaJtYhvAv8FiM$@% zi5h0H5=huTk!ZycCu2S8a$>$4TL!hZMEgopJ}Fy#lsv>K?TaZRZfVDC`1y0kmfgc!v<=x}(Q(sGyDD4t-xA zW}InosMBSaj}uywCd@6e$^%-S{Crx!P z&2le7ud$@@hbhc7Q2#m{IMvKhI95_-l5ieXcBsr0&fW^fz>|d9sZjEwD@k(_`3;zZ zDV&rI;2P_cGtt+`Lp6ze8KncfXb}=UOw~$QbNF3}wUg@zXgA3N@UkNgJ=&K-4-(N= z#*W-~1)u14*>Yo#Hto=E8DA08`+CPx1*Q*u4}8AZF|O$3x`^TRM9&t+)-i*hJA25H9a+BEe-xjlpF(1 zeCAtm%8)*|KQon@e%XGe`Eg%7lQ&o7h zm#Sj{YbPiHj17i)@C|jY!^XA~W(qVj^bfjQfA(G({~y zEm5F`T9n5wamE>Db{INoEZUO!wnIO_(PA0S_6peZVa7@42pTQ%Y@!M_3xMR%2H@yN z0~6FQqBl_(|2QziXOfx0j;^0%?A@fPMn8c$7)s2c%mngc(1uu{Acs_Narkp^P@xZJ zho)muN)fr?s51&Zwn0wgEVabc0Ftm|@XmlDRgcK{hcDofCrz3Z$Rjv_(WR!Xl`-Og zsQnjujGB5JY)Z;`jQWhm9DXB?DA zlo^BEsw_fF13&PhuG@kG5-C8^lMp+>UV&PNdd*u7selU@Ja2#|HbVPg&>L%jNgux8+OK zOYz%&PdzC=!+tit$j_jSwNYxD`cC<6^=HtoeH(q{I#%B&-I?$a|E&JBdS0zn`{lI? zXA1c(eGNKN&}>SB@H8*^$KvDmBwy5h-*Kaq^(}eZ?W7K*Hm9I#c3PZbr`!|ni{*cp z%Ib;gqW*RHAFAIoUxS{`_tP8pqC1^l&_5ghp)S*M+Vl7HO|085Mx4HNf1NJHt`_cj zoKY9zBkT$OiSR@ol|KxB=DrfXRb8$|x-jeRWF^82@>9?dKCKG2#qZc{d!OxF?4YtX zU$Kw!Pw1a_|7%k0$930y#r+1KbKjvT6-`C$^6ZHxGGwGl4Ur^7RReK<|)w|&> ztd@T_{5gAx-}5Kpb2#bvQT7S`eEE^;8MdDG?6ve7|GN2F^-}q^+A-_?Y5#)z@$ysn zKN|+@z}(jxp%F=&^eJn!%B5nE);tiGkP98HFO%}tWm8||}YpS2qPn)QIJN&=# z5As*zpQ*3O{~W&?I{6b!>3`;aIz5A$#n?f0mtD)>;eVL^D13uoj~yq#->1^k{GIG;&cgw5sJN9epTl|OB9eKd}ZpEH=&%{rr7vj_5gl$>q&~x0l1gXt_9#@55h3xE? z^Z%%RrTWRLr@yCum;XNU@b&m-?(6QW`Asup&#RxYzfk>ndb-4&OKPI`(=GFQ`U~~d z_?PK@d5~BA`SeKjsC+^{XFeXE^s8n&z7t+iukloE_`MRNPB~0x-P7)4@fn=<9oUK9 z<E{(1G&sWU;?^V1h>A9PvIBn0zg4}e-Z07Emqi}fRkj8h+9`k5pW&;bWA<@g;ZB+PZW^(f zEqqrG*@<{2oT;F3q84KZeMG11#X&kJUeJG+f2Mj$x7B6-J@wb>`}Vc`dVIr1_d|cn zwjkwtPCe%zk81%M!KNDvKY|X)`|K_8Hvd51x6=x@h540=+Y|0gb*kcOAx$05ju`0C zWt_~=n6Zh0geHoC)U8~#1GAu^ZKa{lSv{wIEPc*DqlfOcdX0TIeqX<8-zeX3uktta z6}}&q)#LeTd%>N8q;cRDY|k^a=WErw)!QoB+ZFDc11F(nl2+L%dpe$Q%f3@h6trT~ zzQR`=##lQ&p%mx)_z=_uV&$@ea*hkFP3kXKj5!cFI7KqH>zp5 zEYCm|dcyH)EuV1fcBv}L`{_n`O-3MEAR5V`L5m2cT|?!7Pp#Z=tIk)hGw8!;W!TvF$cyR0OKXc zN;S6?X(liGWwk1K#oc;75l*V}>;;^5e#|e%9d#|fmEQO7#Wze8FY{O9d+`pNrGoYJ zqNdwbakGkFlRXBVL%*l@-L~6c*WC?s+iv-hYlWU2Skylc{Yt+ohb8onOjkn^m)aas zKi6|~6Y4U@Idrk+xmpL$KboFoCsRxA%3C>!OYE&G^6$%6`CI-9zms>>h%>dQ*TkuK zLado3lxj;ccPMsCoN{qnY+Kw{JN7`&WH&>f(k=7lv;=wLz%M48c|xB1C8UqlLS7Wm zPqfPlw@Iee3b#$7?m=JD33ee5_Z=~z~2IRjN!$tKTzggy#)wVvsjAKFJhC$nN z(B`RHC069(Fzl;?xUX@}CqW;`%{cg5^?gq-C>Vow<&ka)Jw1&%fm?8k6cS+E0$XCx zx#SB9XR%_(W7owE5Erv;xv#cejvMNBz7cL#xA-k{Tik&JbQ>$P!xB#=3b`c%eZByWXxw)g==2jPk^Qo(+aCJp6?kHxrJ68P zk5Fk_Si2rCJc~HPBl;OLLQg01+n^tF zO5TZ(L?x`;^S<3Ju^wY%y;tIP#(a=RaVKq~=Q}7Ng${d2?ofgQ5wda90py;VreS7r zjL{YP$-3o=T-Xjue#v2-Q=JJbfL_*@?;z&}RF`#BM{qkuUo|u>P_UC(?vw*y zyk|i#!#xZd>wuD>4DLBdkx~)1IFr3F4d~%Q*JJHh;v8JL=%Ll=?^%}C-8RY-l7Tp^ zaAraE5=IR>4LiCBJl_p_c9`0x$94p0sV1(ElH7}@^hn;71HH|=e5Q8z3g6Q$HQ=|) zlVK`0_)^&xcioUp{JvQ5*ymGIgL%B%3aClwlhy?b_w0(BnEPzCx?5qjSKd=Yj@usH ziry+0_@SAZ6|@`1dAZ@%(R1W*+Rc16C(=QNZk*XkYvrzOg_G`DK82FJ%TC+9lKB<1 zh)3i7I17*ZOa6@Lhy=ofH<&6GioHygy2>rQgS?^SfYRTP7?YQLk zZC`AqNBnM>q|-6W0(IlA?#iK=#x~nA!>V0vCa(4w^Q-9HI%P){d^KG6XZ2WZu}8%X zds;2ATiC7JR(&?)xAhZxt18esx7}*FAG>xzY^l?EmmkPsY(cwr$Zx6jJd@jw^GQ4z zx6n$KP*!cbCEIB+@7je#ny3SDn-3W6LM+(Zo`(%Luq?rJ_ zFWOD}47%>B#c#(`Wy@tgWV@DC2dIf-cTYT)u2&Oz%G}myIUahdX3s#9==S|0-;G1G z)GO*ydoQopr94(We=DAsEZ&x9Ba8dGqqp6P#QhW)4e#@T@A=E@bi_!_hv8baS{Hqx;=24yzTuf& zaAVzOyX*wtwuM@A@B1~~%6Hro`cNFkQ|gw*iZ3oGR^EtD$~$o)&Zr;wN2^86(8IlN zpI~>{KJNa0KMv8$-E(WMBXKjW&q#S!?C^8qrdoBKnB6IH3A@CFx)~qSQ&78H-a$!Y z{D`Y!1HI;oem6WFi@4>vyQa^miQjRj^L4qZ3VYQ&neK#^TkyB_sj2{X`)ZNjm(Ygy zE8=E&Jhx)PXwu?0)XB8t`_#u7tWtTqWM;cs^*ga8mQb1t;t_Stb<(oD=X!hred>N# zjWdV+weWb{5?A9BX)(N`&+{U_&rgX3aSs@<%Za=%s+rs1Co+roL|;LgrvS`*ho&bWs}p0!1Z zwqj^8g@K$WW5s3DN|M(af|=D?#FtS{zcrz!Kw-ZpapE zGx&yfZhOe-GGw)EmY{>7#uBo|067CE`RxSlk^Vttg|!O)+p?_+RhUlIHQ3=0Esykc zD|P*XUx<)2m=or#e+|%ZQJ>!?Fp6<9pOwsc}QpRyQJLCKkdnSB5 ze#ZYJ_TQRM_-*%QmD0uX5B0x~zsCQhd^_bZQ#c14K9#o?_;{yvkpT--usV zFNe!=+l?_#JI_8QKdU~YJ{r%87UnwF^ji|s^Yos&A6dB)&!XKu%bpd`NQgrNU6_bj zZHYY$HDoWue`)`@I`1!HH~p5sV*f1tj`@!v$SZompXV!VF+RyY?LIBnRt?5Kfp!+_UZ%af{Z!@aM~*f5ZHF{Hpmq_Xp{B>^J${^zrVF^dmAekI&$uL>(w{XyWk0Wjz45AsDDw)8pvta#Q6 z^@uzlFvjwG>T15Kaq<m(vKJUvc3-Foh?n$wbw>{3F zxjnVPZ(uCkHjn^^Wx3$mu@`wb$yXG162f)`ts9Lq5NcqC9Jhp*r}gRbL|QE&6>v*Q zh+pCV1N%w;Zux)M|4sd0@h{Z9s$*EZk1^~y_7mE4xs1s+{IeSX+fYn~2 zete0o$zTh^*tL0ycSNI)T zq2-aA@c}v|4;ty>aX1`h8#GQ zpTQmbWyfvW_w}3NEq^nO1mq(gcMtGE$@Q}6$ODmmR{N|a2i2nNSnM^sLyuXE=$0g9 zU6uof)kC2Em~J$~8Dqc5I}s=EN}Nh@n912;#wj(FR+}%FC*>FA7vidn?l!?I%OYWV~Ij=dueHTE{+p~kovhwP*sqyv`imd46N zVV8lz)w2Yh$I;Wql%3rNZ1)SO!5 zs|qLMJiY=T&g;+nFXprHW$x9N_$%TLA92irOxv~CAg-txByq3m_ri9-S|m&=v=@i@ za9*{&ux)Q=oWph941Jsm0;=?8a<}%kl$IGUB^wQ}6LE>c*<==b1Vz5Bbbs-@;A9frCaI z>d&g{SymOM=lZ&>AwkBhs~w?(uF(oKc7#;lFY!UyR#PzrpE?37&fE$M8fVZvYBs|x zCyq1bG`xd)(szTfs!phrkZwLvo>g1nui_u`mpo?hX|ueqii)#!w_s!2`(~(yalvSRFooY$n`uvDZW=orb90U}$8KOS zzg3w1nt>VkzG+1kaod6Cdc_SqPF==F(uH)wZ26b@cgy$OHd5Tk8*ZxC#hJLwp?{Hg zQA^;TxA~U1&&RQEm(>C%Ot?Qmbo?|PxWkBfr*3;ll6>2AcpseV>H_tWG0f`}b_qRZ zixh4;2^wNmi$m69aH24`(@5Wo_==Hkq3-lhf~d<0U&r7@9#zoN4cM0x9bE)SR7#w( zE4vk>F(vrTFlS0r19_;fwMi2_ZqsBuIqFcU#Lyo|9tMX45LOJN?X zP{tB((?*@?m2Hl8$sjXQEd$?x@^IKiL?qN!i8UW){p(3OAwnZOjddvaK;s5J_HvPd0+JOI-~PZe-xtQr*b^(&NIU}Y)!TXs5C7`aQP#Ur@h?~%>Xq1aW4e=;<5aNw8ot4jfZqWRLudm@(DYPCm@C9p zb=(MSlqS6^JfX%O>$n+En09)_*ih)<4q|xsT$yvNR89(J?ab9n2hxv*)7(y zs1b1KI%SF%5F7OZZw8!APAEsLAP!TGDSgUa zOfhTG#YcuG7D{(>>m7lG~vm3BkBLpvZGROTiAP5qSkrxrrK z3U~zKOJJdLB#iW?wDpHB3tvia{+`>Ywz%4tIF@0je}W|LHMy9-L(LzL(8h;w5anbV zKMHHiJkIgIso^LFrAV$O_w+xvH~7e(d>a3Gm_DM%A_WRJM-WZg9P zNnDvf4d2OKA+D-ZHt5giZeQ07%qt+L5*Yb8M%9EFgoE8FF~mU zl^A8vwi3=4l$bXd@J2xAiKyp=tR)eYUjb+iCfMBVv-q)i`2q%usF&(!>NmiL-LzkRAF%IW|}&IjkEJeHR7i zQsiM6nUTWnKYqmF5{DIi8Rd|T**M|UiieIt!tBdp)=*6p<_{8&M+tk(3j<8VNY84T zV_g>=q_+aO%iw`%m*7L$R&5KOTA0}89o=zQ89B%=ShuR}8ho_yw^$zpaJE9Y#2x@A z?shU_g&G6>moS96LRok`0j1+w67yOM?sD*vfnN!I0)s2U)|iG{4XvDNW8ITeoeg*l zI2yn+RnKe_IIOAW*10tBrFzN1QATwM{;D<+aX9kMP{%@3CU7&f9fPu=r!npUn@61s z^%Fs3WF=|?)eD7rm@O(i9*;%)jIcShZ2=oYZB}(I8MqtKiYwIPi27E-S0S{dnLX;X zt9>2tX<+53KbqGf)f8c-MFwDHMsxv9Zp@dWrMJPsz-Cc)nV-qmr^l;AVkrAK@+gss6WkrG-nYFLGo z6W*z=V*+FB+(_6IjIa9{^dhj^Iu8*&o<>`Ag@%u6Mbre1yqDma1eXJN5fN(e<}D8n zGVqN!idGMQ;(CP`7QC~7QgA0c8NL)IfJp;W!_~4bEh;kuUj=^&2ws;duSu+NnlO*D@DCWuA;FWct8Gmv**$7ptV_?;Vf3EICHt}a zZ?lCOmar2pay4l*@fth%HF3#pKeW$b!jFWLZv!(AC-*$wv7ZCo4SrkO9tsaLDYmPPen>U41eBw2|8`EGUdv)}Xjrb93p9kYqM?MtVU?83~ z_Uc1=8;o(?smXEhiE8>wVUk6aC3;}-+UOO`WrA0Vm{`v{Tpyi%qEvjI!)^H zJk8T4h^pqqu@6zvq%+Sgxf_Zt{+rYqH^I&g#i6icGj~x6RBw+%sP7>c#hJh7&<&J1 zs^jDve*}hnsO0DH72I<}`Dv)2G(+uAX*d3j&DXvZ-o&!CjoghP42_Fy4VET^T#Y+? z2-{$xx2^FtamY=aGPR$p-%WUfgWiqrJgkZFpzj?1LAYakQ*QHAk6~@ifhNC{kK-8g zG@CT&O;D5{%2nfP-aqO)hoJw)5EP}@ya}4@^w9g*9J?rlT=wW`Y~(Y48XJZG?S|m& z5q|R_%p89H-^4w3&1+o~``CY;2Kkd|YEzS+rqqsM$wqjNeHvORUK7LAbeS4cgRKc6 zdYcrQH>J{GY1|DL8o&9Q;y3<3YHQ-ro8mSu`ZqPs2V?uAQ1Uy5YvMIA=-q@6uByh_ z#G3PK9TDa(#@Uf%Qi*o0KWEc}#6Pc2hXH=HbWg2G1Ol zT>c1_V9bZH=J6{)&_kxdLQv!)DjP#CvQ_nesBKMN=5c);gP_P~-WHl1Q>@0!@evmq zTm;{wI)`a+H18&K9x_jZ+_uIzF9-9X&pf2b9YK|t6X|-aBtP>&YV+J4`_3T`4} z7?}q{$UUctLdZ@$p?`vF{>e^$jX(MQsH^%ggt#&fuZ}Pf2OI9iqjou)$o{7 zj&ML8F!bMWi2moXkK>aM`5REy z;Hc{V=BJO^uOalIur}|Ike~dMdn+eXH7cUSlaP(a_*%C?Pwg+~7BL zn62UHeM}A6DJDTah=F|Okc5$9kReQstqG<0a}150-t#bD+X!=o6~@EgLk>LTz(Wo^ zLTz(Wo^LTz(Wo^a?xBmDXSybkszl){>aFcX|P@_8`LdDtA%)btRvKf+586nea`q-#8cjSQtoq4PKS zlONI9*vQpD5e$V?NAPq1CM|+*!smGBu?%8SNaH`pN-m;z9@511HQX`v6z=Po6z)Ha zL3@hxn1sK<-lTBsB447IeCBC2egxT=CT0UO52Jtbq0%7?bN@yYrlDf)N1?ukp|`K$ zo7fc6gw45M{SBW6hTcR?18?eoN}Fu-KM!x*l$SYd^WVH1s5xwtJ9<<6V;9+*hp^1e zF$CqV37@~|zp8WAP{K%|rly)g2&#FA_Qv0S=syo3-ccAC!qV6pXj8kXEE`|KGRN~EJjH6_&fltb zQ=TY{-b4|-8@E4-LGJ3vzbUQbkg86#iAOwX;x;KYDb7p0aW&y&C;ukL8nGx{avz&{ z>^Wr=lMF!`JPnuT@QojZ9k(Td@<(tDwyO4_+>j1HtX-78L= zNpH;8ny=(XzH{>+4A~7HqM&&<)EW3R)YE?xO0W;Y9H-Rqn=mNA5>15D)Hsh*B{#uX zK%mLmNnPQ8>BiJ&#}2_NEmR zCz|{;W!uydUQjK_ctRao;Z4RJxrr`!cl=CL-d8n=9XuO-ab6j(% zc^jwj#xy<@?vK*4M`;i)GSt#3)rJR+54}C=w5k1%=``>)wJ8Cw>Y8d`YhpD%7L&NL z4k_WUj>6{nn;JnhP`kV_lL|^5j?HO`)lFka&H zfT7w!sZgHgJf$#-O+HQ7JiWQQ0zAc_v>$xPMYzb1-UQd!$!%)8Ir7u^KQ>Kn=g{*w z6(H!Lw3>IQ?TxDmqdXDiO^y@bn>^*C95it$2IYw!3JG;6<&hpTgnyn=Oxti8Xv74~@TjCS}nNu`}Kc?@&5D$Em ze|i&S^Ejl`JWURoP_i5N2mDhw`BE%`Y;cghaZ#;NEw>zZ#g;uRaR)limb6*V;dVWZ z6Bn{RCjgy0ocz$hXj;IA(;$keBBGvCZKFO&f#1X>;(et10H+eJ2w0q@fi2*yNr@9o z5iujq`W9K82AKeQ0u#Ve z!A2)apvP5sJPQ5>xh7b`MQK}{9$`o+PU&=w#~F_br|}ux*-G~z!8E2{@PQ9cS$H||vqq~Ogo9jE=_89tnDX+*?+##{dmlD3ZEN{t6 z;T?gmVX4dc2H#4Du4CyA&6R{(E@N z-paeO=MksmVF6qm$sOEoc7-Q6`7B`~zoV&?9YITP1$uLN$Tw+C)l+^;svZF|6( z!PkR8(W+lmMTxWRywE)bUIyIC?K+{SaUZu@Ot`a!uizesfgkdd;+#9{aA!*FuvVOu zJM4B!`t9(pzHG0%jg;N4r>|GwYr(dartFX%#9g*6w$x_aV!QDGRN)&cvJ-o5K`pw4 z)U#cW`y6;X;>?>v9jusbxo+%h+;r(E3@5dCmv=3l=fVw`1~-DnMTeVB;u6O_q}7sI zLakhIUDp!0@yFsGP_bFwtv2FqeY?8NHtZdC&*G-p3|_0TL`&efYb4{oQG>6|+W~Th zyGB*N>^Y=i+ZpxE(wzXfRZPAU$fT}?r9Qt`BvUhBR|0@#FoXkmlblQ z@s;@sw`j=4YC-k`zOx+Aq6D1-VhUfRaJb7Lf*LythjyZ89_6HQQ%D}9VaC_S)w;wt z+aqUm>+Pz**Tv(iS!JtXh&qgK1C)CXx1#f#@hZNIbtPXCSJG8=P2Nm*#1`KThZ-k8 z%Z{jTlBjUg4e^HKHrCivUDH-AMfGH=CjKxVeYeTs%p^zKPq=j^{C`Zn*^{KXktc?@ zBQql-k#}aDsH*O&?yBx4n%4|x$sNp&cFgo5LAJXl=?#AZ{scVhMbLw6v@4SdyC$0% z?QlqNC=O@ICJBwyTiTd z+G1REXqTZ@ioY<0=sn$pvEy(>PQ|X91h!hF=7)4YZH0C6ls{4{>b|}w?yHrAyy5=2 z+ORu?QqX6_y)&)UX5(_4BW{sFoD11Vpq7L^QmT>&K@10pSZ^9T2ziO=3XVrA5>fbc zGq((IM7j}q;p4QO3CQk^h=B89PGOwMc{!6OSwkZ`7h5N5YK7hnBC^J3h$c{9~5c$ch3?9jA`+hP$}*X%1~)RLeNN@7z%jI%O$&HPMDKoflUFr6}e}(5P5t>-eort&G<8Wjol*m%wx0+ zxx~o8BJxlIy-|!jHO@dCwq={K9?PCI>{67(pdA7GJ>9ugKf+3;n6NO243Y{6q2_+-y(oQ^14O z<5-@|-Gmrp9XXUXCK-d>Ym&bZMhIm=y^NI+Yx(^Gh%fT zWWf@XY1y77r}C0V)O&wUUUFaMZ>pE#h~8x14}Y6~5I+HJ&9QTcW=Lt(@5^WG4!`Q& zx1Y%;t`Sa|i|R}mk9%wlF<775ZPT|zjA4#g_DgOKBR!J`>Yjf_2XZ3JpkM`EP zkoo+98M-!^Gbi+^jClKI!XZ{)5dVG8FOt{jWjl|3yid(Tu_o6wVuF(j?<(XHK&-ZDw#jehtM-oHm1A-) z&as&^WvT1PracThZa>!SygNtE=cO=hrqv05p1w)GBfpcD<0JFK_}B99A@=-D_8a%J@Bw|HX6-BfQdqPVu_M>rI(wm>nHMN^GM=@U%o*D?2YNLmx$G9ILNc+WpzcKQX{h#??WEg zOgj#l8qJtn3QU}c<8Gk0L7z1@rRL2XnW4x{;7-%CjM>xnO88Frlh}~&kpETwb@-Xv z;MJ7I#@-u;hBA$|;va=Gg`vIGi;k-GoF4;fPe|Lp#6 zdBfKABsf`<%%;qcm38 z({$5Z&#SVRkPVbCiY4HD65O+=wnbkc^Mqc=OKQn4#S{9ZU3M4Z%l6wzka6*e_&?2Wm|=Gl^_ zb|{~jhxBRKqQpYpwOu(AsBKHc2qYDQ{--J0%~NqYEsE3etUBetPX4X?@6$a0mH3~? zU#DLonr{}*Fk;S|@5Hat7W)jDSl-4sNbaHDqx1ADk?SSeV=G}LJS8uHm(5V4z@vJT zyyEurb$8X>B2NWkp6fBg%tdwZ+vTti6bcs~6bm@M`+6)c>e1=j;AI z*#ABLlHB2|@;)S=3*p=L4c*kqAO}SHG<$`D7J(S6O6o290wGY*VI)||~Z>M7?BKESqqwn(PvQHa& zkzGk=`M5xgOmMD;?m>8x2xxpE&C^-Lg6x{QA*`yKYCKMGxnUiVlJ_l__w37XZi2Q zPvmdHyNF2pBmIe;r?1T`2HMfaI~Zu?@ykrlw5vWpt)xLo0b@I1z9dm%SE-QW;`gyEk~9vI;Q@V{2RGo@483yy8UVTPx`z0 z1K-mdxfkZcC9#wmc3bSy9n2yz+!oKlb$1~hQgbrR$_Y+$$ByKt**3^;EH}u$uF-Ld znBJhPaY&4auPVoKmrul*h&6$pab;z&1R3TMebxRY`>RCUhIj&q{-ge``hoo-uEoc3 zN6gWaW`?ySa@UDbcx-RchjvYX!f>yVO6)^Kloit!5jiPxn5hG^D|h^UJcKMVSmcFcDyX52(G zRs5tlDJ_ z+~|a%QkARowO2*1nRS7g2wn-*1{-~H{)OI6Q%yin%#l?7%oe$^yvY2u0xNq0_ z6L+87p?BzY`6;prePOSs`}8^ACdgE05!W*#wyr3enNET>MK)4dfniN*0c$l1h`vMi z9pX=OtkOk|AVQ-;Od;8zZQUVL3Tsgd30%@Vl^_XotUlDY2*l#M#hZ5DZP{&>=_B`$zA#t?DMY7tR4vJQHbuG$YmLw|TV_41v+Z!eMzRu+ z((^H(L8O+7!)H%h>YxHYkMm!TY^8H)q*7B;(v1uU( zijE!2i0mp4&2D_6@9T%)=@}B_o^0Yxa4$7$k>eaxu$wpdCe8MR*aqLJ+qRepQ@X^N zp35_O#?G1kKNBHA_?_mg@?%-eYi zji!U1DncKmy0XZ&C+P)wF<%s4k#Df6u$Dd-H{++`C*r&M=jOIr$FZH8WRWk6X^qV4 zq^b_cwtbpbY|;ZG1xP*Rtsj%&f0ke?LwSM zlNNeI1MbH$+q#$In~u9#w<+)16?I$uT>WSMqwq<3s2}>r;xJ6JQwb{}+XZ%8mWZAB zBtEb!;W2w6o|BIa zj?WOP=gBF1j=vGV>K4PEUa@O>g}fcV%YMW@pm*aPe;+d5cvzr|pjw(hHMt!RZ6<5< zu~|!xpb2>)4<+K>+bNBB&8lkxEu5D{FANyIQth)d-wp{5~ekco)-)y?xovuGF8k^v>U8G;zn z_7dTcyY^{z+vJ)4IQ`WBg1zUjk}vWN{mA#gJCOA)b|5dzi<#W?!*Jkxc9SF9mEDM2 zVq0vdeyW9bXvJ~cWmHazRzA|3^D3=`YHp^M!8*oJU-U%tVu3CM$UByuaenHJaE^cBbC2C(}{la96DCG17LG~R| z4=ved(*hiTbQtv63_39h{Wbyb(c`(JC&8oU0=Ph$i?eJtVgAoc;$?rzlXuyngPn^(uA_w3V~N6x{D^+w34wi$Bb!rb_%?6(NyxWjvdN$|w@rzt&%PpC zsYwv~4jdNNmINNfVat;PFo;x5tGfa3cBKLtE@ft?lSVny7T#IGqZ?mSa^Lm7>#kT~s=CLLlqRFeVLF;Br z5vi(~EU8%;RJjn!b%N{}79oyPFY7}-i=0;8H9dSomI z1@FsQzh&p#rs}3`)fCXrP?P}LKn_jYX5dp|Pj=P5>+%iJLSLxgG2i} ze(3n!T$imd2pF;QfRWHO&ALU9Hp#vNEDz%bc-6jY(*bC)iGCn!ktuO6 zYYG_EW9-08+JS7ynyomJkt1HhPG$FVh3?8a8#3Y#B((Hwm(}$ltEYZwo7#Y|fYzvqpW&k>b_1+wkF>xTK#Aay61K!|$QU#{Q;z1rm%c^JtENi?Q zpZTucl^xS}ZInaIern@$NXOGK^uu`EaTT#2Dx7fGG&HhRk;!-vMtMI}Bas+Gs$yVw z$i>FrWCJ?}2-ejBosC<3l7IpNagfE*o*f4Tj%8#Nj0(?c<4_Crf=rcT_W$UDZV-HR>V2leb3LTY5dnrcAc zfxwZQL5*0$@2i?dd{>G!kOH;%UD3+KRpTJH^Ny;;U5sLq4rDWe#v<&t8oAc(fS_Iv z+j|7B#AqM}Yh;UJ`M!_ z4zk3-9A(6{BAY`fqS#928LC@P>$pPD$Ypktz(UGzotQ0sjbgk0Y$^)7XWgmYZx5c0~hdTlGE{Rbh;h&)~BJwBzUIPE~h~qlN zd+O+k(k^z?CX2R~w%I>?mlDh2@!J)wq15ubJaPPt!5hc5m$v9X{BpQku6i8h?eg^T z6?;^|@%`g#<$9_2_}$|tzx*zD{`izWD)Gy*zpORjYC;_uN5uc~DZdJ}m$L#1hfl!o z0<-cd&oaOJ(?v-l+Zw_8_n^E} z+N^P{K%(3`#zc9iTrKwtUdmbdukiGj&y{z+#928z{$0N1AI`u0e|)z*ar{jAeSA$H z{XhO~j_PzrPyO+`w6D~D+>%m)K6<-cJwD3s<0p>W>yLh`qte13`hEQ5AL~3mE8ky! zN-3phU*0J#E1xfqa<}~c5{B-mmM_aae##v^t^R*^%3I}`@^rye!MDQLD76)wNbuc& z52<+EFNZy%0#+&fBcbo5%<`tkopQgFr|_+DUdkvngrjFPMxMmzE`2Voba+SOC~p?p zDeoOWk9i4apb+rwa+g+0S>^fT`{w9>#1(z?p23}RugnP^ZO-`4xO3cIkN@H5S3auQ zVQxg(6%I)iwHyY>KN&H?*^olMwDwIrFDa~MSw;-p?p?Bf2$te zdbw`v7V@rXhp_-}q1>h|tX9Wlonf73YqVNw3RML;&!8rY6@%Cz@S+ljsjNCn?w5f@ z)}7cVm_Owp^mEB;)1y0Vm-IApH;MxVi3{BAfT3+}U zRWf+0!Tifd3icU+m2`q$oi$j)RYS#8%eSZntf*|;HB!q>s&>SBCbtxF14*nbbJHLr z9ht=aannh#_k|`yzVp~lB|q4dgoPqDT-(Ff%pkuuWK0|!TI~p*I@w?)GJ1vJ%%fJ_ zk~Lp-zyjKHC{eS->KE;=SgdkLRba)(AS(yZSls7WbGSN##1qOa*W-JT>-OV;L`G-> zsVnb`zS-5=dQ4LmyS7Jr@z7TN z(Dr=K>_qsPkOPUF;ue^U19`yv446=d6z|%R9C_+X`IAf;=>qNfLR zKleO50~KnQBM%QmGg1et9}guWhNC>JvDF~Jqe%g`aY!m2s~y0F&?XsoSa;ecX?ct+ z4Qfr8ALA(0A~IgfifqK1#B-r7tCa96Z7Sd}!~R5|8xb{Mk2P9o2RaH>=Pfl6TN?D^ zMi_~Qq>|ukSTq-q};2 zgn$nO_}Nj!=r2?%PzD8Em$Lwgfa8uCZk|iGZgkfk%oMN#w(V9sL^n%-*JV;sfzaA!C_3VEYsjaNZV! zv?q7PKHGE1&nz$&W6d^WBeXUALgkTnXdG8#xvin;w#ZvAXXzZ9C36-Q;Iyp&oqkP^ zr_*UpzE6HC-ZCKs`YU@URRl?!fNs|eRF4e#FzgxF{=!Cn!XJqqshOcU%DhN1aszmo zL|%I_)Ppc^uzm*MiorhPTBd!YOqQHr2n0zl_1W z9e)|_$aPM8iK6Yy5#9X_t7?Yx{*^JJMU#5q{luCRa0zZLr7obJ*O*x%FN@OQ{>#fM^p zPx*;3B(rvzBPVqR1l&4VO^?J2`P?BVE$LF^6O6EHs!kZ=Q)14*J1zFyp?HxV$z2Pd zyIfaOV#Y#8oV%e*I)2g@8_#rDgjHlopG#kN|E+$7RMZ*KlW)22L(lkjc+Xv@L*QpT z*T@2ybtLxPi0+xk?g4!S`^LK4CC$*)li*`hvLj*R3{BaJu>P5f+@-*Oe391mzC>>NlO8+Z8z!>>g#|2) z%V|IB;Mr-%Lq{Onb(lBs4Z%bznY&>{eNA34Pq^+JA$e@$I-{}LK#_z&}2>L2YtiTCOI{+55{Dh}R=s-`-2!Vko@--^%W z!|=d9&YK+C9X%#s1EKI47qHlymaMwEfX^k_#JJs-+3lo3Le|j;`b*SxBRH@b&(H>o zX**5k`GT7DC)HVb85w5(h5ZWOmL#sachh&tFZp}o1~lH#naLRoE)C4pGWtcI(Y5dp z)cD*DBxI(9{Q+(~wFKs6)6&rSD&hv1|3HBO+G>NWoNBQMnP)!|zZIX;#}QDV^NM=R=&GR(p?!W79_c6cad@ov z5^Ra?XkP#ww+&xq@R-bXv#<9o_C46=ev^z0tev7AU?HZ^*Sogv#IEavskkT?E%q}o zWB?|o-No=qc%6PnjO?a(ny==6WIq(Y&euTi>%cW^1rd@TBYfaC{R+P)*YY#=)PW1; ziO}Wav@PI+EGwXwG10ICvK=?+4k&S(4`a*2bBRq@_<$QcnI-}(eR5X7{~JCIa|U_1 z%|-f}xum}>=F$uP*nghhN+SZQ~@_-v~LcJG8cASFC zWoYmnWFkOoEJD|0AoYkXzTvjazO8V~%Mx5LPBQS}2>TbA^3!@zEC%pnvuI%Lw^tmp zS+j5WP4y^U3-6~N@*mNkoBMe`?Mou3#m*$=Q#=pij$h1(Qdh}Bdzw*%%3V60f6X8jDCrZaS2F4)C9Z_kj|!>jUD^)1ZD zTQQ|*f8l;&eq!HMt8rJ1Qq7O~;ww`P$XMxeUK6YSK4#!;0$qJ^nBPTcE?uunl|)?=(WL3aFUyf<;Xg6l- zn3skbyof=%j}GuCD2S`w6DPL<{DaXGkqpL z&)3;4{=jCluaFB^j)%4yV`H-AkkvOf6eK$Ez=6QJ$HEp9us)NJV=4HnE90W3>lSks zffSmWe2gK_umv4h?1&)vIM`LqJfwsZ`fNI#=Xgg{WroMey>Ojgqc`0(f!x;gHc9D; z-6jK8BjBqzCPLdo`gX^1E9?h(s4-v!W~Df?sM{kOki?qHR&~wRHD)bYb`imkLv`5{ zL)KtA<=};(VFy<;bWSYB6Z~YHPhG$lUVHEvz0Iz(8{~$&#&7sr*e9}TUs!lQ*+v=* z6K*2IBS5thxNv~PO=_SyLZN48SV;=(J^&O5LG1?6H{jR~nWW7a$4;4y{X=95`~mxh zY$ta@R~COL_#%N%&DtqFCabi_HmfO-+u^3a>2A7P@veBl9@`gjTlPIM4K|j>`9vJ& zXa`1Ii?%q{00Gho<^)*qSf8Q=6h29!ks6|<+H6cgE-ItJfjg-Vfvil&I7YA-7ZZHK zAvZmnp!jdwwr=4|;I;+q;+TQ%oBQ&fy$3$DO4lSj5A<&CL+XS_7azlXFrLv4iB%?T zm@4XoY{2l5#9)nJ;Qd6JtZm0Qd>h4thlSXVk+IY^SeeS=J=QXSBgJUu4S^M>2fc#2 zQBoYzLEI<3w4FA|rpbPt5WUJJgkx$n_x)kkzJn^8@VmZYMC?g9j10~V2ri4$G z=o$F-&|SGn(HaH+?EwEiy~hs>v;$@ki{IH$4AEw+a?~)65_IVj^p{Xq93xE&8pyE8 zil!aXfY)kL=)R?ime(O6Rz(KP6#Y^0i~yGm$+OJIjgs=2DJ@S3UN zt-2+dB&^FLG$+90C=57OoC*4r3`=bShh>8dNb4cT8AU54U=K!4YjnU8dteRpYy$RShmsQhdvFSe`?i{4C$<$`m-tOd00k;=6^%Q-O7W~fuOxa` zt{Z%4HQ+f>5yfhVv4?wQHx!;yC>Q-6`C^}`SVEvlLJJNl<_!nkg2SvWiiH=wqZLz2 z{e8J{ahs3`T8fH(-oifehSS5RS4#=`(Dh zz~+!+mm4kGG|WA+TFy&}VE}A_TK7XWiZz0n0&pl$9LcJHg%OlpHH5-r6F7lx zi!~BPu&&sKJn(f^4F?8X#@BftFlacU0TERb7$bJ5o3=vtS&^Hu`^_|Q1`U>O(u(R6 z%zqJjKhmHz4Om&wFUCTtw}O!ZA1T+MxSyJ-?gt5was!3df#L}rkXmZVL4pr~XwU=N zH;^~ofD_xuuxQ$<1O^R833?2O#X4{~44`fepJG`o-v( zs;1)1rND6x)P|J_EjRZ)m|UJ?L3g zO)H^Sme2;MX=vMG5Ql8Un;cS_Y_LikptaT9r+AYQ2U-mnZ5D4UlIl1+1biy!0klY@ z!Z99cPt+3OwFvBD=08*e-_T8WMB%2E1{#)FS67FrNUuj62K_;qr1Ykt(5ehOt|EXz zMOFl)H-oY3D<0I#F-u#}c0?=GsKARhebG(#C3MJ|n3@BeOrh69yfp}rcrte7hXx%) zLcmKbq>KnE$Q1{w!n zDDjj4ZDiPmDP(evc|jgp*!u-~NWggnsDh$Tv?6M%CP^NsA*tyWpafpUh6RF}BtT9L zML&X8S(Sm)$Rk>bnC&eztC9Fhth-tq@L>kGlvM_;HEJ1%!pUl&d8|ulfj`R9=otq` zAyxDZEpeDHV}WxOr9$%>;0+?G4(+xifiKztD5NIfF9FDdi;AkM>xQX-mLd5Pz}8eW z`sfbP%Sx)!Y6OQMLy8h2W)oYHkdpb3jC{d$)nF9FLk3(iKoj-go&)^{)K}maF$z4S z776?WU^1f|KnS{P4H~t04t+xVBgzZMJt7J-wZL76K4xe=6C?nXg5MduEQ3lI#)rmT z&1Nef*R2lt^z8B9HRi9G6QLYpN@&)_l={K(^zaAvE3EzT9r zWR;^O9#5GHt)!!ROCQTe0d^QC;Mx&0JRMr-em%7N5+8xRz6u@>1e6UL1N7N3O&!%( z>PYzTnypE|mVvezWDrsl_)gVO)u>%y?(l^=a8QhYk6Hu13)Dy%DX3QzNQSdIs(!d7nm8`QGW@(CF)i9#ufD2qIQY;6(FThJ4b08HM=TBO$xo0s5787 zzMAnJa5(f^0^%8XPe(LS`kv8i4~RQpj)Hq-;27g&Xi%TUUTTKA33^`IaNPF-6$!bJ zL$;D=u>#ZtaL7@#^$GOd)-qraY7YMc&dkww zxhF8n2-=A$TfP};uM+-P;!GaQ5i!?2E4v@Y@3*`aZ&HI`Jc*cj0 z>Es5m(2CG0g-)uIMre@<2k(3_qo!%G+AO$vJ7ufTZ#^-qWX0T#H#FiT$b0e$v||Sf zQWS0a@rbpwZ08!QP*~8!0o{|^YK!ig0}F{qLtp2{bw^VT9d;mQ7n-VdwiA14$RTsk zHt$GEW-|6iB<$pfOJc#pquaqpU!1pR-6Eak6m-2VZ_DfP)A*tPz4=Id5pLxNb~BCw zR&uVBu-Dv8<|eC#f!s>Z>{I?+JqypmhCT2EYwE7UE{q6`w1jrfRrzLIWe?>OvdMYSVXx=M?sq1LU$ghg=jpb{ zwrb)3?Pl^4IRPzG+hQ-RdqVGP?A0I-=_8RvA5=e~7U+4+(upubren+QL$CNy+|@Vp zLwOM4oor|IvRvj%ewm#Xr|A+ayH>gxdLw;-e2sryy+U7-r)3Q~nosga{Fn5f^pD+d z(uee#TqAXZy?o+iIxo-i8Qta;yPfa*YyLWc4kO;T8*)gSdfJ?kFUyPZ6?P`hvzp!@ zx8nN}d)UL8ADZcSN}a*3oRjoq!hQw6DChXJ?>MYiWk;P#Uo+oPe?s4&ubOsvrazRw zr$2Q*{6PF7yemHAPt15&w&%&E@Ty~)%4R-HPw9;i`N!#F{srLOvkf)nPsNMzRe9OH zE?<(c-;;Z`$0nd5J#WubX3jY5ix!kakL%iGOpk|&*pUn54fPlNFXg}B z--;~u>?iUq`;X#3rN4DQa=+#uVb5O6ob^}SH}f~eWjPxwd`I1npUC&z@6GRMlq>eY zboA+PCBA82H?O*j@j{|vFMN@ICjXKARDKcn?Sgzwb90%VQP|mJuxBH+1N;GGCAaLP znj;Ad87T;07 z7Vp^iWLxoO{T7xD~khk9yY z%+@_dw?<@zG%HV=OZgk_U$MWk-$`GkFWCzDLi`u`AN61Je;z|3=%FoRcH560vH1^+ooqs*PuFpA&(Yqt>(~t5mXpp~`4`^Fl z7JnZ89G0^au`1yKpbt$|wK8-jv~9X-NnMa{=D&!4#r|A=RiEP>w=O?QKe2yfo%mbz z7Wu+%sww>vd5ye5FH)!%J+LwcRdXk)O!lvbWjq^XKV_AKBS_K3-0j_FcNu=eLejdb_4?wVq0#A9XGPA1Pe==0#{iGC(U_s#eE}x z(|#>nCZ|Y?KMC*AAB(@`e!th{L_Zu&>@p1B^bhx?)@rp+b!jr2A067A+*cp;u??Ed3jJMS0S zvRe>~aao=vpl$lK_y+bhO_^=`nfST=e)!MkpV;rj0|Wo?!d26`e9F$67C8`4=nejn z`n~(WUGq=E(9V!^>QcO@nO?M$x#qAAVwtYm8`vN6nOZeNwM4#R{)BOL1{%8_G=iH7 zI|$T-!cHST7w6@&JVnm&SLIjy8~QbWAkH=>0Q0(zkn7hn!Ivp?ASHKM}`3rW@jQKs0?EB#-?w??ReTUs7TeeM> zBvWVQlIn^oG>p&XDnWcLc2nKK*(PSVsdQ3aATRkdaz2jHnjZ2E^Gx1zH^X)R0GiRZ zX7P3Y6?c&@_(t5z+kQtKMsR!A5eo(|{2MfWm!DVz?oww_+l>*iPb$MT2q zE%~8YO~X7L&(L$~6rT+(IuzUPnOSxB*d2e{CHYux#|oK71cM6%5eec98xu9v6Fc#d zx@WJ+8{q-;p_B50XSrf?AfR`FVksr1N>%O~yfZ zOg>Y;rf-Fx$#=;$`Am&WH!ji>W?pnn!yd|=_(H9*m2fZK(<|v|fWJPQ;>(yv&ZuQr zF^cTecLx@G!%Wh*WAZOl%`RaMc#~W)r}(%X(5+mgg-RMX)Xj={ctw;wflKnFIjdMa z7f#a!*`~YvzImVg!v9nT^O1Z&4kC7-xf66TcT>Y0irtXubGc?$&5B*&kJCEqN9@o{ zC&k%xiY(+#t{Yhb%QC5T!`Zn(;_{k8Wbm+LQE%t;Q9- znx5JnGqN4Ngr1ybC&Dysxe*<*1Hb8?v6XZu-c`@tFwLe{EDx{ov$R78WK(RBo~&@} zF*9>?fh>4%60yur(sS}$K4(wb*;r4TA*B!Xugovx+wNns;`YN>m=nusA$4^lARZ8V zL7v7(VU?}QNA8K*kbTH`MdMxj0MC8cW+38Qk*U}sG5?Q2; zv}-oNcl(%Sx|lOzDGhT8_Cku?(e5lc@0mEsW>QUTs=N7p^-Ei#ZG0S7#6BI@^X!CK zgiWW(hZvRX7#oPZW>&=``y}SLA8Vkaj&=vJ@ zc*p;WzZM9C8`(iR=KMw&X}4$F4VBSv9> z9z7nx#@;gz=u^@slj@9qm0phL#XN06vfYb4KP1i6aj;l1$fp|Cbq^k6m&1vCf-E{J z>tZK83|GzX+}rWp_({Gmc0`TAcPPwA_ zGs|Qt&Z@~+7l?u(Qv8&BL_U;P$sPHO_IXov1C`xScJ21lHrbRpuEU!otBtUkx7ofN z$p&CDX4e+vuoszzUn^mkzC^s%!V6=mMnH^M3VGF)5}|N!{wCe2H)`T z1JH;gVMeMUIvFt|$$Xp^9pL;BIDAeXt4A63Q8BU;V$q(?XWU6X=O=7EKtGuXsfFSx z2OU5bn!8zAd-%CfzcdY)fpJozM%1v_{4m^@ume<^$pYq@nDGwfM;0OKT#V z5uJ>S77?e+NjImkpPJTUMb=|OjG1wd)lceJtTQe4@;Y!swH)Tv6s?03uJK#+u;-XfI`~hcJ!1@UFf9$UVkse>V4OEo zyc)J6sK&h~-zOiMYxKT&0Vp6QMyk1nKr~VgE501_%|y_~&HPNS2Ryf-bVB`grc7g98~^`3l^ zZ-}e@L;H!nChn;xHVbHk?7+d^E8DzFp!ac;sU=D7iLEk2fD^*gTMPrNJkaGp$7i8c zl+a^EXtZqc!>e1gf)(#~#6}_Tb7A160gy>uaWsY^q8#$#|29viXp`=dXA%A#R1~10k8qvh=kRH!jIWw zr?ZELg~or@_U#0HP#m+xQw2U66ux+_LnkA+g#)J(h)BrCLWT6=i};AH#Czd^dPpDZ zHU3OKk6CToeLeJ51^;mZTDMJEH#Gx&oFcv=i*66CQ2PQ$IIxEly3bIv4Gy224F4Pf z?+S}O5fWpB!$T!DU6ZzCD>rrd5AOzY?Aa(1{!S+EhevGJX8#HrW|@gOBD3U3>sbzuOQz5RxrwNAUcnO$ERr6 zTB_xSsT*kdFymA}cSqI@S!@o_p(H&G)$Tb4ZeZpv8^olLBsOvFYHtA*dBvUOKb` z11v}!6m6quUBtKr*0EzG;+=S;w~s{^TQs(1j8rmOtbiejzO$;VIMinGq(+Tu{2Eq1~YgN*^bInt-cBb!n<y2ZIg5 zf+_$5v{j@10r(D}#8R_^ewhKU7N3HB2`#^=vu12qcw|w0$C^Z|G@h`~%BKowqY?nK za41Fw+H;0|BXYn%QDLCrvt?lINbqMd2O1P7a3vj$cnyk+(38hu0*niW1SrP=E)r)J zTJ~6T;6T1XnzSCO8Ha&o!GppBTE)=@4roO5oWMqxhZ?pFiQZ=P%@s}pJm(QbEfFJt zz=I_m$OGHw;5TNdKpUV@)XR=2HKG*;xR%i9lLmozmxMKeV9cp{1l$4ZIzww@Q$b@V zstK^t6#;58z#+kSGw^c&mSNp8Xid4A(I0YT(X{B3FLZ`yRPp3HqRotv;Lr|X1is`U2oTV?xX43t4F*9H1h!+^ z4(!-I1J5iSO>C*9p1avKbp+^0Txs}gq+e7laG>1*6wkQ<*Ar?S&pT`#+5+k%INZUH zd{!V8NGaos_-{M8F(^BN^g?bqAbB}l0xtuMg3N?mH{qA_lc5Tf0Y_~KNT)!E$HP$5 z1?m$+&mX|uh&)HY283C-VuyZ<|2bs^neyl>O|I$SJjJ)GaK!WAje?{^uaCn5u%r!iyIlz>qS9L-%$25MtQzH-tNQzuIgfqA;@~wa~b3LKWmMCS0uaL_M z`B5F}a!wG6Qez!#nL}CrGY;O_+trY50&E&M3;Yyv6i|u?Te6r zSRB%gmZy`CTxJd!bIkI|u_<~_35?k%|IgCIQOk=eL;fu=I@FnnlFHmfAC>#j7wtsO zJ8*X5vQ9nASQ1LG06#tG$s7-e8{uav@&%VQa3QS@&lo7Oh(*yNGo+C7L_1V6v{DiM z2IL3O64a=UOytyA#(;JxBBjuYoh8_S2br_6lOG2;*YM4;k*5l{j!_6l4oEIT__2yX zius3j2C!ubWg09bL7^0L?3`}}s4N}1bwNnT97PT}AQZ4VV2$w2@EJq?S#X4- zCT5;wyk%Sme+MXyM|Nre>ENV*DvT66ji zaq^S>G-76|a{LHPnai0%hM#%ySiCdN@|S&cJk@#UG;(N$$?q~u;~nv2SyrGrc0zN0 zGqtXhMyA?=F}bBSg7D?>7-%ohru(#62fEIB!qLHQQ)=^f&I5&% zB=lWbCJKCKU)jMfJMPnXWk^Yn1IG&F#=M|1=Oa_=I*&)Z%=t{u%U{NuORPYM?36?f z&5wKmmrK?nB*!culk!D)36=dR@?3t2&O1Zq63&uaN`%JyWvP@@WT@KW?gqh7c( z?IjI4eum1DmeVa$$uY~g8B%v*xz0QPFJqTjb6A;T{?1<|^r>&gld)!)3}HL}OV|=x zA>{PQ;jROp@s#Pfuf@vwj2)Pa!E`v0<7CR2mG1SC0xc?V$B#&Qz`w* zI2zCy;`AxuROkEad~|>-!(Pf<#+M;We6$ls!AF8--ua(HPM@4Y4%HpLC2-ThUE;Ja zpfXIxnJLQgGOu#GQ*Gdyr(xy$ zC3kcD5@!y{?koeDa~xm!y9_OPe+pCjm$=IRwgc+{o%v=vv9g~6EoDvvd?WHkD-o{z zxDNIlKT}-#<*yQ#>tM{j*)L;0eO$+-@IO$of=xeQ-YcM6f?WVh)2 z&#qIfr?F1`?2A-RvA(1=`()nal69T`C2Z!7M_A~DXPBJdQ?BJ$s`JZ!Id++1_Sg88 zp)bP}`iED4uQ>3E1FtyniUY4W@QMSkIPi)CuQ>3E1FtyniUY4W@QMSkIPi)CuQ>3E z1FtyniUY4W@QMSkIPm{34&)uGyi<~QM)J-{xu4?UD)&puuyW_*>$@r0r`*NK|4+YM z$CbZISN^Z?D$)%voHRihUI;n>@NLJu_^eR()bdxbP0syuuO4= zJKZnOu5wSVjGHl*ILi0ezq0?SZy7It<=w7-{XPvVIaS88FZMRe_$7qu;FE}*zf0Vu zUv^vgxECQg)V_c_&3g%vp#s9(3wYmoXBhS3mvNMFN{ksYzSvXrU&H^BvYdLRBg3CQ zr8~pq9X{FdFLRzDUUI;7sC@aY5n5s{U8nf+JNumeFI}f)lQEV#cuDz7*i%YvCw}=q zhh{FE{tun7(DCsdcb277*z78w%;W5Pn$9VV?!+nSDPxs+|2n-n&6nS@gC~EVK4n>dww(hF2Y!5-$JGDQEvO1>bqUOf6HZU(lRsFY#sH?9M;eNh{~Zb-qr+ za;ywp#@8KJ8KaC<`sC1;P+zCHOsVuKp-MXS3u+bOm2t}xA}_znJm#8#A&o4<3M(*NcAWoV9@L$gmlagp6Q#S+4HzA}zdeoNdr zMuw4{|Jh|;#5#SKIV))`!}EXrYseDsOX#n=GEd8xx`Va+ewj*1U;bZ)yu_NRb}#so zOa1FHPgBo+Ii$qrU%c~|>f}nom8r9MyBGP)(5JMNl$Jhao=#KA@6uhqb1M0lVN1xI zMyBf&Tj?+HUHWDC99G7$FJk5Rr8`sf@+;%Eo$nkc<0`*SsV~3FoRle*P$jmEF^9R% zyG*zA$ygPh3{ldOQ#!?;Ay475Z<)vJ$HD!VU!|*zU&58{QfkUj-$|pycbbP1cTW53 zsbqJFC5L2Je#&?0pRs@4H@nrZeM*>;+Dw6b5tjWGV*bD5=J+|yGG>0C!sJ@&P*YST z*Zq7ZRpG>w1$G-C_rRbf%I~IP9YR1$nFv%`(AP&x0WldFJtesbLMmk_&ze;Frpsl=Hvea%;Q zLUTT{9GcF#O^J7bUw-o0J&Ip}xH*>w19?!4v-JXDWe!VtjgaC6e$|OvrtLa0vs>fz zqQ#lLobOD30+jDyu^o7YGRzdZoWid$#Lfvw2VaeFQgM(U&|2|;$+D8EqVSP$S%hZH zC5J5FaaIXoIlcTpV<<>biGXqVA;yc86kH52xg0tC8SY0AP#BTV*zq@bQ>2u!(24`3 zLR{Xt9}+t!u2a6*h#LzM@EZ8@$?!~1mfP}4xT6t((c;b#tH_SDXIgWLqH`lAb3Ah) zb?C4aPGZG_VpBxsR*EB5b%z@EeI4Rj(3<&? zkUDOKR3+dA^yT3`&= zid7tJ^?2NG5Bs{#4g(}sAH`}!xfMs8*jhY6`Ga1AvX{rHo=)PC#Vv1g;tutRIijF1 zR4i=NT1Zh*Whh^Xn{~K7gnL4OuGj-zp}1#eNx&`a0z3;4=q^9P{)IFeMg&@Cfy3yDJar9M>PI<1pq(oGIb%Ws9IIE;`CQM3Cxw+gu9Ti|w} z0ldKtBo8}fqAnmW3H2wSp3xIp(YO;DP|pIa_~tLVtpLYrx+xER58YP-ax?a*En1@$ z23ukT<>8NQ!w}L0bWI+bBT=D;3A&mSTATz+1rj>-DJ=hLSS5~!6gN*jN~wTG0CFHv zf6PIIoP!H!9W+YSqSkq|L+rrq`yEje6<xGs?dGYPySc5~p z30doNYXUq?M0a^uf7W}V9-&)Yboq7Kf@Tjwd-S0LouU$;J5)C^H;TI6C2f!PC_?ZtMlLVlwM7LTg1pWzh&HzHUzZuBsQcc$8|WtI+1bkPlW>RRZa! z#|kx;5L)v!aY&#wUf>3!XbRAx&}wEHDR>)B2x_du!_jKkV+T3*Xh{fip`rOdq22P} zBJzlu3htn<;aL_t_lJ>UHK0|nxP4AgYfUXdIz-m0jGj@Ujt7(*@7x9tB*#Szv??69 zA>qKOA>+E!YvvFGT=)hBkpM4fDR6f=p`XztfpU)fjr0V(NAF7j4IkV$_s5xL0|*Js z94>}hDXJVjzsV^;E(|#DJE?16)>VgEV8B}m8L@zMsN25gswT?}+GmDuf|euXymn|2 zh+Vn^QUmRf8->;?=g=W<5-E8=y3T*_64WVBVor*DXBqcfHQKmP{)aYzknd#U(Ret% z&2hwieS0Kv4^jh8;?cNEE5IF!_L?FE1)LV?`A#Yt?ueX9SY|xFk z&esieLD4O@#dh4T*|P@(RG}TkW59!eH?OFwg!T&$Z2+mBU^7Vcx;8Y`P)j9+{*eI- zcYy7kVvr4_KGRLRSR)d8@3>n$33MR>RDw$ODVVH*f}tB-#2+(3B=I8>QBa3RuERkikS|qhbw!{wG7wG8>@)Dq5B|*1}g@rHCSM-NI z)l0io%hW?PBIlu@x@0ef-6v?sf=0VAF3*#T#bt5{srSkXT{ClT&dj>Gun3($i*`k? znq?1*GSIv8JU#c*{&`v=8)QFKbc?nPw6+A;(xmlRwa{hEV1X<^gNy2?J-iO84&=VX zsLOU2gLIsp=NI`UbtPPJSM60XYMXqQ&#Q<0k$(n#bg*lx(5Hn%3o2MN_sAVsAA7(i z-71BCH`61adCK>j7OmN%v_}uq32Q;?(;0P1o%h4OLHFpgp64sY0qx@#^lR~Ygx<(F zOvmLF_m23keIxbIMf0Khf%;{fEOrGn@F3O(o0X5vV>c5P_+p%ulh6h@3(hz72tDsc zd^d+JxVY}O!vTYCF4Av@?L?d)Be7w2+@hI+ew+EyL3hb*`l)?bEZP&->jy$FgH{j)O~ibFkho^& zpn0h+FNb%`8<8f$x9vKG)mUiuT9MnjAusSkycceY%lurtD6aeKup4%rY`AIqK-?Eg z5n8RpnqCR3b|bCOq`r(FrC+))#H88ey8?Q&ebo#^3a!2)MI|J$A))b5LhGFvO%v*z zA7S0akzIz?vZb_XjzW_S$&37kfu%ls!@a?-Css^^%i*k9;IsO%f1;P%Uf7bWY%Lt{ zbvB=#`Cpmfzlt3_%h08BBD>9S>UTY1lsCdIKZv^$<6BGPm^vHIixJT+PQ(sf5378& z*a;`Tn_i^X>6`u*za`)Fud8eROnNUPRwFDX(qaFad_xY#9kNL_LL$q2L2r^idL`bV zZ;&^`H%SrRMEw}!g*or;vHQgoYRBVZDa`5Pq8_N43lHLR{wRJ`d`Q0H50Lj`o7?3< z)Mw}rGcC5Iwu*f`d!)xt@C)K%F>HDb#)4*5&ih5b8IEF&jmhisrhkhT@tt^+ylyYR z{@OeIet4>9)k^v(J|WBEfOo}8*x*m?wwctQun)+65%nBj*So5vN7T6KBhYGC>`Umz zQ+pKSCf}B4v#v_io_eaVO|t-fZ!2P#Ra`%Gd%mgP74O71p)vXfy~r=7-;mSkshcO8 z{sZwP&sv{a5!%wsEZLXS_E+g+@rXa8Q7&ufg^YuY>V7e*&xC!krV_>+TLJbc!#R4z zPS8QpO`8~jEZA9%k|al=H(d6w(>LN^nw(ASS6uR-m*?8XX7tpxJj!>J9XqUbiUQ=hp0Ee9|yPHre z<*L{r$Dr|?xIqh3@NbZ}-DQ8pzombZKcKT5);rZt?VYe74lLDMe4QqC5+277{3rB* zo`OZO1-la|9ihF&fSC{zX5TK`6>_L{`7!c{6wO&V;Gsu`!47Vmipzc%GSL^Vq+8}q ziS(dN^h$9-zb(J%VI9mb*|qpFd*o*IkslPhD1`-ofb#teTBq-Y=WHP^v28P8M(F_S zV?(G3ur?bO)1E)34c14_N@#YZ{Q{$eu$Do>N!!kQnzgv^@2#v=x(D70};j zXc|&yIrQq1mfSb%e$_0o6~9K0bf3Hs-bk;7ThNaER=DcVstNW@aZ|>W2NwUD#`CRdw?uZIK;7cN= z&&5L((;S}+b8=0>N@+0|dM&h|>Hb7j-S6`)v+L^$+KAEXLvm6xz+RHY2tpn>5}F#? z(gL)$k$y;CpMZWv(_ajLE9cX=8A#baSxp|J-Q0uDz9~8{CW~1%PZ!AyeFh1eCrfN2 z?5Op)DYxyRIAKlJjrvsg&_G7ovY+(x9@Zr~7UIx8H55jz0V@p&mSl9(VT6!iqm>O) z=r!eM;x%$c4$~gg^b_RpBy7q#6%8~U8rYq4i+r+xZC*Mrm(Ygq>P-g=XppaC+C^Z? zE_Kn~(9L1>F%9Ux0Q+*jE4F->uQ}Lw2}cB@vsjf4^l;GDNBYeW&zeie%{6hJk4Wfb zGgZi8mF&kA^Q@SY56O(57fWJBLWh2w4fA2c@6%1Q6JU)x?S%@5Hg?2y4N=f9L`fp1Dp~~g2Prh^7sJJ{fL=p!T~CBj)<;_jqi6v;@_Ly~vKjZp z&M4FrJC~;E6vhurWIgVOUA-N)&O%EvgtZoS>ynWphaI! z*rB3rppi_$E_|^@medTJjWZFtlRbW99<2#%hnfws6*j{T+e2+S;q_1pP1%Bs_PGHD zOVk3E4pVpNaV^n^DBpyc6+^l*&yZl})Aahj*q`f=8z#_42`!n!rk}&^MmTaibi=He z=SXeVO}S|eSyppqS+B-Tx)rzmcG0orZ7}=PH4j~V20AxgTcKv6)$gUb7QsScsu|2v zIHcJVRRM){mB+-;F(}&_R?Tlfhg8EJ*%51D(LFcM!=#?V_z(I9^`c$U z>j9(sV#gj(j5RGGbyF)^7Ix~DLcmST zQ*@7nB}&of`U=$F(53P`sY|yK^v4B^?{y{Q*W+hd=S(T3+u+dE!(!w z_1Zk2Y58Wzn*16HI_xagO(=AtDa@@&#b!NYph;B==)(%NRF}~BS73JHQO`*eWm2;h zQlTd-Q?Vnr?1ov_Yayw`p=B|yu?@DBw)GxA5Lly%SO=5PBIlqj(RPa-*P~!1lY;LN z_;fQiEXqbz1vr3m!VH%|<_+BW=Sd{Ck}4W?pVvaJ1DQXV|9R+OOqjdJ3WdxVtiGm0 z^h0}SKQXH$+Yy>`Y8YnO2(1d#bdGfa39U({8mkoXSj~ZJzLG#UBkaUM8y-1~ z`vw~C?6Kcut8zncuoPfbob3}5>jY9kdsW-@8gPby2O1V-C^Qzjop2~o6KtJk&6|w~ z-JQ1L+olz&zDHqAOVwmGz~UgwE0(Ylr@A3a-KNiXVQw^}dwu527D;47EZNC4Wu^q| zJu{S)+16N*6y2sjpw1geB!w={bV6Y7k{|nB4&BTYBOa9Cfj$;Zgb$^0GFs3Gt-!p; z!5$6jX+_j^!*xTVpxu;beaEo>8(`;z-Q*LYRgg4`dGB1jFFrD#kk9l3w?Nl9?6t&h zLG^iZo(v{fab`Wbo(}0Md2SZPs$9V+2R(0b5}^+__BvRSjs0m*^(FK>3MK8ak{7WO zDKT#@+JP3(9<0aYS$kHDu@OlXjTgvUvPYkoW%5`(lau5&`#Jp>BaIoluMgvnY?(2B zmN5t0AdsIHJ)xV$0*l2Hw&YT=X15L2RQ*tbZr%Xhx(qskNs}JQ9lvK$Is|iFb7Y~L zJM>a2hQm0`I^&1K5Fhju6!(ZeeYF_i$8t@_@K8+ZNA4pNFx!|l+X^i;TBD%^i_rm^ z$2C^O`H_K+Ts;$>(M7Ujx8s3<&2=_PVW~!71W?p?MUrBVt&z>JCyxx|ja4BT(0v_Y zd6`o5^J8=*Ld&!6qy47sv#s0lz|fwbqy;l&pO`swmj-rMJS~<3Rw?C?=(0m@RE`T8 zD+KGBbWg6ErGQ>TC$`7;(Q?*ZTaSnHVWQ~s*cULEy_>B9){^KxB@sGTO;bVM1Z+QR z%G+YV4yIuZi?jxw?7G2BfLBvZQG4B<@#k38oX{Pljd2@;KKB6Y&9OT*WfMI~JB{i= z(@XkwTMib(uI(Y&wzud}ZPhD##W=kv`oOnUIc1)N>2ROlF<;61X@>6*=(uA|-y{1I zN-}o&iarh)g@sMBsOHk5O=3r&g{IBW#+ZAAP0%()Ens_k-|krGnWg*13CnuJv5Ld{ z98FXVF{;q!hknsU>fND{S{$Kh|Jr)Q4qEICQD`|2lf?{qR6M2+!_#7(Z`eI|9H479 z^%z)FR=osLnhpspb^A@eF4iop6vsn->>386B-J0fW!+R&jiR+uM?9AjMk)p?Sq!a$ z!AMlKNk8fHd2OkOv^i=$?>6X%2z2REj2P)aY#3rU)hbyCOX9hl3DahZ!YZ@eOxqN_ zsLCtTHb`QnMa$H@ZZ-%U8AqCtpJP;wZ(v13oDH7$R49@hYn9#548eR z#}3`0UO=~~X>jz591m?2__DALgth><2>y$P$l8c82O`Am(>($^$rSp9)rwof9C9U~ z|0_1-mfUe@IZf7*3O&xLrjVKgU7}9Vy5gmtdz;V|**HgXysU z7poL&b45*|Un!6i4}H*Rt6knJ!PAE*2L zvAYu=im$|zv`F?--S;XgdKt9lCyWFO!Z*cYS}5k@qF58F7~!FvG6Uu;Ig2?IlS6UX z^nhdAaz#G%4~yyIx!I4kFc`)yEPJSn%3W3Abpg%hc36$^2@Y-R8skSj zMsKByq^48&8T*OpynMA9JTGTcd z;&uOa@tS6?VfNx4UBp;_O2lF^9H*LwEdtjY`^`uiNj*i6IEaS^EA7YyiHE)lZVc0N z@jQi{3_OFT&-ZAIK=cqhN7ssF`=R?;_((+k*gmJbY?DmLi-e^?-_)>*;+M%I{XpF{ z57e@0s3A9om6+jl&P;@U3R^IKk}R7PFbDP(iS=(Wj5^ek*cE3rlv%x~7hR-5dQ8)2 z>BrcD4Dew##?G2?KWwP!lbBJ(Zi&?%Hl&t{8Tv!{E7(YxV-Lt~I7a*UCc7#oXp`@| zr)F9{Vu3#-lW`60+J$)DFncLLlD&tUQg%QoSJg~?0zLenDckZ7U|+6 z{QYp*45$OM6`!Oh>5l$@Jc%2;WzO;|#d&wZU!+ZS$Y$6>NZvBrGhKqRbH(*A6q_Pp zPPPzNAcH5ChBJh*bGBF3)SlTjy9M^h{BS(yFR}9|$pO^+Sa|t; z{)L%#&tf!`4HVx|Z>fH^1*_Y8S!U}s#vCv?dR;N-$=xD zn;ZNbRt>N59{JpTK|k?dQH(sognFZRx43C0;!y!@^Dzc1G~DF)LSbITU~b=G#Pc8WctU$L*qtT`wy z@wdZ`a7he`mfvGbYML*FW8S8)D@ZTc%k%=h;2Mx>%obFgxAgmjW8@pd-=?4W&(oaw z$}gwO^v(EtY?}>{&%o`_SD|Cci46NP5r05V0H7<&hW>k{yKd@rp=7~LXCxMD2BxGTON@5#BeX2#>| z`hET`zv55ml39>5#hO2|EivwxIh!WLNNl6t^%_|22vvhwGW{*}XZopq=KojvkM_2h zaTu|?H|RU&PwZRfAUz~8-Lb#)AIJ~&vbajWWr}!Jk218=e5Uw_d}tn~Z9XI}>r3KI z`W<`54$x=%j{Ld1qbI|j85iI+dAm3#s(M||i-oYp4ty6G<>$pEc9D;(!D1j_j%qOT zHBE6f{b%xsPKh77zZZA>Y?@_H%z!*6zhl2e+Zq92P=I^l6rf;xY{53nukHun`v2%Ju z64&p~i`VTNlBr?WTVV7dP`~Vi_}z4%*34)0ANU=I6-)kD*Epe9_&4o^2+MhTRy;KG z1@_+TGqJ)>Io0>c^urH+|Srpr$ZfVXly~MBiA-^IY*)QcoyXk!>U_8Y`p={h(oOpX>;)OrT?I=x#V^dy#X~V4Vtg(R^aefe zU(*w=P3o}sfVS05+DZ2;O^FrVWx8Uo94s(CC`NSKV+|2&2Py4RjBR~gxCd(!wl1;Kp>Yl<>{0BOqxU=x2kelMSkZOg zGFYPsP2OeOvJ1Ju*{gt6Cb=K7WeuDwQN5zaHh7nBl6q={iX#SN;@Biub75T!HewRi zVQ9-Cm$GSk-4!+xtF)Te2ShTnc1kYjhhfSbGORt*fmpLd^dm*Aj-*Yw=wR7Otcyd; z0k;zo&7$qbIc8k3EwM^%1~g9Qn1isX*VLxW7ETUX-SpcDHO_|VaO##g&y_aK26$d` zy<&t+7+8WWMpVDWcuP0Jp#QF+VK1$Oe;}W^S#v*4q6fQgj`XE;KD{1Bc+1y&OYYDCK7Hb+< zp|O3Up^xQmz{xi;M9yG$V8V^kA@C99tE=b}-!;o}v-o@R_vs0l7V~;Xr&uSq#Jk}Q z)XZi2IeRRh#fSVJd8(JxAiHHSHsk}cN-)<@%PhLPVN&dcbC%K9_$90q4~T8`M10OZ zm&?2s&X}tPJ*k+GU1XqHTE`9~V!>yg2q3$#?X(+$CKRu*b_6>9l?m9|W8=ku#EA~xqQq3p zwe;_3kK3?6o>M{08|WdC70fPxRl=9~WPQ z>9_>S$6(j;_rv>kfUU;QDOF$SP58F56fsV`p8A`y1F4Rk%6L1wnSZbn`1@PE%Il6P?Pv~@jsA%B=^mhIiPLY zt#6v&qi_3`dSw3A{NLhJG9y(gG;}1=+X3& zJY+34Zg0|eu;)7piMUOEsXq&I0Tw8W8wD(X`mv&-7R@s~U+nq5cn+m}$)Az1i>P{e z(^qJ%XtJyFPsA`#ckDb~eFgsnn((|sGefkR@_{8RiV`+<9`H+@w!)s>V)^>E(Y&ZqjZ#Y5oWKSN6wzf$j;+Q~YT0es~+>(2Dxd|D*g- z_)IR^V|U;N_Z+mS$~$MQOn9?@t~Jmz_}DqFOV{ieJu8YZ&;&HNqvg?NtjzP7HgG4YmslfFjl z7~}jz{ycrApBH;^R}A=z`fc|fzgAT2e7axU^Uui&N}hOFPqkNyQB@6_{y9x-#~$(~ z?dF4Qv_K2SD+zmBu3GdY8i&8&(tHU2(u+ ztc(1@YGyj-uwGZ}lM_K8LA|bDQa(V3^_WA+*a6y)nP(Sjb~{|LJ?zLn4L@@qk}vI~ zT?nvxN19}UT_l(35IMv=WPxI@)J&@h8xot$aoq{gB*L7mSEnwIymMuP{Qe!)6)*R`WtzQ41?;hRQ+AE-$J+Q%&>YalC6E zn@8cXeyX2@C3O&*YCuzl9ShP%{<;han`p6?$tqpvTXe&3(?e3Fy?RK%4zn9Db@cNG zd^c^;Ewy9!d_`l|T48t7Vn0#$GK@+*b~lP1+oyZLl`fW70rSdVOY~5zjR^EMYQwJD zWxLE4)PkQ8&*9n-y8+`ia}>o-jBelB*lMnVh#n?=m~Z(1@h@CfiSFUnH-Ll zD_&z5MQM!7I7W9xgER#&M65XqtVLRkH7R!H2v#O-%ePF+VN6$G4T3fl&f$^`nsl;D zWYJ>RjV`e@vlaIAfjOikVa$cGS0iDMNK`CR#aI)gw*YDwc2otpB5-3q7lVza0r)n&}77VJ!z zqEkMG1+t;{AU{=Kb6v9E_et!SAos`iknQPhwdrw=Ozet7P880akU>6_TE1?M{gFPg zJE*a{0{0XOjHpdlfVDLZ92leZiSE=J211|3n!d)Gjlo$@-D?Kz8PU=ewFEhQ>ZjNv z^N>E4PcWxCi8a$LdTp;8bR)8d*UVl_Y)!7kMV@#6SKSfHwJ%}UfDG$#K4JP)MQ$ma ziVUlIIVHVQRCSw<$PqGZu#Oh;PBZps31;*WJH-aPVEuH64pVAJ{N>P1YQ=(hkiLo! z)mQ!t`N%vDTcoA?Ja&g1tY+FVj`M0X30R{u^KQ17HmiQy);U(=Bx+Z>E|?!gOTOfv z>Nz>>A1j=KBmMRaJL}J}F?%iz#^F#UM4?<|gJD(8Hwo4(33jCoQc)MoYq4ebc#OB@ zU3Q-Z^NG7BXYFwuG}Kc+W+v!aI+RYrBA*l3DQDCC8CsfkS)~JP)J&u^7^|^3np)uy zvx4V*Iz%!hm*T!@vEg_&o--HBIe}TTYq6@ujwd@J71yHu4Ebc(1q)+tT)`qIe+?y^ zK*{IkcKlL*#Xd7%spL;=ADM82c0`V=bH1$(z=K&joo3^-cvj5Xd`qC;kA*W~!k?!X zJx)o+J+q9lGGMssZ~%q)ms#1RJI8Ktd98YECceIWrk&!@4_3y=usg zlW~Kcx-iCjC{EnPML*9M#WGnFd$N%R*@PLBqij?SN9uZYgI5&Js0-9)jW*HtdF)84 zF*y<-E8-#416^^@jHqD>JFsko52Y?~Kvu+Du}s$qth1(l*CfMgLX6uXgEKn;XDrYPRNN6- zz8;6YL4kJ7_lQ9ci?nRWpBEFnE~dooc#lqt$@r!J6sr~+tjb`4)8Z5vA1q*bm3L9> zrt;}HBUi|}UQ!Ejomb_ch4oi9%ty>fpuESxdaGKbbAFMm(;a~u7_pa)(X)Kq4yty- zDG0P=^@P0+T18#yi)i&@7g{*j7L7y5*BLv)tHmS>?hEyd%!UW-bNj$1(THt4{T3ED zMLTxIh9qK>Ja^AfO6zo+VNXmPs9pkF<8g!zrU5d*dQ(;J(>1q{=IDyv@h1c=tM4;d zU3O!jwwHE^ro-&r)MB0IcE1~K9nMA5wgY8uh@Xq&qA8y1&*N?LG|sab{~+D7Gid93 zIP47<{iZKRONPb8SiGupNr9R_t0uLsey^sG%>wnT^;juolIzq9JHO$(SAY1Afmu;kUz=bV|>~ zN%|-}DOSu0$H`Gk84Z1=Rn!9Z{m~n(#Th=S7tEG~-92_-PEuDGQWN@uyI{wQrrRnO z$#PgLHYj#;#lC5H%10%}PGJD8dl%~oy$*I!3yc*kRtf}835XWK87WH1kcNeMHz*E8 zv_akBQ*lYp`6uELW=w~WaM+L)1ER0!lC_BQ7U+}r{F0bTnBNerpcu@`V@39=k#vS$ zifCI!o{7%7c?Apd8oRC(dp=|+jI%L6#QIa0#0XON_@3Al;E-y_9@Q6nif)Cz$qw*Q zJuZhrrC8v1#e&i$a=`$@iiv?E~e*zTA^l~;eCsTFN<;^xT%ao1o4kSDjy=EFQe%Vk@kod!%l>GkyjcZz)8O+AvkF@;6G zOtvtuu4h_!Z^TY>=ylkWWhZuzZM!YLtFRkrs-z*YN=N#5+u@WY#VIA(5{=Z*sM!=} z_h>WLUDJ2VzBEwaRJE*|O);hKtA}wqtgv;vq8E#0zeS1YQ3DeEr8p@~juWg^Vy=B? zcGH?!rmJMzoY1E0_T8i>_0wTD;@hSYx5X;L*40kJ*qWjqE1WYb`t(4+o($`?7~T1X z?;^bn=Q1otJPxB?+ZAB{JdUIx+A^C2XZecn$*rY*T2uMHMsMuVJskDbMKkph2wPl0WGH-V(>U0q$eu$8%dbq;W@rVONl0*W9iP?B6l$_=RrW zUG#9ABh&-7ExK(Zq5b3C0lCnalZm>kQ=A&}{d&ZVdFm?Ycki=1`eB$;uoEknG5=Wz z8|p-Khk-a~2S|^o^24-i_A`fyL%Aui>YCOBZu|Kj(&upgAm$T7eZH$e&uDffTAgCu z??~Jof)MjnS7;e2N&{Uu-Iod$*t5d3`hYpAlK1K%oaq--LDL%Ik-8|h0 z>wMYH7t3N-)O|n30?4;)6*wUhcOq6%)1loVDZ=Wr+x8WQn;LY$wN+d7yMB%xMtfqn zE#_2lP3&6G<61PI(ZDXI&sN;~0@in8Rb%zF0EaAAz!)H0FYhPA2DZZ4K-{&D>BsyN z_b4uVoO@=oVn!!jDTeqNF&=2@3b<7mcfz*7S+uZ8mc=Y)>>IX%xI@05;|wGjCKuEt zF``fOEPcQpVYah}aGVlgE!!W*;yHOX3>nP1^dUK+4TbZVs#{?uZ<|G*ft74Y!>GBS zFWP>$Dn1iGu^;P6nZycu_sEwL;bZioI7db}&d0K2wnf+2I@wSwW`@QvBX&T=s2TD7 zp)U@ZvxX_`qs#3$O&>elu+b}STOR9{8nzedRl&%Z>=jjaRP2X6gPva0DQcY>V8cF- z2w+3p4~Gl}(!8^DeqUC&hhrpUk9vKFpYUO}>^c zs-u9Y9lH6P|A2w|*4RhS-2-nht#tCAEQ+1StCd0bF zeS^Qjdc(B!_WvY*B|hbcbktr6*UUvqU00|V$=r267e6*1saf66ZrFF(+wu}xkX^b; zXZ%C^P*2f~*dkZhH?ZFLdb&jV-J>{zh0^I2gA`{wHFOf#O}XoiW0xN0 z=goO@hK-As!7LuL!m93%BYdQICwxZ^q)GXg=D%lu9zSNo#qaWeZ~riyaSQ66|A7C3 ze#XDRZoxsgB7c+o0sp4#u@B7;ekti{Z8WUZ8zf9^4!Wi729Hnzu}8;Ll2WM@Rg9Ulazypo8tO`o zUN?Ve&buY{m-4@1{~h_2zLfri{8yHzZg*dQ;y;d`g~#cUohs z&A-?$&2e!pU{%^(R;V3*hcD`<{E3+_PTUz?@Nb&;!=PRf|IGfb__3H{Z}Wdk{!DyR zVnvz#Jbr4XO^scp@6or#1>O{^aZaw1ia*2N5H~TutFfK9X%GEK_+5G}t@-bpKR5r8 z{#>7x-(!DjzQY^x5fA1bb}Od&jGtAz`V4v3zR$0V6Lm-YB>sxcq!zo*ZrUqkls1Ze zw&_;nyv7ZqqT8I8Z?LOjkYN@?zwjTLFKIO6{=4$`%}rCMv-Gxl%Jxz>KW8r&%X1DTtLN-|!Wu8eF8%SGxJoYiKC&0l zFL>NLXDxzL++;7EgfWTULF3js!I5l_vJ_)q0WbjEDc-B1@3;&uK8KbLm(?f6sv zX-Xu+gq;YtlrZK; z9XJs!N8K1d!$xAu?!<+F{a$;_$H^@@D)-oo`LdXEb$-cRlVhoA*5#7kP&oS=`#Elt z`0h|e&x%uo9_y0^_pBNAyC_EDt`+JL=kWPe{x)rpC-$%9U--W<8~pv^kHsI+vtp+B ziTo+Mtta_`KyMUB)n&rW0N-N|{m1UE+ms{pE&Yvf*>%M&x`=t}hB?wTi&g6aD=Kur zRNV$&Ad7ZW)a)?59B#OVm_gn9G^{2{-==Sg5n1tbdWNnS$GXelu2brxEqkJHR@7Gt ztP*1M202ePf^k8>NGqMFgSfB8`P*@nFJTYnf7gHQC&9_@x!+Nj?K=NNeqipB=VaGc zVvYBh@qlwvqRJM+SNyJ84&C80zm=}~w%m`a#fsWU*hdCuuu{QrbD86GnOn6>YQvt; zK02yK#Q+~6qbAV5b763>}J$Rc$>c~F0g&_*xwCL_$*qw0|l)W zW+Ge&BSlr?#Fu!aR%A0`PuE@w{o$By#dW`__YL6<(M<+8R!3Nq{Xguz>C;}fbti~t zdH0tjxbGxLO4MR4*OD#EwyZ#j<4)VLgJhD9E6H@DGh0p1m-{E+Ti1M;Dpc2eoax4V zn59zF-N@oN-XzGD7s-|kYoSO{3%Kv(eP6!&v(4{Zyq6E<>c3!$59+xWI5;>sST1&) zGe8;K(b(ONQ+6BMQEsWaa%4Buz|bAOoARc?&a>Vvj+gr_V<;VUD{Po)!8zt{734s~ z4TD=B730%lPS2_-*;ddo&$!!3*3V9)Be2qS@E)Y(=4UEMNvFn z?Wk5#Vjl$D*fh&>7^dZpgta7m8$EYLC4E`1+b!vE6mf5yRv3>Jn3K9e*$x=TApf`e z8P--C;jX%i-jT@}hm*x_)^sGKV8k`vV=Qj5GhxJ+!y;P7k=mlTos`V3TinqIBRN^( z^o8umHpe|&+fvu`ioRme#+Q0pwheY95?1{M?)#`t(Jdzo)(%`N;D$@lk(eXf>0&|+i;b$!&_m)I zpVgDRua?4HgB3t_BUWO=U?~vyq?=ej)84U{@&N%u9vb4K0OJ-vM`395bjv9Ib_#Em^e~ z7t^4at8l8*bdjfh3t2I?%?En9Tr;gWZRhNiK#IiBF2_51vFOEav4wBL2&ok|G;+8a zTF~Q2XF|*z>)?UumhZT(#)N z9CqDPM|V;SC5W{*aElW~z(zl!T9VHC;I^40xZ` zBAzKN5{7Uc>;l|L*h>6~J5|HUmBY}xsKbUEgMQPl_vRQJJ|yMIX5zF?23Sg`!E}- znOf$-)S-#a*!X+)`{9I1{}QRsHu7zt6nbnY8&Sz=BG=gX8cIB5SPnJDA$XH_W9ZmM zG|4rFkiEoT;}`^ z!)t6FkR~;RMRwva!^ZD14-_&R!Y}csH<_}w(UWq3AUQleDMb`Ahc01jQbO>YrtFu? zk1#XVI863$u!(*)?o&33sqq>66Ko83uoIokMdO!YV_wHp$mi3BsFBH3$CNWXLy7*_ zJr18?6vo}7kTK~=p~fMzE$2`6&Hfoqkj6Cd{3fWc{lX@-Tr=ny>OawJ!cdHaovE5l zn&jWu$0glB=uQ9f9yZ09Vfo$UPk!rraWtVah4C}zOIcHOn^ZHU#znXd-{eE^#*f^Y zLgs;RvuQAL$T6IJ@Ao60>`NSHKFXR#1Emn;m;K3}{fW-~p)(#)$Z&?SLBK5}xlZG@ z*s1EaJz{+4AURK?KeugzK2~G&7bp(&+KGAer3(FE6|HIM+yBmQKy(36Dwcn&kZ5V4&n}rb{a1wfRN&|&4HJoDL7&C~PlCR^ZzFW7( zaU1Z<;X}Mp*hHZ*-k>lM{}TVqyMaG(dG#K)ZJz{qDCQ!X9|(9#?ge$?{N%7 zhj8fcHnAvVgvp}~;!M`uk-xeZr-uJHjDjCwQoQ9oN)2tIZfZC|Y(0|lwT;G7#HYi% zXnDNJ7V#uZ${#9mDt*yPfEhp%3{fFpa*@r|5MSHq8R0H#SjMEMsq>LAb?tJXOBBhE zup3*(9lOZpYn+^3ij80ne|pouF+@+-u1vZ7E&q&79Oe-8roYCM-h@vOQ@_cUG18{3 ziOtmT2&^0rhiNX=wZ~n^~hoEF~2zoZW<#>Hf)d7A# ze#Xw>3}ThY1M(+4qM$e5nOerqIYBrS0~rpygdRd~!YB@E7YN_i6o?v?S;W)VIgntl zYB%v0@XxVkKC_)*W0SFn!u{M(9GN;%rktYu%+$z_Y}pV;x^7(spj6WI%waujMMHt(3^1Li}0H`$(AWLbcr{j zk>BM#-YBjncCt4(L@~gy7S)JQhod-iOqou0Wz1Z{1R-~0{H87QRl?8Q!^oUuN)|Ct z{iy0UQE7O|6f<9x7X{L#?)hhGnMQ+|UF4JVdhDAq@{^#1qc>@ln=ukBb4wUhat1sl zR$#4ywQ?xJ$tfe-*yOO|Jj}jCO>a^s+GNJDk*$GJIW#_HO_xeMhoE=H%RCS++1w_S zu(E%~Y$!GK2$%c`PGOp`+4kE{qScse&-5L_x;iHE&2-5Be*EkrzXnS7vUWER3QZIV zN+#1ByUADAIN6t;<>tSkJEldpOpTt|5X1pK_R03L_Rqd!3Y04HZ}=qtvJN|jlAH2w z9E$wNO%VDMMmG9WSPeYm5C?>npG^p&LU9tbDfNs+u>1X*(3wM`tv9)9@F<)^81idE z(wkhFW_D#eJ;x?vjNNY2ZycJa5cQ0c{XJaN0(kgP+!>m2%1undZy;l?GPJByPQE2@ z=uh_M--Pt{Q6kub--8@@kOL2L;6V;N$bknr@E`{sO)^DeO`;x_k4Xzyga4@0hO8e4ulK+8G| z+59FBg(Elp=}GX$o&B;;_RV{@#Df8rsl$++3}K9I4SwU3`OdD4+oXgrvl-JU@1sRf zUDMD04tDyJ$uTy&aTH1;jlNDn1I@I{IuzL{bn`B2dv<3$dXCfWYs_(uWE~NAZ)r;m*}NTm&f*f;i581aIt3TF58E$S+eUYZ%!Z7~$l9S<`Mp6Gjfx_-9%a zGr|2P1-}{I)lgT*NW5no#gbD(?*>lsWkWVfNya7@*|KX4BhE4xIaKz^e2n=d4jN3t zrx1k#^E+b^gs}WQDB-ypGgBacqVH=M{LGLsw5)v^cgD-O4gNTE*5xAH{u!2O zHsJ{;`!?9*Z|co6TaVcW!U{s2cNWwP3HwDg#mwplRd|f?K$=1vM*~a zqMs=ecD7|s$(~DS%un_qJpC!$9Fk}?HVWOukg3us3<^aUW&LchT}>-L370U48+tck zGj#0AHVWhKrIujhFxk~mY4U_9j}5sprLu-*`)@xRnhh?|%rJu!P1#P*vW7Okx2g$8F~{W=Nsh( zL5Tv{i5@-4p50?xj>Bx?m`%L`slzYNVj zCBpknJi;VXZoch(X~{m#Q`Z>zL@uQ-!*hy!?V@y(59I>U3AH`q*_^+jcgCU+L?d%_ zKebGk{2R_oU=p6jQ-V`6^wp^PPj?Oo)6}pgl&an1ydz)23H6h>%a9BuJJ~W%zYWVi z^ehoBr%cz_6l(07?GBIXnJbht;l6a?zpR<%_-of zGu_y}moRkx~?V)psZxqn!DwZVla58XGtoe1{ z6VQOg@RfOJdvwS_4jG6Xy1g`H;)huaoqHrLBO*Uk*SAX0Nsy)GSM)Mpkv-!$ooq3Y+lVeq$lEbQRoNgq$-gs44lZ7YSpjB4GkH- z9N&2aFNg`;#I^+$34QcpUTmq5vktNh3?wy{E!>Ijn>D$@mlevzB29cXt?~^4JqbGJ z2=4g`P)Y5wnd==Hrqg6{0deH>(){rzdq(-82 zB&b+OzVp!K%C@GtuvKic^I_gi@otHG`2snsR^%E=XUQ*B8xlAE!%DTt7sVQGz>i8+ zkc0r}QjlEjj)&bd;z&FYx1nr@;iCUIoR61E=u}}#uBB%Al$@1YIX5$ASoGaSxnyob zGSqU}^U$J^I$^rpQtpm>_0vj*qj4{rD0})AJC%Nu&Zir;(yNR?%E(sJO{n7rn)uj) zUa}i;)vlL)%~G2ohtn+I9}hrA`}16sJJ_1Oq0X0(885E61&*6(4ze-aY-FLQSHmh_ zanQ_admc5;wnRrw8c0VD9nOp0>T&tc*k{yU$sh;rVtS|gMRiUtF&4TBy4ltC)JBbg ztjq#Zm(yK6Fm2yGJLgsSZqVBJYSwJ->`3(n|eb-rfYzv3%M0{ z;TOuAp>iwnPFzCU28nW_Q=p!Rk?Na{-3hrGU)Nt%4|C{FNoV~j^=k1JBxX(+Nc}5z zgnf`bv8=D#%i%V^8z7A#v?N*$hx_>w?W7qLowQvYw|}g^rcR21xS~Gb?}k^@FT-uM z%|n*5-xl}8Et2%GU9dOpT?0MStnFtN5RFlRw3)5rKT&$3{P#dE+9Wdj_iDKz}>$%C!QI~;Yu zZ(#?-3+cbtUyl#5>+Z+ZYw8vLqx25S=t%XvdBh#$TO+dz`Ya^oePr%vNbIR57$k<; zIn>-+@tT8%BYsG|Wd4o#rhC-hvM=*j#rMJw_`B6zenfvUKB14>ZH|S?o|VvX8n3&) zB`N3J?kwk7OD*^tXcuP9LGy?Hzbn2`J|wTkmsOD8iQiMF{9Sz<`X!$Bk6O;4Gp#r+ zejQJXXrww7vl`JsJ<{iyl}^@{zZ?Ab@;7x?4h zc(K*?_<}f9Mte3vQ@xljXUulHElw%sppivR`90zf!hc(SEuJtpt5=JksDD!5b#J@t za-VumK3zP{_f#FT!Oyd|`MdT*eOI^3i2@p;)mA=ZdU3%I#dh^Y{cq&A)Kh%TzAk=N z{>XiY{h~~9Mn0=Q=N_{MfXS*#oEGo6_YL%r2uLW@khWMtTXbBlHsZ8=Nc?sBwtdk~ zmA~RrEP9<^Vx&->$i8sEffxLkf%yd6G3T^Lr75~NA{Cgiz$ zXx~gv75~zI6FM*Y;%D*u{AEa@`i(ec79rv7$?~~yGD0_k?TOp`3Omi-hm@kb=$Yo! zbOFii3~~hH;qoQM z3#OL!WqHQF&E65oRn;I)#(4(q@csq=uk>HVZ<(X&MtIHqqx(Dkihb3+6_VYs&`Q6L*ubXQ0o|z7yWG??FD}QrWWH97&&1-%x*L|B8Pt?U&c=FZe%I-;X~@KMilO zGwe2>^AGFKsn4T!9*|o@S3!4;Nd8?F@x@+2`SS9Fcu{;^|8e?#^`zJW*@Uw9gip3Np@61_E_01*5l2Tpl>R)=8>SK3Cei+W1+o8{)@vq$NAS;`1Ra3mBdwkj4wac!j+G3vXG5f*YF61b5Ux=RS zyB_NQimdbvcg;d7tsk1U>BdgLc)+wnD`JGeFfxtMDlQ=fzQPEyoO94Xt0wB6w5vJ_ zeS+RlE9G6jWY;+42YVQdQ3eXqY4}hKSv{hy=+-XA7-Fh|wB9ru&=Q*&3wfuy9*LqI z9Y~B}!51`YMChv5&hhAt$Hk z@^(W0$$@}A46$L>8MG}*aAY7El}5J)TDn<%e=y;;x+A&FQw3y+X>j9aI8wzSxy^MV z%@~G!;E^u^GDtb(OS!dTt%Rhe0(qm5Hx}ul@lS=(pq?~S4%!Pe^cPgndaJ;Vg1jT% z;uv2fNIoWhR82*JACFvi$mQ7MkkG8_TuvC9GSD&81kVYrKPXW2Xe40-&$X_y@0_9bW1X9NOMK5e{ zl(}Aa>jCny(gyD*jOrrg4@QQelfaLHrg%GTrV~=-YJOB#bW$rYk8wc->E8u7DmD^k zK>>N=AOlSGHFC!xRlHTSOXy0}6Be4#BehRRRhpEL5M`mautd5H<{}IwCVFb4s;My0 zW4#huFAPSi95WI0-|dK5l|{+~Bm%lAJyk(Ewn8q;4o9jiDfwQ%#P*M?j zV<3e}*R{uCPU1J|q{#}Y<5T4%n-mzkE0j9&5Bbc8p`UuP=QiYq-Y6kcs)U{mk2>fu z=GBnv<1pGakg>%fA1Xmclbb9i{Y2=BZUq@g2_tki(t{F`l`4ehBr^-N0%nPd1n-!2}#*innB_I__VTP-R_yS0tGbkw1hSzuf0wtu77T404;YEB0 z8e;-JQ~#$@*VkXRLQW{mbbZ}A7}PZm9_*k*J}Au2BF4J5?eHbJ2|n%T(l)&#Y!~Ry ztF|44)pXZGrn6cqR@ACl-v^k&?^BgfkjQz8@?}C(Pd}_@TGNN?@81gIkXcMFZau1kRg0TLI1i%i*7IS z3+ytDNY%PQ{@b4HGsYml%x*K=IW!AYZPzO?>$9tFlrSEXj}%Xqj|pM89mz^wD$c13 z?rM3*EE&v`71~DuebsE|^d3j3FM5I|6j9#*g?1 z>LYcrx|!~>6}1vEvyAJO**Uu#5`5{vqdxTPxx9T#zzILeNvLws9=RLSC8{8(KUtAgu??HBZy<1<0T z34WWM%)E0Gyj?Ju~5UvZMS26MC2JsJrH}Iwvldi*m9!0@<=( zcF(IPihX*-uBQ*;d*O^bZ*C~ek=U|d3QMksI=WpQu8x<-;@)biT47hAo$Z{xsfTV~ z@q~QAenmVhj-|<1rH}l3<*D?sxf-FpSS-h7d{gVHrMK{d_P9R54~BWvtn2oZ_;I>Y ztVXULQD5XQVZ8WQ+-8@R!1ikWPFkw$*iUx{C7caMoOux8q{K7i~y7`E=Y>9T6wQQL!twS;fz} z)Ap>pf)-ob$I+0tuO}VHC`-5# z7CP2=yQ->B%=`X5^O3t_+f1Y{gx?Q;s9y?CR@>u(IhB5DUU9F*7(NU)CBm~Al+;0f zTs~Yu!=aeO9ORsPSHA7vk5|Lc?SaO@-?vJCqxyn8Ec^Du_*3&E{<43=ybmepD`J%9 zBY_2?Jo>SjUf9k%S zzFt1*C#zG1SO2^E59U9sx71BJ#g3Rq;#1Yr)f4QbJb+TZ&CbN1$JgBJ?sRe6bort9 zwE3F-bM;@dzrcKGcTDa-^8YpdJNJLOpRrqM#tGD}C*#xXDfYNJ9H!Aiy^~(8UiQ$v zi!XIn9Wsxn=hUC1zqJ2a{Sl<2Ue$jS{%8Jg`Trq)R@}wx5prAQWAaJ!w0uGzmR)f% z{=E8Od|A9LuGyj3s`i?r!1x{im+oJOzfhl3EB3qUf2sbh{r8CfW;Ivt3x^^1{Av5e z^f`VMqn8iNtM&)%7w!zZqx!sKX3b7}f`8urnf`147y6}Q%KlO~`R~|&fV5m_a+DnP z7918|uuu8@MZf&m|JwY5Mg9@H;;^b@XWedlG(N&VE5BJO`_Ca)b~(N(9RJ_!e^zfp zo@OWPwMYEp;@R*dJE|tq)%c!&$GuyeW8YreyjL~d#T!Q&e*?I z|DOFn;x+UOt8CUCkSB}JtIzop7(Z72gYuOBFnuhp=o{v4f({$IFC7pE#bNb={j=g* z;yE#tuj>C>{tf@3KCMYY=zKWFp7CEwk77k~C0>jlR~JMwAG=HTj_df{e4pH|=i~Nx zBz;5wxqrzWv>z8gkpF0Z%wI3gxJ$)KDbi=zbMbMpO+YtC3)N}+iMT76gQR3V zDZ74~Kj@zp-&S9DpXIac9jp-iu=t_=2|sIYDXu@8o-RL=4n|1s*Gtv;@PRm6d=&2} zXmk)*u`Opbmk0O}^CkB$_)GD)UA3?2SJ+Q@;BTdiY+atPpOcTvW97Djp(njnoe9+A z-H3gR5xQ#DVudsCa+f*e{;2#T`K+2rXXVe$8~ion9!~PDa;;c$&=4g)Rw+~g(zMJppGS*2S8#c-e8T*B@maB7wbh;Sz4(gz zPw`E5tL!0t2a8AGyVpTGEL)1_%vtq`xUQD?D(k4NcAK5nb7~(K?8Wk*#gmc?=pip7 zG(NwaK2W#RIy4F#Nsoskd?%k2thnw!Ngs(z;+m?;o}4M>P;RruZmggjP|IqYI)>GcgY2l@rCQ~Jz9z47Xr@)y?ON!`7Mm^i zq0c>Lzr_F8eWrkJg<{#CvEN}oVQ;%r=|URu-AXWM{Qua11ifzb!w{9}&Ct1SER@IDWr;i@z@4b$1HrAQ$_@!x8E5kfkrys;lly^^v)d zF2$Ro$EVm%dAxk2RPk#ZGP2!)VkwZ|I+dA3m&{wmtNOL@mU_>e z)2nWd?-ED!NpUh9w!E6u8`TYra6S$f)OEIovHP?BG5J~h`QmANBy~(L-gc*oH#wH6 z*}K(8{%#nGX|@k?#g7#S-R^3>WcW_6`78WdwP@DOu7Gu$cv3wbkJ{as#V~QZ_%M73 z8mG-^eyLiB8?mEz@O>zYyD59@P<3Vnbi6ps7xL z#Lk-Y3OdHZs-JZ8YKPbnu|^*!P1|q8HMi_BgG;+XahE()9;$YkxrBL)S@zfUwQydY z59j!`06o@zV7q*-nAg1GVUA5=MmG!_)hG<(mTH%yeGX_Y<6BI(>gbJFnLFybx*9L) z>*{hwOaErB9zr{k|k7~zWTGn^@ZGMYikGJ%l zVxd}-1GEqme%jBnnQDgkuUZK!5@8}?O({ZpvxDZfs@{b&{j@Gu+)`1c1;4--`BGd> z{W#82kQ2IVutuUMz)y>#^dzln_1rLG2PO37s$5sJjF|&wEIX=GVg)9(BD0+cDZ#2;v^YvALR*nwVMSoSEDkMJol=Kk z4zCwo$IgVVhn($_X~-*gOk$ltq735%gU+V{yR-_sKn#+SE%dmn2@W~ud|;so7h@F2 zF=oAL-t1JEi<@?VmX>d*36$UON!@vb}167zs8?0ieQN+pxZ;3hH_SiS)SRL@|X5i6F zS6F+HErWd$4vjQo-Bzv@TX1dVorE<@!>Ud(p;6jutzvx2V%LjfcLr2xcMm&zk;Q&$ znE@Nb6^T_4)kjVu6iRn0V$Zec#5V6+0_!pi`e)8tkuZnIB@MaExLN3q0d22 z%a&hLkTb4ny`xn(qbzCBxecdJsLU)_7YFJfthBR_dYFjoefL zP3i?p(19tzo5H${!kR&`&RX;hR7?#E?9197Uza1Z>d=?7NsqFMSdr30)$-7QRX|2K zYsIyI7AUke))dVE>ot=MYbdd&AyvM>{wv4olcW{pVYR~7%06$YjSA~t-j9+w5yZ>nyXM9lcsB8#9Nu@+b1zQ*O4JvJRZNeS@`zL?tZ509o1qm) z7Fr1 zWtmXVc*|qmFS3L`8G0i=9I;pvbvi*J{a+|*GqqLdnfz@K3? zx5CP10<;1o0-x0`4qREEb%`|w;c%p}LY^_ac^wlysa~T*Y91(`$rOMRPm~YH`Pyah zCS&2UwXN|bm%V4mPJc=lrI6BF)wT*Qj=Z3JU@)Q;VIvp01q{7;4J|g|vWAl%`AGN? zMPHkUXQ)liN%Cn-#t55y*v$|P{`j434%`yI^d!!6YC`SKevMD|^P3n%x2*9?K+L_o zae<&~+UJ zO{Eo1My0kM#Q{gHj!1dz@lm9cEa0V&uEW}V zhE4fyahKA;HvFO*#O{ z(g;0DKa3LE8p*U#98)l{H!QqY3K)>FH{X|yo#ZG+ZUb&yxgL)(dAWg9gH9C7R~ z;)&L`Y?o-yB=no8cG1!uz|h9`0X!jA^fnBmD%tlNYQqmo?0Lw(8ffg>;5p#%O&Ftuc7%3H10C#U zuGr>z*ul31oNcN`YF#avN>$=EU$83{wZ0fewDJXVkhswU*VDa#+7UZxR_t&G*kQdt z?2~(nN$|R&Z^mo-62C5Q+lu#iOH3r}?6?_+F`gb0b+KG7S4(PxGdq*ES!n9hkL#m; zKid~kkHbxSO2j=*g?54AU6v*hTCh+;z)g9XZm~v&GK1Cmu|X zrXy)ju@hsk4R^D;iWQV|{8GGKEtMOp4IbtTq*g%hl*LG{Tv3Z|(XFI)jlCZ+o#yp+ zxvM(F9@PipcD0jr)vCV1uJWt=Ty-%lsFk>m@|yMY9{bqEtnOC*u#wgnoo`z%HdNn^ z%oOsFvt9AHc*tSpOzu#vxLjV-SIt$Gu#!;4CAW^U!+J^yy{URmO`vVS?vYrr$Q835 z(1w7&84umb?vNCi9d2{H?6SUsMs5#H+1RJKRYDuKz?e%-l{oRCX3{k8N|pwuFQDZ| ztw+?wfKjD{o^ZL_>~@^br8(WPjIA=-0b0O$gay8mkb2t_Ok(^RF*_^T8a;BtIE3L{ z;#=UY0(Dejw^2=M?C|laYD!E+YWLa|{L`T9In2Ans$20Z5hvJ0k7K7&qP|#+_anZo zKor^uqZQLN69$@LInJdr=#4hhVj{L2q_#7he$&e(&T`77xExj^_|h0P3AC9SR3vC< zjA~fB#5bqAc2YwFu$;GBFqfRMQw6@mh_ixW&8`@n78FZWeNr%Ol$ZyiPBVk{NnsSF z@vK_9?a_Kx7~hxBYizcJEgI(vim8NDp|)?hHNL{I&!U&?vRw`9x|jOCrh|C!-3d_P zFdpMC)r}KsI?k2Qfm?!(!+8lo?ZU9=xiyUwoo2}_rDd~f))kHWh8$m#0G$GKB+?YY zn@39+y9G{|YG^hVTMW*+@~N_;aO&3e*gDZsOC0mt08OiMqw2Wt-qgPfU5^B(!5&>z7Ur$dVkt#ixr9eDAe86YRzN+-l1iQ^(ujF2}%+Av<*aa~ERDbT#tYpdIHM3iZdJr4cx{A+W!ykxP77Vx;a_iB!dw0YAi% z?G~6bDVz%6(|X$CL~+&C9gWsg4Q=0SNSrCQt8P`|yo6mh8wr#cP81htF%@!IqxK+w zz>&wiAmXpOrmL`X?mN0uwtXuyMze@P)i?dJSK?fW!k?jM6!kuSzzCLu5^v>lU4a znrcvP9$y+!b9hH;`H_|ic8gR=e5oFNLd57>qo)aoNsc`J8g}Z7C@%UFehK3dzrxI> zLhTXtxZGk~PJSBy@mnLTf}0=|Q+|`1xCph0a79+#<4)Ch4p90Vgv?=04WVa-(vw^b zgy3W2YI*^5DIO0)vGJCxsb)M%8QC(7Fe3WZCQPj1M90HMf5IeQ8y|9Ic;-U?7C)If zr8$QseoKUDcy8VVH=9s;XLti`LX1Nb#f(R|L_6b*>17%Xh5V*x1J7@Ie%eMZqL-nR zKMjor(!@dUCN&wKp51)bm?L)X3KXaL%nU8EIJhGMbGutUdSwk8(m2RdrrqR|8fMuo9gh0$@mZCVvZKX#(*xCxCBk)B4o*RpHHlt7zdF@9E4{BCLm zuJOeyoYiGL^wd}@MX!W&M{zE8BGw_}&|)1htQ)NQ$c+2! zwJWT_pq-lZ=vf11WJ z6LO+LzM;3L-gBh827P~lb@mb|^8-&>=_g`ac0d#3`Vy@aNBRWlbF}}ulh6wDc0_B( z@H8kr)nedAqh`sLU`0!{9C9JRufj~iVI+>!AcaVMU-ZEJ+oFP>Ty`9IpH{xlD zQ9_xsfyF5-kNnYtI0DBwgH?_MQp}L!Wgl*w7PGLsKJs>CXf1h7_BoxN#7e72*-6Zy zR6q7O`dNn_O$|_cQ1-4R8N;|PGLQ3I7UdB8;1Vf!{eakuep(Uh4*XfnVi{JhbidrN zboQ%lrr1mgEtJ)q!1^qka42Kh1{D@sC33wSra{~YICaHgblr!if$clYLCw(28Ln{h zj86xQNX2%$tJo2?v8{eKVyC27D>vj?!q~jnP(y+J1>F}zy>3^^b=OZ!cCdG`Q_xC0 zPL@_%<5s@Y91YlWizBt-aT7sZiB&PI+Mx?>nA)(FxaBId5_<}(ylh6cO&{OmR<}ED z(_7g7_=I`5nsK9Q#V-i#p_hxkUE(~YMnA4M^c{aY;VfEOi-Xun6A5L-Py&1u`*s^U z6!(Qk!WYfsdd}RA=Mzp0#ZTO-;$gqtT1=(Ry~OoNIn(YVaV|HDvX!J zKy}^0ct}0VzmcAd-Egt|jsBJXnK~Or=8$<9J55_dN8b`3i?bHG%f+agW;|>W6KW(k zFoLW6UAJMo{IEDKzoP%E@~PBIAB119nOiw!-=j>r?{#qwYBC)0BIp8UCdS^Xn_+s+kFR!_N;OjKLUmH2D+ zPW;ecD>mE~dnoR~__8h5b;Ym6YYcmTe7ikSJu3b}{;B2Vg(}8Z?RUz*4>z!%SX56z z`}9L)*S_n2RpI=*x#~voKygg%W?N&YTCrEtWpyjA%IRXiI~Ja||C4$a`E=Gr@m>2L z`DTaV^4-PJ@D%$J`<$M!=gkMz+wl!~wpdp?^xm+K9g;ivs94~)!p&mA zGq=+pWU~4n&0~7fFH|3h@2I~ie~#KUlMd_87cZ#ehWT6OynR#rT3!@5+h#aF%nq9^ zv0b6&A#YdQWUQ%S1^rpG-*&=!NbD{9fxc2z zcI3BO+$51()2zhqk6Nm*d%$P-8}4-`o4Ny-zcvtW{%_biV*wEY#6%p z?rb`5E>_od4}BH1->U6;3tF(A8pf_99n;Uduj#FEr*-CvHLG zE}7Vo4nmjogk^Ts-jSF2^>~Nh4J!%lhNt@@IDaj+q%C5reMrB^r{nIDr;2}IKg79% zgi~le+4YkgyQF-Jn2lYtVHe^}f6L$Gw&$M~$?Z`(ZK z3;aNQP~jAZ?TLYz5qr!wH;-=!J1Ta?RrVIYDQ_p7!b7WzbD$Rcw04i*Wl!SV-mE=@ z6^#XZskj{9_h;0{?v`8#y)+lLi8<`sLLak58yxS3+vV+aTi$WY`1VG6s@xj(*nLWb z7u23`#2r>F-qs88j61D9l;`Xvw~)~LrH?s~IqUfTv?1@hb%2%AnP&ed)TT$IG6J`WXpDNnP>X^P>lgm}*7UHVKsDaOv zJM^P=cRChN@Evj{&f7(`5N?U{?7X<*F1TA}(XQ)}onSKz_aITOlcrrT)kAH>Npp+c z5i?)z7F*asyAN$LuVyWJBC{fInOp8gxDsx$s#vVn0{Rh#*33<@={Om?sx8p3p|3%2 zjh-5}P{VAoJ#Do!VjlGdb0OK|SZPp;X~B{v=4H1=Ej(ww<#3i+p*JqETM{uoP?*K? zw#QtUVZN9!V+@nkMAeaPkDlM4H!EUU-4c@ipAGqbGUKnOo9B#mhn8|AZlYMzS-J0 z<4}CWM*}sr?-*n3PgsQ8U=wBf6YhWcnSC=Y!uV~|P-@`WZT<^*;~2u*T=pZ^CQ1$u_s?&hO^w z?_m)nmrE0lD30y97Gw-6LBb!0F0qcSaH@fPFuuj;QDfEEO)#wdn)_BcH2nF!k|Qb} zCe}5Z;*(hG2pGR{)Z_}|M}=C=>JXY|RVtlZ{1*YWxGZro5m(VKu(wZvZQ6L;ku>?bttuDeG_!xlkZ< z$yi;N1ab~}iBW%vkg|pv#6_V)9g79Nsogo(h=1adTn#5=w>1~^RJA>)gVJ9CFLTrI zpEhZeFNKVC3<);E%Mb@1$(}<}`m#?0v7kXQIXr#Mqu-=PIgvvVC5p4eo3JQll=g;K zRns(Z6O_0h8yUa(COReHv4&7RB1p!gk|kV%RQK5lLVpTFF~r(MaS}WMCR>?<2!0}< zs($-T8_^7il}aFhhQyONqR^_2JKM=^fLDO4oT}_!!i8E5AHB&bwJ|w%^7Aw+0)((B z76V&BT;U(_w}6!}6as!U+p1&mwO@dXa6H}=vWZz@K2P!Fd<>u{TM51uuqhoxOQVk} zTP0i(?i|v!G;9=O%@y@R$RmTN0amR2C?|o@0@YU8X7D43#TQ$mH7GGVz^aDC6WJK>Bw|7C!={m&5$_7|Ak~P^BP4|(PLO`=IFjAqS;1ez zk8&J*VJ=?~WxNTatnnCfnOZOS!=201)c6!8)jSYoh4LZ@@f>UFgzdnM+r%MPfFWMU zUV<{mNJn7JBjH(*9V_7_Fi<8~DP~w#a99zKeT`j2Su@Xf z@FRAg-Nk1ZW-fXmU6hHRH<#sg%$`KF*4c#R;&0{TjI_7c@>I0k%V& z)Q?w>$D?e&nl;^Ofn5k6`?KL=%t$WAg)rpPajWBOH)d)(`E1duHslIMr+3`Vv>4aa zh;__V#N0ma=Eu~D;&9p_=F3*<+dDXwdBNcnthvUnr$s(_UY?n=!bJcc^^$D>>&&Ubi38S=Lt!UgO63c1PViYT}^M?^6>R!Zn zRZhsZLf$Hvh`tgf*S1}W{R%M=a30cNuUDh263PvJBY|CIK5`g+Dy(F2)Ej{jX*Dd+ z>l)M_szJJ?+o2uX9y?Z+zAx-pD2ze_jBA(ZCk?)HiPB`PgxV1iro{J?5Whyh%@7ZR zTcB3Bx&~2wO=vMBxM28BE7ao%-%w+ix+RmK!BB@P>^4*w2Xmx~!9_5#bEHtz7z+55 z-m-quy97j|hAQG7f5ITBfw8s8Z+d1}wvmg%^#Z2LvSo51;_ot(Q-Ve|It`6V$=XdtWxQ(6g z8beq)#s;T}i+oD>jp5|eP|fc#=adIThfQ;lwL$(FI`dB4fA5ietm3~R7VU78Ios;~Y&TJ9dT9KH!f9OaY}Z3>Yw z8~o-yhBpv;n|t`#pWK-PvXP;bWk})K6U4f!=+4q=tGn`}*( zG2MoKrq%f85ZTWm)cuC2P+Ak78nh#J8hD?tE8LJ*gV=Rj^{%i(%%XO*a3&NoIqYh> z#LlrRam97q7QS6z?Ss#jGh$Xu#kQnbF?JM08-4$3SY&Hc|%;6cM%KD;n<#EHNC1G=F<+jE6lMWT6Od+9Cxj%t$r#E$^})$o}F>q)hx%! zTz^w7+YVNWcc@u52#{Hz2Gx|@#vp|w;2cT0?1p|S%*E-%(i&e*D`p_3)Hc4|&bfBl zuzT_`ICslN`62B}rBqmMEJN=Q!mc4A85$OjqGfb;4Rf)lpsF z(G#MB9K<@j0j&Zjw@Szl^7Cm*;motd-btXH_BO-Wrr2jKJ85ulUQ95o-!t^Bwp+C- zq+TJ0NIM3Ik4jBq+@jGFR4tFa9Xk+xhW!iOwjGBZ5!Data@`G7$4r+Kn#naoYbC7c zRJb)B+N@u!s0}+R(IXT%Eo*Ud$+k64z7>;dWS8QiS*u0{oLP*JV?5)=(05i(JRI!oUy8L4}nYfnLgXRI3`AUg|N7VPso(Q%7Qd#j*;gE{Z8TS+zl7 zSm9K890lZ4XgQ1`%8qCoj5i9zEGOM$=my3%P(RiMP7W)`k`Pm-!&`|)SIlD_#o~Nd z>Z8AI6d;^hAz;S{JhY28zLEih+<}1eGXXdndovn4BSkN* zhm8^(>JD!&`$h)1q!=4EQPV71`UIeA!-fiAa^jHa=_47Uy_{?eR9Hh zu)rPo*bgY(h!ZQtq(EL`K8~H2&~=>(bQt2d7(dGnXoF5<2IF7XR;>W;0*wT)^Tjc0 zi1qjDYV6pq5W7Jwv*0Wt-qZpWjASF|aZrg!kHWbI)pEe`7zt>=OYo{GBy1ELh1LkI z+7-ADfCEzFDvV4bawcItFSJXX28l>%!fF{uS}W|N70Aytl*ri#{!5HI9a3zuJ{yoP zkz&F=kVHO-mWH$e*@@uM4-Je(Dk9n>gAql-D2cZf&WG5pYTNqMUP7t^Fu*7F<3I;H zSyT!oV`#%H!l+IDBU-K!t8*47LO50tQ`h4phDMDl+bC7+EXH13FW1V|VwFSQR<#<} z818LQolrIBq7!lJ!pyoYYP;W+_L)QKFh5{9>*%}cf_p!_gZp})@auXh^!!NRR172R zt&Hm}YElmLqP@;<*u{eRz2d3r1@pV=dHql^?QW^}?OWBG>AjTvReM`3q`P6AcP)2E z3~o31Lww$@rOV;0K3#l_TSRMmy4+JdlAd8-DqgV9mM8SQy6ev1c399q=D$j3+|`KN z0&33gQU^HhH`ycAE;}Vx^ksIo#Qke=2_x!hcfdczzFbN3JLNOx2y*qhcqjf;yi)zd zyv0A1H!OI-*|h!fs65F}7RUG=HHlW^B5tU@=RPo(;z}`%y@1E<7wwDTrSP14xSUHB zc7%Sae`H_Lzr?=MP1`fm)%JA29pNX^adSlPanoVFxE4P0r*LQOTv||_YL9s=eL4QF z{+jzTBnxb<7VUfbHT^^WvU($(X4m|Hu98MYRRPj5g z&%5CFTzs+kUH&`nX?DOfeW7|Iy==axUbSzfPr{<;px4@Oj;dq&xI5zZ@-3*1mAs(O z=u_-0zpPg6j6I~DWG|}U#jWfwRwt`je+T8|wSj-=**J zpX;-3(N3m4?wEO`IH?{g4+qT0GyG1ck?URq{&ub}ODr9=bA1%Ap z74Zh-fBkLwkK$+M1HPyx`Mx0hN&YZu$-%Uf&&ZLka6|ZPdapdq&*>_(^xpCj^Gx^( z{~h+C{CssH&Z-6ej{On)`||HuDBu16*n9IYyKehV5O1khdlhOgvbcb|NNTyVWLvf@ z8k?Kn1Kx8r!cA#rk?bSG|fdU|G({vnt-J!hs*I%m+QGjaCdWG0DYJ27m_vZKX> zL{Sn&iGoE+B*hKfw_@=YYhT}d@GhSy_sm}~hY#o7i~GeFUjSe1%lC_LjhEyw-z0a) z9ey)ihqyqJ3MKM_Kf#ZLBjPl_j#jeIZZ`MIcZWy9!}1}v+l^#(buPSMenh{|e@tHD zXXFCuksHi5w}V19(hld{s^aD$!+gdaqeu90b-~WW8eMDeBKM1j^uz2u`2%vBrG7TN zX`YdfneWr5RIpbZ;lpu@+TpevM%Q?1p=Zs{U=Qnbc1#=%Cvo<4NpVcySjOMs@9{gcjd?Gh_ov140-Ck#9(EXeNo{P*Zg)G_X1Yf8Wzc|< zt%NCaH9N~s#N+gwxnb&|FKm*#{k`@cd9UB)cGwM)%7qx|3-(9khj9;i9c8*ht`|Gl zcDqpx>26ue%3_7h(s6n&p3o=EIXOwnVIXX_yYk)G8NG|{Aln_YLzKu1?11=j_<{I| zILvQ|PQD>*4_nDbKj6ApYYvSpVTO*&GvT;79?xYrS(Oc$&FU_((`{j!_!hcNY}M;+ zcRp#~a6ciBnIE%**oAE&>%w-k)vwDi-$Tbx4`N#?vKtJ-OPA--vj>9g2@gwDY*$cN=1=_6G3p{$M4Eo^7piq#rI&+}L0 zvub}hCMO~^95O1qBxLUeG->)C(-xMq>;9}hC7|Pl&9kcLHvM)GyT4RH_Z{Lm;5Jya z6LARr?FI6x+{<60Cn@yG;?{v+zxgOaUd-GPlY_8duCmjR1T@Ez`c-BX;8>xFx zk9zfhNm?)hE zCe%@IA7?UDr|w`~VT5gkE}M0t#a{8RndjXBb=uF!YG@0sCY`oyC*Z2+r!8(qTxMtJ zIdx6X>bk1X*4Qa18Hjxza;~iEu`e3eLPma9J}j5$NqIoOz+VsJ1SgwVIbh9B)NHRC z%|`>IJLpw*Hk>2ZFymPEbyXtO&?yGk2pg~+yzDUk(H(MQcAve+4EY&*RJ|Nt2`4e? z#;7!3wu^Xo+YvD)2lHxv(_YdS{WzN8&yCm--fOC;SIdF0cD9!6jCY%{ zP>;}gW8d)5f#B!JD#nhBfrK7D>P8jy6*?a#vT<_5Pth4SgHm5Nt)Mm}heD63W~&Bg zyLg8mwp-0^z0p>}rEnxWVou0Q_GZ9&TC;43?iQnQ)b(a%Iu|DVxSX&zJx--(2rsWu zN{8g2=n0S!RZF36YrH2z>*RNYA-gEg(qr)$iQUi^ipE}xHcaOZE87A@!Z^C zkdx+9emX4h3hPmWY*6%ywut$XU3Dee#%Wj&y^_#K>ThNz!%^saxDc+Rj4X;3Q=&MJ zla0}STV``%Qcvoe7=umODLHFbLmTSRAnj9KvQ?BR&YlS(t62vdc3b(~VIxMU7u~UV zoSn58ZTT6xsOzMS48<`w!aKw=nK4szicGp2Sx%t`NVE`?*w_~#C9SIga~irTN~Apu zi|t{zUFXn`<;N^^6Zxy=y0{tU2$3BqabtAI)#y@~i8FFWOlA{uf=`nbSu>C!2)$Xi z>rkz}%yAk$E}OFL3~R$({BE;WtcVNplsKy|@QeJizd;v7iFWxRwkGtOR$J#wWZq20 z>vr7SAhQ7{&~lVxLqm^+mPm#Id;}uB$uE;=?b}Nmt@uS z*kQ!7$3ZGHE@ca9%HlLj%;`Kv%{AXidPGmwL%KzqD)}X~U{;X&PBJRD=G*;8KdN!xRp4~Sk3z8lCv`RQ!JjoX~hD$KWK%XbSJfqQO-|}rj0wvb zPO4kXxoNAfWUCH3uPOBPnpw9X>b@LmzFk7EA%l#2D6=vzXILY*gKCUI@1t5K^L94g zq~rW*9M5w;trtR_V3rba@-1&=)liqq*&>5nE}hL5BV=V`mEp7mNqkIl)sPPos4v;D z8Zd2H-7SK`Y@BpC3^YNhg?u^GU5O{zj22z-m`$=}vxpppzOt}l2&>U{+Tq(tJ8M&I zS-a`*T^O(R*-j1VUO6x3=(N1az#%th=H-&doL3Tu8I>+&n5SCIUg;9YT*+bWf?}40 zmKTyMq7^fs8gDZlq{FtMRJ4dB!M#Kl(VIbMoq^$t6fHzt_RDNlV$+xYvPG9IX5j{_CUS+rhk`$iRe6dtb9BW*7M!dyv~|cK z%q|61r#03#OjUy##~jduZxJi*qN=beffgHcbhLJ5mFA~d0f<=dV4!J0jiUvYSV0k> zixkw6PNX!HTt&5rYACz1t_rNRE6k)N=DfVbFs~&gT9zat)QH_IhS{jW=@A0zc;Xa@ z!mKk#-{IgI(mBy`Mp!!Avg)e3!bwh8OMv{cskl@}5nfDOuUO3J8S>LC1IFEdC8@7SO^>}c_lUCBTd zaZBUx7O})jevy^Tob6#Vq|MLMlABf4Ft4j-k#y)eTVX3X@_?k?6Du4BQe_@;;RHKW zaV4v$vRf8CY=PArN-5Ia!j^SA>I!mD;ryjXO=ZZjfc{(6Q8wxXt2Z2Hd})m=37nax zI7Mx0Va`?+%8G+-KRM?spw{Bhy75%@u&NSp+B(PTmnRzZSW8~g6;sL=RGBZz)<{g% zfQ!BqupYyfY^z_AHIr7RDs~33UJSL2NXYZ&I9tYNDfAng1&Ug$Q6l-0LJ4Lih4n&F zGjkd}IdZW|vEE2hd%u*o(dDdFLN-0GWF5NVTLN;}qBP`Kq2s8pbd{8l<`s<`)8%ZD z5L@L7IdWHmj#x$QuOlyrE7MvIOoK9OOKwG%2udHt>Kk~9vcpQGmX*vR#j1~(@x);~ z7Rm%Wxek0_OQAia_5w8roNSdSW3du&s-3s8k|lOIn~%#Gq$KmSo>WoOx?)z%0%?hL z)oDm<5jd+%O145?5Z((x*Wg_p0s0|!C9yn?)>+qctxfhWCeu4J!C5JUoOE5lN@zC|d5e99s zsG)H>tf~cD;w94UDx#t>YR?uTQkBm$)Jp@sslF2DNGogMJrX)S9M%rA>Ab~5A~^N8 za*8Ym0#27W=-M^|DJhSYD^iuUlu4)Q5NLNe+7ECQ`2Y?e z{=Q$gs;XY0GX^@cGqjGfVwOUOL2McB8pvB|l_IWTJ}yXQO*@;E6{LidCeChzdtrLOUe< zQMARLXsjZ-vaOjVj`mcLyd)P9FSI|5pmsp_ysinXnWBcHjnpdvoXX1@arevM1;+Fm zqfzh;EtA38p+mbsN_pL4?NC)TLeps_bs+;EGK@R|$|=g#ykGTYigsF~4b*7O8Oa-c zfWS%?!Ahp7GptmyWnN+koh|xhjxueCUKCZ8YDX(aug{ll#ZN|X-B(h1btSrhG|ZXh zyd>IH$#k+RLn(4g4mpuy9Tv3&w+7I9SOgyss;LB&)c|gbnn7R0u`g^^Z41F#f8OdB zkP9g%z&VO_(G0fOs#ilT)+1`7CA=C}k#@9_r0iE?DJvlsm4MQtDz=rBRGqc}AKF4J zFfy$FQuHCbDgnvrYJsAKq$staq*irnEC;k;VVbOGQnsQ!Ov#}NyHTq}`ELy^QNv>G*Om0D!a;!5OqEJRzNmunM z!`_6SWmw;qkWG-N|5-yqg|w4pRYp9}(qwgk-a{bgGQyEBD)oJ3Rv{P_`HDf_=V;@6 zi4j3ei$DoB<+viyZhDjtUqwjufPA1>nP$rbycI~FMc*Y-+qZ)JTopA@vt`>#>ar41 zLIU`1(BjDwPrb@2LPjqhss<%UR5;2W0k4r;nCsAzEvX8HrX*2z7%$sZ@S!Xhd<$ZV z+Q86m+IqgoDtgtSM~Ta_#h~2g7{O#nwMFU-FnKAW4*{JzYf+frnHIieS_66v(e9TN zY64v*(A9#{O%z5Jc{$?j27Hw5vMnK2pqQ5lcx=)0vy!VboW#hGTUjYfyjcYIu~JXV zWGMh0(PMD*=lOD0_6QYm1udTP1$$-zDMegB)#HSdM(8q?3$z^;xC*To1@{8N zM=qC(lmLp-2o50a@QV?F!8b?TvNR$BHKcEaSCBvO39jOu!a#h0L*c`rtx*Wk0ZI__ z#210OZwWyP6k?nqCIUHWFlv%$?;`vHBlXnaHGw~h(0n7d4ylQNIp7%Z+QA@iU>eU- zg4V^SPTSxQ;Mgv9Gc=oT?F_)0hwu}*X~U>@J#3Eqi9 z@}==l@I3Ldfs;Z=w!&TDjU0flbcF^EY4{h7XQBj-;29d>xCRDoglroW3Wz~` zQ>s(>N`8__bOZRCl@g5rlhT*)J^szOM11)MG~wSi1+1WxLQ1x`KMVSWyK97X+i%M0 z0zc(N;j8KTc3j&w@gNCSIj?O2uug z0$RYEzGQ=PkqY%T+~mKYQMeVpRD%x%yh*okDZUE3ZN#APmtvK|D$<&436e~NA*IBJ z0$SiC-X_izX-U4C)aX0Q+X$=RK#|gv?f`d>e|k4fic?`ysKr0j7y$0pgDUj>H1w`;^+f{MJAw}sDyk&M0dR(Lll-cEyhTkaLEh3^!X z^e@6`!V)A=Y?_GBlPS`g-l?rftw?~~-zo?G7Jfmo@Y}Q}%0)P;Vbgf(Taad23s}Nz z+7xU}d$Nhfx568(`&)QToF<**Ked+WdD|ptf;HcTd+|)L+b$^v1y(c8Mg6`VGuyzp z?OOP7KLa)3SHejANw(svfVf7=3l3R?oNT6no$M*sQuqnC_%7UvuLMuAy={_fGKI_A zzmh%CE6ith-qPKQb=!)zr#O(vco?;)4TaEAnEybV;W!S+5F!Q zp@1dqL_fic5Yqd$Y2qhHfzwQJ;jj7C^pVon#B*=aDWEA;g=_IleiLpJTF_AVR=1$G z;hsV&@RBW=W~_^^w?7j`;j0O4;wrdE{EN^Mp2pwZqTCE2xfVVPTl$i>aBoAJ*v&A~ zTQw*rm!>JOQn-nV#s6nr3*YL$iErV%@KuCZ;3XP`|MV=V6`V-+07xng$>tljCPu<( zwiT(&6x0fz>6yL@9=Tg@`?mNN*a=JHuNv4*3b$jE+=_oQ?FmzXUXg+()V;-}!f(@0 zlTtys>8GICd?vSoUV5fnNnsSYg`36q+p!aVf;8jpZnX&otiWwzBwTk38{^$OzdIbb z!+|>-xWj=v9Js@QI~=&ffjb-xWj=v9Js@QI~=&ffjb-xWj=v9Js@Q zI~@4`83!D8LyA42;+b|((w0tZOHhR!8`0RWDfai$esc2P zq$C@*+utcP1(V*%H1V460_p&7#xX%`1GfoDZUtW9cKb`+3N2wKsJ?}#-l9;@N^TB+ ze+w@`n|_kr;a{YuNufzgH(YLiHRDm>HJ^$8+s*Ct-=^1ePi}ADrMexHWJ_4Z+ugEz zypz4@nruy43Em8=8B*bzpz1A5)$rf+)%0gpz0}P-y!2f4>urrb(Fg7JdOM z_|_GH;m_Zt`E?7H|bv6DP${ zHo|+mpCZo9XY-wKix{VO@>Ni2o`p%NEHKntnCccxAr{Fs;Urr+HIsa&ufiokl5dU^ zbs4BPX%xPS(2~8G+LUK`g9EPNFQqV@0m^a0F}dONV<|m-!{*^iN;rp#f8tWg`&14R z+ym3$ow$-*l0Ai!{>`VpWjD8=s_|X;Xu?uzlKr+x?&_`YrmFzNHgJ6-?M?V?e+4A< z4NX`9N!&{&LErvNUmi3Q4-$V0U+UI7#X>h+Q@H7`@J}X{)r6aDy5TqFYiQW?EqHP% zd^N*N@8p_Hft8-F0rj`wg=;~-h;!j1Jqufbq27jH#Hi_>uOkIdJfsN&qV*Sb^)_3a5bOIJ=xE+^*#b zqrf${Xy_770^@YIz|-TIN~CYZo8oM8R>xWNhAujSv)mb^BqYvC|4YLw=OQ{u8Hf_8+;O;TI zk?a)P^I=zu3t=i=Q|BO`d__(3bmqU3)o7ckMd&~XxO>@5LndZg&c-EE(yfrv>=e*y zB_J7NaT6L@OBf&KNfKv)&14hM8gkiB&^fUTgS$W(Zp{iMwGx-yB1H=AoLf+(#AzczTKE*CQBDT`)*{H9H+3aRM5iW-4&eCgsK9pn&>j=1)jke2@TFj>C zB(yN*Y?950MGgrm-^F`ukL=-H6!&!T^-0%2=+kv|(@%;CaluA@mf{XX0=W>@9(!V6 zMnhH1i=1E2u9FFWJ>~+kN_m^<7TvtZLE>0+i_S>dX0cPQL&%GI3UcQY*#(Q6uOXkD zBo$g*lHlzly}U{n!%Z<^$1UWB^9eP_2ya(iS$76nte19$cG06YgdJvM*2`Dv9G&qu zk@x4sX?7`2g=Li_2isL|=(FvPxY-EFbag#m4Oe-t7HQRWst(`6+i4Glt^w0&`qU>53Py?aZ}`OJikIOi*YfFUI9As1LV6x zkM31H8v5q54RjYYao|?GxTNO%47u(u$dlrD@fABYTgRob?3cdBy5zM!}>5xyJU?* zu7u3Qaek4Ur&OPXRt!4GYG;r^<#S}hK*C*IvRB0okGuH%qFyDCm*HhqitryGT`Y0$mxeC*L{C5- z(4#zwE<^pOUY|poeZXz%v6VyS#?1Na5;wy8%XC~!=o@A_%oD`J!l#6MK}HCqd&nx< z13h7>H}ax@^o0=RKyAw#71A&8O*gb;VxJuCnW5g5`8Z&-0bkYBKmW z=*tyi2>GE^4p^QfV#={1YoR^w$_M#cJLcEWA=wikORgcOrl#41ze=vMaXk@m7o(VF z^Eqx$Ni7LX$)U|ow8Lr*P9rZHoJy(7KuI9QIW%oqwDtzFBm(Kpao3UP$_Cx2TN8&3%{yZoZ?$E$it?B9 zaf?}xXXY|+qoRtB@h$PLivT^h$Vr%DFruRGh@Y$O}$dJUa8q)H)~85j7Z8J8CX z>My-6p_|t)^CbOW3$3IzuVj$PRSOLF{%Q1L1bq)UP&1ubkLh!3$wp`u+QQfRZeMk{ zMKMBCgSbl1=@_7&C7TwIJu;|C8T97lH3MBoY);-ZlR6Jm4y8y!K96@sXp<2%?~fbA z7I~N7nhk46cIUaj9o4l`oz&UcAztUWAZOmRXV60e)rvom2_mvU;?$8}=Bv|7mbYe+-u0s4sfWcZYQ zw`ien#%KJK{*@5LHG-QkbxnBSD$KCKINtO18hnXOsvG1Z~^{RL*xO~4l?-oTXZPRUt&1l?0wwOUy59eu6 zFUME?$vDpDGu$)Fdt5*1b6va@H3agFbcg$}{H*zTwk=M`=jnIYgS9wlKC<0; zj~<~L?RwKImSqeF?S3EVSw54M2>O=1M|E4=scBHle3^FIchHZqUos!cMnW`CnQxkZ zHizs@-l2xF{%p|DI84`OBe5;a$T!)`{sr@zy$}`*v?$ST^z$9EEw*sTirO-;-{pVa zd|E%0*YeloKiR(}Kk=t1p(AWe44Hn>69(?c)u!yUFSis$2Ddd=2ZPd3a4T#v8C z5<@#|OTJy)tACFE68(hT=5o6?`&;)dvCm&d@3?_(M9m*is2O>G=&;M=d^qU$`Th9` zH$&U`uwJ7FFm9+CP|}dJXY2I`*r(lRhVh?Ebu`ZOJ ztKn7ioOw>Yu5#N>a4(Y{Ro#XdXgv{2Xn}k6L;6$V3-aS}ZFa^zM*o6+i@gLn<{=8b zZhB*YRwtdbV3o|IIT~Nk&(T-oMOwB)xG4#(L4Y0vG8^W_DrqrW<464G+%NlgkyXFf z{AKnh;W2XBwCkPb-fSBkW4*eYcl#E-7|)UYW{-bX9utfCpxi9C`axaIp&Lj{yJg*C zw!4p!&(mL)@4^V<8Tyy*kM-m64DI3fn0LtS`8r2Q59^Lqnyce#FZJwzxu8mH9mXpg z9QDM^kf|^glRW(>|2gv|{Z;X?&@K0wKNJ6n{GB;sI>r6@`|^7fivzKTbcw1QH%H~O z*;DK#eUX>wdbi21)jhtR;fB|2CN7c|x0QZc{<{1sd0#$Ho%}ztKaf8_@5|hK&HLnb zw^l%7mh7VSa6;@g-?vZ7qpt4O`Q1oeZ(PkL!&Q;T8M)%y{e$sK{_Ff#dB)D>u>E$zGGI(YV`ewv;A0>!j%% zqk26lR-o(YtNHKezfV8KZt_1&l-Q5rihT!r$Une$$DQ_my3>`#E8*|NH~bIHc`~SX z$9w1?uUhEnb>re{JP$o(t7JHQCeg8K_5EbGx?metVpP>Ia{;7N}TZkiaL+H;39n}?oJv$kLk7kZ__@SJI&m}tfqxQ{2 z$NpFL23un5?H2i7@)iGU^1XE0{Dc34_$_)A9IrcQJZ8}8r`!DTxSt=eS54j3R7*B& zA5C=V=fY_NI_xh)AQ$DlAIm>#evkiq_a1wKe$)OLdBUB}F8fQeh3_zrsQWRlKIlV! z4)cO}jP(}mSomzBlYJc8>lV4-DKOdSuq}u^Mm2Iy&>CiGu1guX{HcD1+{?e5{f7D^d!O9N2IPVKPtBjZC*yIu;5*0;@o>01w1jK%IjEgm+e09%>U~C&_3^J++rVOzi7V1K4C`03HhA$`8Tt_ zSNqu<8KaxSMz%HEOzZYcd^23&6Jg#AB|7=X$j=l$6xp6QJkfsQ-qoYLcFD%*wn^*el{*lpHeUi@FlAN&8y zUXPKj$os^v`bYV@C`Jx34?oE)e>xtZZ^-Lxgx+O$8R&f^(5WG=lF6`={k;Dz_hHeW zKNKqRjqumxarPqg2_7}Q@e%Ps@}Rj_Y{@aoQP0Jv=$?EZKcuHZJH}hguJygF#X|pu zSr!BScd}2%VR;u?n`6w0AG0UI1@mfHqFdz$^d|9Meit-6PP60u8R%+!TD&4J=oMX) zxRovpM`%>b2_=#Ee-VDg-OD<|`@(!YD8HM(828yDMo7kkLdWUo6K4)R3;-Ku;nd_X`0 z9BmO3@g;L0JVjm-$HjzPiUVShjpW0A$Uxs2?U7$qpFlgXmfR-~sTcIi<^}Y6hy9FS z!?yDc`h)ady~aTYk$*)WFwgK8)FFCF%(J9{aZNTF`}5Wa{TXh3{A&IV+Rh%feP(~y z>)w=)%QyHNp{#opvy6XGZHk*?EnLZ7r6E2cUk*pi#caiQ5=x?!}OIm&;meyUFLy6t6K^rrYIxhrnKcx&3eY!AwxKx6Eo?5doPSi7R@{H|ute*~3jj{IWR2 zUY1XXz2ca-VCPI5OZVQd!?(`J8y2zsa6<`{JwothlV}5i@nMCfh{Uvo-PF@HN!?HufIf86U^U>ty(rdoi5D zh`H{zh#l@>wvFz@cxVwiD^H8(vd78G@dAlqmGv9wS{B>PTD6hgtAE{OzMDQ^`plE| zd2(8Q-#!a{$HD^ELjE z?V`Ks2D&FaOHYTV)f4`V#7%Z#gzgUSiWs~2QBls%yW?!He?EI2+ICNynON3I*W%V} ztKAacqkq%hPr88J=^x{J)XDJ8@FYK{m*c$JoZW*S^ltZn8#1MEDjYM<@@L6&>O?#Z z?fxCvh+ISOa+}#E^HK3-tb28Zcl%lQxY;L9Wq)t?#>-@tEvRkuo}|y$WMU{I;mvSF zJ!ib!Cr_KR*_`N%BWP8&(XC`h{9^p99b^63gZ^Utp?EPIqko&d81je}WO5IEhkcK^ z&)pNd#4>cFzMSt-`{Hx@ ztR_13gZu;ho$Ow^4ZY>%>@~k%?g>B9CxywT%u6aNGI{mQj zRNMSkx>x@VMpXyJKkye_2{Vv3abNt1{-E29{=Ajm$oGe5!?W=@voAZt=Shp~F(}z# zJG)Q(JNbotUFgX(b)Npc{=PXCziS_(SIkJ>>bJ;;{U`K0!Uo+DO7u|nq}`(r@Mpqn zb}Db-t!y35#BRDnNcvkC$5#Bkq1Asc{FQsdJR|-w1V(wk7$NtHk7k_hcAb>aOJ)yw zjK7c{&T?w6JAntUT*%dw!emgv3Fyam)>S_9C`USe*eosDc%V9(hyPfjq$cM9g zbT?YoYvMV~%bxQG+zZD;0Z3_CvH3>mSp-=AeH;oM4M+Eoi=#+;1N+pA%otx$Chz#DIJT zqsHgVUiUrv99_-_*s$Lr|AqT7*_kJuS$XyXc>+4mU$!sgk*wGbIly+3OuU=@w)$0d zHysSS?6mqW{U!_IN9z0ZkgS`Hi!3zkNdmxVbLcDX4m_&1O6quS05#l zyyCmeCYOo#yMLv=A|5oG`L1k9?{Pl}FPR^Q$LuR^-q*yS-sL_>-$l2O;k+$gQ^6k$ zujDV}2XoZB&?<(^UF4nebNR264~4Dvp4g|~3{Q%E`Lp41>E(H~!ZDgP_l5`AwlG3^ z!iqTK-r$GiYv!Ojj=5PGGonrG9psnHm*^wpZl6h-pA!2W=8@uwxL2MbGhvml@!S1& zxe@cpuCS`d*@f)5d4s&}&xD)4F1mAu*6<_rQ}I1+m)&N2#5I0I9@ekY7f~ytosKJ6 z8yR66#i;2+Pf@i~<}y8RV?2>TM?EQI6ATkC}5M zH?yQ}+R*BEGpyQ*a$IIJ3agIdsu<@p3Yru}PaIL3?Cx+k+a7S!6UH1%VZvQ@7v))h zMqFXJn_^>tNIC5=@>IcfPabBN^I|0|3HX;->8FG&$CbE{LCXtW4aAmRCAQ15=rC1-n|d8q z+E|Nf&9F6NZC(;CAnZHD~|ULnwO z=Ao&IgXiBgU-m4g>~+P6+Rzkr|8W`RZVx4=vIz5yvxKw(cfi&f+YN8+}pm35DU0DrVTbQ-M`fB34299gMd;{tb+Z0dJ_$S;V z76q;Jtr~Gn@MMY<78KMim~KE54gD6RfZg_$Vvwj6{?ohZ)_fN(iGps>aSe=QFTQmn zw~}k}n_`u4i!hT-;h(}ND5Q6Sq<=E$EBPy+5;oOvOVnHgqls66t=G_S+_fAsgW(I;w$H&@X%xyh-?lEm0`Gnpp0ZTY~?$*v%9qH+L&9 z6OM1-x`r)pl**LbA(e2Lgch-5^jP8l+JOSDsEqaFU0Ns8Gj{&Y5ErWqgB8>)5w25eA72FB_8tFot z40nY#*R8O+M@yOLsnlkbR5^vF8sR$F1bl!#+G7qkQg&$5W0{sCT0K+B%f95`Zeb9Q zRgC5894)+VgqhM$%M>YzWmdHa2IRdvfTxlJ%lMK!M4MLC1r*sJ~myF?}@e$uj=des+=IX zoFr2WI`+{9V^>^s(jKwF-f!M1wwNvkO~h={U7=^?o7pjO&QAyETg+;CH%8uTvoWlf z&t@0$)BJ2a<6}6F@z|p1^h0h?^xHA=kob7^h#96!a>8E=XY(WBmAIcCvJ<=}d$Mlb z$H#F0#nx<8ka*S~kw^KP@`yejF7d^zT@16e*(e#28~wxflNrzZ!X&%wF8h<=r`i7e zrEttHgnl+k2i%ZnVTajFyX6gY7s*@ z*?*~iS=}XXSN^OtRY0~;lq-3~LFmBY9_=J#VA z?3h01FZ*RW=r`nR^q}j}9ch(Ceb{|5d_dRfIizY_|I|E(xymU!Pu7~9bdw(?8_kX| zC>Q-XbHu*H4w|F>f|zh6K593ZLD?x*c8Glr6fRVGL^q^H1tu7mtKF5kc!r zcuwx2FXNm`C1BsyZT4&2M!nvw(v$LK|2jJ^PREnx8e1j(Vl779ZIsZZES*1FU~BxB z*_w?BCI;BJImn(5ukgcIX}lSrC0MWVV_0)7 z%Q-n2Cisl3hppsm^!NCq{s!)cImQmS$K;bbkehl#{3!h(*@65W2^DtAyd=>W$`usF@G#EWsqCVITbgd(8eLd4j!4 z&Xe{0v*9=6hsXw77CCv%>@(i&3rFL!858TmDC@y#le%6Ym*p9MUM}(OxS9Mm*5UsR zZ|BeHe+=Jd-!jk1V{*#flYNDMl|7P;>N$Ce?#uSZr^F$(U`7Q}YkTstoX@7+O@H2A zGPor&@5q?_HLS${PjW~;rT;4awf`PgZ%>DtWGDTC{|)nDGAgdBSN&e|a(=+SCN8>m zhxM9lZ7kbaJ8356S%21EGi5o5S>?aOZq9FpR{w+|`$fIP~ zoEOjQJ?fy}uivmY)BxKWw^Ni-aaG?CH{&&VL(Z`(AC8|-tLR~edRbZW4f#*;Rop}~ zVK<0hBww??Aa~IlaX)!hyrK?}Qz5rCjq`GL)U3)I_PV|iZbaNW!k__MZs-3Ry957& z8jX9zH^d)Pm%Sd&W;2nAU!cEYKM{6_>;C!Ni=Ud{k76dh5=Lm2Zx8L}hPfm!+HsGT zk}vX_+NuA0#OYtfF8>7mFY+7yadtXCXBOQi`!W6b{1?qub4~5_p1v#&>ofWJIHv}( zU2L=H@)PPjKNqJg&TkmRi9N`WHvUUwC44vhL9qFY?1H^Wm-YJm!{(RiFR=~&GJ8%u zD_$h$*)=!LCqla)zk{46;m&$<~;)fO=pI@pxH!Y2*x03e;& zee6@_i|T`PEIX;6ijQS4k~hMHziH}>lDp%B@ttCWFS|?Ow0_ec@rp%rtPvF@dVa8oa^gEnN&C?8z5ZpK_H=76Jd$V171e7jjr~GMoR^gTqv~`QDMGVR{=m+{u zw}4)BdV>IioQmhk4fMAaj(aU^d){GiVwF-dCULV&U|GLdrq{(~c_o{OIM2qf)2VDR z$8D@+z|*XqmBK=t6*FjOCgOz4HFl^4q3!7Xu+9*>RVV4@19UhajNN&~V9i%71l+d~ z=E$_jvGcPap_N%y14aP^>kASi6jBeE?~4VuBye+qXw7S?>dU%9YgtF^w%xu%)pCqG z1kUzK%sS~(oYQmJ0!jCE;N+`a42v1gj4_N^c-^i@+`W-wHm4h>hy~`lGM#Y6`Bc~H zYP=R(WQ(o_j59d2u7Moa=mmn_C+0%Jpl zCuz{pz)93pV^l2g#Xy0=WUyJ-ZNoHarZ3b*_=$KYlOV}eH~u<}HZj(tpqFS+P!^34 znm7u0$wzu8lk9J&P(af&QM9-4RKuR|5;PeFTY{!<_ckgCQp8DPoQWFMz%G0=LsE?x z6)p+G<6oGj&)eY`q(U^PB>cip^V#(C_S7W)81PLajAT={{G@k5!Q!nNF)mV&;^uGh z$ii+L@wSarB`zmh!b$HU%3ZJrpn^I92hj-yO`A@zQr0{JU{8J5BL9Iwf z;aWVCuk?2fDhZ|Y2z!^D$;=Em|KZPxG7ZL2wmL@BT-Wg>M1rFShDe* zU`@Ebg_|%O;3-}yO&+Bsl{!+2sGkvUhuIq|N!0ed0nK1bEds+oJp*CD^=K!O@eL~W zR^3h%QVlO$J>JQlLP?<|lWYl+Oz}?80xNMT{S!{XwG_(~q-PO}!Zo=hKBrP48+M8B47rtZCBaf| z*oIrmZ;6~WFv+!`pc~&s*vX#$$yW+7K?@i8mc5y)2_v~BI)zE06clU&lKAKvoRYU< zpYW2KYT%`qB|hE84!{m@r=>(YG~8%Ku7+yFjYn}=t|q9#sbpErT2wjF&(K?>7+aKw zfVT(LK(ewyY4LC`sHd{6v0e}w>%c|KQ`jEV0B!hhgp0GvDEEnCS^=r#pks(Y*;7~> zmdjx!;*e4I^EobDqe zRvp#^c!ibodR)#{a-6QGIICkGHSfvS&^6eDol$}Ap+TJuC;e5?#kTNWmSr2s17VO~ zut(If?67{tykTZEm2IY%kLitcjc=E2b{9^N+{0VMTGtV#=riJ3iqlCf(mAtP?#7N_ zzaC;6=wdh*PGu+Q(Rhqr%y7T3YN3=--JQ2&ScBlW7uWr~;h4*x$%b z+J$U8-N|-P?B9?fJuVN4^W?1fsXaxm+fry%B}MgMUUJwup-W^nU(7d$&$IU%8n%fR zcENlP=a5da@o?O?W7q7yu+0u)Hr6hVh(J%oBjkv?jps0{ZF{P*VlBk=3 z`1R~7aYT$zs!y2j@^8u)!;(DBYWn^3QJ-%7YiDI~40o#@j#K$1HR-EigP{bugw>jx z^pb{jiO1+n^yv4||6o4NXdH_3{^|G)@%`*%D90IkU-%6FfZZ6{@>zby?V-=wOMFVr zhas~GYbB*@%Fe3m@gz2t z^XhfKM?OiWv7g>U$K+Nq?3ev%dV!3)bMzX;saw^hd&PRb!+nN+k#6MUt{z`dKghnF zpJF{^lN)0n5%15teNIl8pNb$3m}|1%Zq2sDb+Rg^`C;|CJEbS>O6baau!_<{J4HX) zZGOu<$`{3S%$t^t6`SyVUMe)+>G5EnO+y(pWhW0`6+fddtIKSr$i~= zM7A*|x(OtXc<_hx6^!$`#gOimy}E|+UoGp(vi!H~Bk`J9Vdw2*{-4ZirXyx@)Z9xS zCOzS7z|Wt+F6Iroo^BHx;u_NGPxC|c6>~bwsu~-{ET~UaIL4=@BwPKx@pt6Uv7AoP z^YZ)tJN&1-hrSzoqPxtyvtE9R?~gCD)9$L6VH?SPev@kx^Y%=Bh#%DFIN^P)KO18G zsuJcy-Q%vo{9f^O{b7voFRCaXw~w0;d-C_FU1p2Ehj)?_aUXrfUeL3l&evfjX+0k_ zGv>8C(9`0AAi4)DYB={u&{pte0qF!jMy32U*2|C5OGv|y*i-qmy_bAIZ<~j$@_hP`pTPm}=;c!=ab8#znIz zmqOW7b+`Ef{b(TWh&U4W>b>Tu>x%EB@6Oj}gIPI?=K1UuoLjE)zA)l9@)1)JljhBM zke&%Myy|Nm@vc&-T3f|)S&6fBJI2+%E6IzG-%ld#irpxqR{XVnBbkmZ&5?{?; z@fUPi55?hZ4I8r6?54eHPU#aQ&#-?gu|J!2h)P&ei=xgu>6m_Z_yvC-o4~1z*TgFf zD-wDXF?>J{tFoMyrz7UgVp{bO+ykr!MYkj38aab|Y_DZYrj2*_M|rEb~{x!SH6h#;~RswwQaxs9tiH*m-froToQQ zYgl8~(q35-3)xLGt*DQ5W zshy-OPuXMQxV~&ANfj$jyYmgaCU5#H;;cR&uBjzL-I&H*LT$fm%?y`tw zHt(m=x6IO#@3noQTX)d*95Y=5868&2AP1)~_qFY=747s*cO%a7Wr^Ncw8+*_%UAgv zpGJwFBRGx4aKDe~$U0(MRt>lXPSkD1w2EG`j<0oX*_6CUFNU1V=c}d-=SzlZuO;@T z$Nju+iY{tm+a;v;1n!6nGYmK4#(7%JYO1ambAr|ar-=e)w;4_m>P}msrEJyW?xk!g zn=?y>OCB3QUn7_Ek zAF?C4Q2nx@w#|;+5gT=t&ch*pCSI^fVvy-Z*x(xlXZ`X*kJO3Bc|5+9J@f+Wd|eN7 zk9QdMIruT3h$S1uL1AT_jxa;AK&{+y9HD!v3RS{=odxHe!nB@Sq)TCa-$Qx~H*PVE z(QT!1U!R_H$Qs;Z<(bd)l+BQ82I*n0Ky-X3QaQowMa0~N#kncWSw12`2MqU%`7@4FvEoe3bR}>?D)m!GGlTm-<=kUb7IFGHFy1u-iF3jnCq`UPRtX$> z+~>;C(nVSY$F2m0TtH5A0#g`+Y2-LVDr&5ko1t5e8)eXCDKUXW%$5s$?>Ojwf}5;Y^@PIimYXkHMGhGDq> zGy{u6mabE(j8Usx2%HJC*n1+T^@3Hp&vA1)+t%A+i>>pXS^9A~u}1>;KD#qNakwSR zV#kTV$#6)qTWC+h+|2~Wr+Uh8r*)htoNKF>iJ2Z>^BZa_Y@t4EINUVossJVac(CH z`w9x?x$?jbVlP8>p()E861Fg6>ZW{-8V*YJz~EL}gWWd?cO)B}?*yzl*Ulm9d@9d5 zPTM++uT@v}CCWhR>5gG$o+n})Mh<&}I8Ml_iuKtV!>U;3YTxZyoc-gtqtA`)89U`C z^3>ogZN_-r(^>U??z=ui+SAgZZl_Vk+#9DG6;X;M*618gvZkH1$1kNlu`Sk0$1K!1 zohGdAmE&~k&)o!hjB*xw0cBVAB)DSpH1RmUgZ2=&k2}!fy)r24X-n_c`|QB%+ig1( z9X@9xaUzZq?%S?UJZ>W<+`7y9pb4VRw)GzJFx7)_HxCr<3vFU;w0dCz^PWW*-(P)2AI=UHWV9SQs zHoFe1C+@%>Snk#(&UEt^`3Zj{AI2yA$f0$11HOU&cf$@-S1s8@oyHgG1v{xnep)jD zIZ;gbV%g$6?912mWqF`?!@$kWas9;Hv)`!u;*gI7vqQHPcH%bQ@I8TBBH4++nnryR z&+8dusayJLDABvPwY2GYJTO-MVL7i)5^i@5K;%3q3a(6>)`KW&?RiJP|NnrCbr zj^cAx+>tv&K4Pzt?WS%-+oJ|~&2IBc@~XSRZ;ESrukOq9^3Z&#J~dzXd+G$`5B}); z_mJCF92@YYUW8+e4pBZcT78MH4hP8_oI%EH|5bi7i};4PCUzL}&(v4`SLK)TwtFn6 zr~`WrWd)_C&v5f!IyYwuv(xnnKe8|4Q9AQ;h7Ki2Q1J$sTrN&i#+gZ~I?SW`X}I63biS-GM2GEVEUp*t0K}~r*P3xhflkPimr$F05#P_OuFaC(XZ{Bcgy5!GovLB_-_``hUCk1;B(*RgFC+;t+ z^?a@#)L-&1_}BiSD(qY>d{=CROYwE^c7Z*K-E;$WtRAID4CiSzPSd6@-P4+tOYu5NCO7Mr%EUGE zUH2nsMZiAgaKaw&T)yyMhA;Kk{82u0J^Pxtsc-NDIm~l^iZ!YS?vD5}=lsx|@=9#g zobN}J2z80?gXT5)zWrVI19y#^^uZMI{%I>@hyJ%irRas3|q3IBdN zFx@g{r|K^MkSF_vew;>bnmhS&7VHhh4U1>-SUljj_2>C3s_dwKVs2xmA+v|+dBC}7 zz9Z3&+FgUwhI~`?%euWKe_#JNUo%{8#HD$ZKD0@Hk?!bw`p9?Pfx4+)k67Q;U3aYR zyU*@cisE;Mtxv5(}drRAEjT$&)t^>XE@lJ zzr?QD*ZDO_ZJA5BpKhDa+--AT9kZ$JmmRh5_xvu~b(;|*TBP-=Ld{gS;_GE!&H4TK zvG^tbRNUs-pQc{g=9k4=^-Z(~l|Ryt!9WcewI+G&81v(seUhh$KNnLb5DF^{we&6N&0p<6I&MZSnl2Uc72J@(jm+0 zqxwUKeg`9XME;TE29te%t)1{j2oH{4K-9S^UudH}?O9pPEnYGq;i6*56m(3vZjNx{vDRee-j*xQ-6^DnEko<1GCM}+1EHJ|6j!4vD@NYt=BkL!QMAFsV7X2 z)Lr=t`BC^LVQ!GE2kgFg2f43ikJuztYQyd6gUI8Oo%0v+MSSXCh*{Y%d-Afm z5#G)};D0QB;$M>^{UH95|D*gz|9KcooXr=v!khkTJt!~a1NK0C9lzv{(n$6-^i-g2 z*^*T~c1P)mowBnywtc_D57-rc&E3*JP(MjOwClR?yXj;0Q~NLKUaZ7^zT&SJoQq1! z_{e<|9?M7eo_VI{ZfH?^BgWy8*)ww#F%H)BP1H*}>_9?GfV-~V<$oCdjpF)+`-cBo z{tPs~@=I~WU3Zv`mwTeBpV-XqmZ$Y|SNzPZJDNG`NPKz9u|F-Pj2%|AWzTO#8n3*j zulTprAGtpY2lWg6mHBo0P$c$+U8rmER(f4xZYo#hX+jSlk?u6})7-;2dZWgiiXWv# z8p{zsR~XNVKJPkw%d0)d^Ip1^{~-Nox@Aw?ZT>6ytMpO&RGf<|`Ym&l?};_khf==s zUljC!3akC16QN~=SLz(!Q=>5PQ#;P{8rr@L^uvfvw=MQG#-sJ`N~zxQqw*Qj{ww~8 zxb2ViCDfj`W_3;bPE&gM7#Br*@ zVN5SBnYnsY?x;g??&cAFm~p6ZSx4Q*R`CvDXoGxno; z%B#FCx9v`R-To2I?fwqR=ijsc6#j?2myu5jC0xBNZut%Olz+^y!>pcgaFRFmu7=(x zHO2VkGx3d>s5Q6A*F7}zxOLTwb3OJGqMbK6zOVBe;!pLTpf=pg|3&=2`WODxt*3py zrw+mm^_r>@+6@0|eaI`fBOz705qI61JJH%0-(40Rf55IfUJep^Og9!-l?h+EBQ?|*Gp7xV7>0&L%rnNX z8NPSYw%q5Nu~L`?VIAK!xQE_i=Ca;UJDg*!spdb}lp+r2F-Q@Z1hOX%*Qr*iqy#1C+78D67=v@{{1*0>fINcI^C^yj9RCg`rhde`?@tvGD9G#ZjXWeor zZnMvkPa~9BUhoAPF_RiG4`)Vdl+orPz5UeJJ&ze_#cDhZkF9c7V>YWEre46DnC<3X z!ak?C;kMKU@20VNZl089?u@Z|PzJ8&F~=w{dzGekmN2)dn8Tc+>6#8G(|)N=>f~<5 z*L><0z*QIiSj$Z`w^fC1LOL?$7WqknJ}h&fet#r-2Ubw?4dO0l%t><0Od`kUd1|m{jANEgBS%y-4=5o+)AK#v_;GkMYVt=CM;_{hcon4)c;3yU*Ox;>?3OwQP%rkQO}iHKR^^p}KBK+6$v0xu8iq31ssfw9j5Jb+npQA3oEj4V55Tv;5x`2|)-?O#SVevg>B-m)WU;eO zAT-HH;xvTCylq?{^$USHTmd|TCqk~iVyFeCqdIlRqNW5;)rh+_9J9y>k8ldK;-V~S zj-d{D~(-%sglSs1zgIh*zEN~tATTI0w#izX<)43 zr$$(X^k^846@h@7#kvwy4Au}7cnwvJ8k><)G72)oXbUNEP1-3IgOrmWt4JOOY4KQr zh>($nq;-?($iN>`@8JsgZyyIPGdLog)~F_R3NDL>Xc62tt`kHr~7`B*Dnt+9<8$PlnP${|2UpA$x4z7CudB!#`1^SZpID-MCiVQb>ak zgyX<38Q)MKS_EfR%O%C68Y~V7uUdaf1Lap6uf~5y4n~A)sniHlXl4~57&G9yRQjqW#Oj!#CS34BloFoOgj!+crkx2FVOt7BseOod)%Xzx@!h&es^mv+ z3iI+!&=x{C#6?7TAseNX%nG~Z^*8w?tX57deDWpv(7%O^;1teY{8M_!kKhSUOP#_{ zye$>e_>+rbCs>Q$+7h^n4K>@miGFLy-D1)|<)&@i1he3i{}$#d)XT6dNf0D9VeGej z6O3rCWU-3dG%$w}L}e#5uF%9xxUC^B2;Vera=rAS7$V&M+k6thQy1}4sFz%Y3m1hU zLsTeT=EB|n)7xM8witxf;&|AUE?80gv~Y36;Ca^4MVVS5vmPIxMVYU zY-1-JdqIOjk)58GZ`HUB-Yw=!Uk@yz-(nNxmU?R9Y`JY?B+Qk68=?(Mm~9>QjqN2~ zZsgL2NeJE2Br2`UGyW+Z^loD%E?ydmX)-K$Co|?)s5c@mwa377LVR59EwqYOTW#v7T;e$ z+mJ1OOOfJgDH0d-kZB?0V_;fX3#B)~TiFo)%D;sZH@}JBx-D{zT0vH2ys5S473B-X zXz{cr;J*My?Hz-Ei%Vgs9x$}{RAZ=DBn+ZRAzuEIi`==vqyH8w0-Er+#=i|in5~;i z2&Ibt398{DL;f$#OBdk~*DEXw+76+p*CQDyye0a^HupL5Up76Y!9UTaH)~1?(V+4| zZ=(3p5N(pOzjzZSJ^r^Ik|04c-ed~wZJGk)+op#w$h1B!1q*j8{Q#-~e)O~1m8gJG76Wlbgm+La^Dh=V1 zc}Z(Uox+eWz5Q?438owO%7<2S+SNCLgod8GSmjJu2P9}~C|$J1M~2paXzjE#mOMxH(t6t=y(DaZ$y;sjFL=A`r z+%!*%*;1x=i`_ygglQlvTJ%r6Q`p~zwIK;k6k_AsrjjJbE0O^57U0uLqlJ;gT6wG_ z)26`#kDhcvkL(1o7jSa5rp0g5Y%XAgMdoFCTE15Bmp+u1mUd|HiCQb0mO|@C)LZw< zH?98@oP2EKOR=a_fV`yL&xa8Buu(A;*g`sEVNA{PY$=>=C4+^D(VkaDW(_X0>Z`vauK*7MYc}oAp z0p(rWh7hDRw!v!OEv+^N18m}AWhfS+(55Ifa03h~$18qY{CEMQ+|H;2v8e+DrE*QF zq)@T>PYn)10-n~NY%NY}BMvAIg{PG={gd$xKeqXAc_aSF*8UUD%GP4FkQIixpx_&< z_Dz0dQ%wxNjo;Ei>rXURGHU+= z@Dre9D3=M(;AtTQYoFGi>@5xdEqsOBVj95p1x_o07XFe$D%;^AG{vqj>=bepA3-Um zm!V#|{Dn^oA&fSZN0?Qp7ShsN;fE$|jYWZv51Si|- zzqQeu%9n2ZDE8J6O)|Q9x40fS9`2Q2i?PCLap+B{B0S&37#a#KE7*L-4TUp! z=$}lR#+6*mMVu`y1>cwPP$=T5<&b!zu;e127P^uGVZJnk5iY{EvA2E+uoj;2PjQnp z$WSb;EjCa}gRSgZ!TETci-X3kH1;?p#BrXc3>41h=q|>r*q=}P?h8&*)i@o(adJm= zHO`7qZ)o60rT9?3koP_sBmQ=G7ZhN3vcX~=zk z%|myYTdSEochBUb^emmQNq}B1ob}pLYpfp_nNh>tw0{c&AMaH)noCsyq^yJDfq_SA935P$sT9WGk5thoZYkF7ZoQq>Lcc5ubXh_lAKfB8a)?t6I3(ly zyhHnF6V8VL+V>k8cOjPjdLQQ^cT4ew`1x4>^*zH*W9T&Ece9|_spJX7W)FH{Ay^IOLH@-anGKA5l-|N z`8yX~1-)At8trsH^~x51(_N33#DUxpGk54v;_4^v$S-6^_bg6s7H^GjW<8v&ZS4e`3z-sjB!;q6YAOfKI4*ZqD7Y zF6s!S2jz@0-8VxGEqVHF`L?^|ZutGs0oJqnk-l3)^I<$ioxu6(xR$`JWeRuspo~42 zCB4YU>BP-dC!$7_ef}Nsj(x*HKT_zqaeS5@ggfcJKdg_$L{xc@hkQLi3vEIjG^euY z=e(H0j{Sr+nyboX|89Ppy_Mb;ubDv{*M&c@U&njqX+Gp*UhzS~Noupf2M(pEoZ&QY z@rMC7GNduS1BPWMzh&R$-!0!wf?x98Ja*3n^zWv7>Y;w7#x)Dwv@W&_H2K+%U+DAj zLOi#)T~WQT6IHo^x}v|wzH7f%f1h8MJ4n}=c$Dv`yY8;MFK~8P;66gOX`ml2tofdu z1)KyH&-@d97*8xx5qHuX`7QsR{y~1zT+y3($zS9L>Rx>}-|?ui>C`V`&#dPSwOK>| zah!#7QPNWd8O2jJ)zIU~ZpQDbALzHjb-$PT?o1u3NA7O;y1s9p$Pz~yXGQJ0-{PC~ zKzHmsK*NGB{HPrBk?YAz>2>!e?)P{*y{=rZ|r^0c`S|-@?7>4G=L?X zE9G536{iv!(BN|}SlLPY@p^vCiF7kvw!HKbB&~{mm>$SS@&WYyK%*pEur6DR1BW`~ znV95}nyB-7l;^0oTlFP(O}=g~r%Q3CDgC%F(&J_c^DI0;_!3Smw6q#lcU-sbS=?Qy z(E{^Dndn8R!jR)kZh+2NyUVs6QYkuNp=WXgeHUok%n3V9q?d9o@$FaW)D=!tAx-G1 z1d}-7=6bs4a6&aglS9IJT!%Bnva4|N%~T2fTEPi4js7g*G_P3Zxxww28hulmGtB5{ zoGnY0z==4~_0TS9pk=|}Y;OkD*sZ%6bV5}ya?y0=YZ(?6M&X38#|;o-A<$12)Nh8K z&cev5#_6?GNt~}!c+kF~FRm*AUL5*b$N{~f#yL9IP%?`I!=UYLc>KsD1(QLhH;>z0BPSXEe|N!RuAD)8t6Y1MtU>Jn3O?a}c>=YMCfPC8gpto)?S}ekDpB9Jg zWXQF$Q#w}^2~Hff{8E}*PALq*JpRc>aC*p2VOkR!f5I{iBsA|8hPntreyxuMCQ&5$ zwN%Ju8aw&KCVa~qrHl;4=o&-zm!^%S#UN;l*}hx8T3n(kX~c_h3_F8ZzYAXu5G2LC0wxs5$Cz844CKfp~7)zU(Vq!pUwQX3MxgCb~h?CwBw1s+N`gNaA9PSYk-GX*iLA$5NUAAgH z&2uL}<0M}qrY>@L?pYaf+{~Ib_{1#P zG~iC2+)?;WVwLV0x&sz^Zp$pp(Q{2D+Ukh0Hec|i!ufp$-Meub7d2XNf!-uc4Imbp z4_w8e-PQryLt}$qs%~C7i~;IiUD<_!#t6s>x;iq_EEX9j@#Bom3(hL*S%&6S&*W6h zGp!>)kEy_SfyL;Tbqwz3mC$SgiJ;GM_NNB6pBQfG*IaN!ET$1>10tZW7F=%zQ7}dEq(+A}P`JQ;!U8}qNDBP2G z9Q0Ae$LdT>BGYU2ro(tlF+YzZ_skty=#P@KxQrY21NU$F@5MU5>o2pV{)Ye3{VM)K zf1K}G+|?|$plN2`?%9nn@#pf$-t}LKr)m&ZD{s;H> z^4InKT=>*)^VidLiEk{`XWcyV&+>!#Fg;GsIy-HAAp(1@1j z5w$+xYtvz*BB43k&5#QVgSOnGg_8Y@FXI4-#44db&G<4F(BPxy7Na+Tk()>VqTpkj z9>_2ToB6gkLfeJ04@v>rC`EN0PeN;yFxyfCo)F$$n1H^IOl;mQJq6mWEdsZIP60&? zl+Fbt^k9uh@PSGZKG!(gGbg-@puRLwe)mj`%PXcoWdg+M-69~uZfL*fs9!R z(NG{?3T^Oisd%`^5HIxKLW!zrT!iT^{K((KO_;D!j2>jeoiVgi$IEsn*dC4oebpsw!&#)^d?L)x}i*=2|_#&)HLqUxXDfry<2~JQ*3RVFYzf{i$m#J zQ6ucuP?!LFOP&5HY)gyY1ZiOeUm4xNh%W<-7OL@2Wg|3P`Nq}8(b8MR*Z%+Jn>a`? zt8z)@lpwq!T9kLITr9AAlwr!}+(5~cWE&L_M z${pcjn-Ih;rIP+vzGQ3NBqMTJJg9%rNL08!;Sc3w*5kWr5Wi=;;lve`mi^Rm_*O0x ze7!%Aiv$h3Vh$~<1KZODBdoq&=NkgrJmPj7rbqs(0R6R?b%Um!xb3c$4L^9T7eX+QsBTLZ?21mVb{KDKQh%Gy_Lf z>ZGpi^P$+$ud}QCK;h<{dQi_X*Y}Ja@}~|ubN#89$hpLwN(y?7G}Ci|S=c-=pce<_ zhI&`L>E2McJZ5t+|Mtk?o(q2$V})mBB$ghth;z27Vz<)l>7pVs=BEYUXdHAL7QO zAL;MMYknxssMQD1 zu=kGIQx#(S3fhaIN6y@{1tnmhwxPxEwE%5}p&v*`2v=n|584zkKGcXx9on{FI#Tib@iCPkWZk=`$;C8XKjzlimI>*w|3c-MZF?yyJdIX~m`3|*Ug%Wb$#hIEHXI;}AS7)J&p-L#!ALl@h%gz-Y& z)IB+KBY$R&QO(D=`xO)b-?6zc*gf%vLOV~v|l>>Oowkry5%(4p3F%(*zswMg7T zpa&lBy6<`hvn~Zac|xfZD7z?kDB(5AE($OpRFebz3UvQCeEr!@-L)_dkAT)Q+sT;i zs1ZIlb;6@Q)y>R*y(k#pbM*d>I6?hO7y&5Ibr&Y!-#7FLLiNJo5f~>c)JTRe2mzBY zf2A;v$P3hB%)&&p2@*!3)~TkwA^xb9Bpwntg%p~atl(caxHW9H31Q%4@lZ?@dz&&! z8<~VhBQ+eO8=~hf(oXz&Jgc{B{75ndwORq2)#eD+%k5tLT6!nZV9`ljK^z@HwXMBykzi%D23JJE05 z1S2SgS()FouPBipNti-X4DCO`R;G0wrSMOAN_gZVzZI=E{EB13SV302 zwDHoLZ9^qO%FT?qU zzJ*U4r*7gUp4(?7M@k97TGRTHL|QC@wiqj)7MEgc<839<;m;%20}^ ze5Qs!;=bj)rP)d%eTz+)87{)3CpOepu9q=6_^o)bO?<2PTj&at{8}GM8|ArZY9!TC z4mag}>!W~2G9-w+XrHKTQQ4u`2#fr56JGxYRf=O3Pa9h+$=2@SOZ-!wQf`tQsLp1* zGio$RpiOlPDexf(;SqL5i&`p%H6p%ko|Q*tqUkoADetSR5%cV7)1HMhk2}>^B}aOY zcO>Q->Z){X<)IPRvW)qlFst`OH#5B+Xic{-yZHXX?d^6=EcB7wEIo1PM{KLi)RYh0 zR-Uq18oGtWXdp3h&S@5A_I^(83tfkfP)FPCCbdJbbI!8EY_EHT#ejP)VY4&s6@ zC}8zKEb3)Oucj)Fd6~MWF(YO%i?0C{9YgI!g?NyA5>G;`X-RE1j=w ztO`oBA7@&r8P(u1RKCMeGF*qxBNH@ESn|2TEjns~{202ftt2F?XBv6yAW;T6a?G`b zjzpUMz+)B5v(j-$DTjnuH(~T)n1m^b>;DfqradR4cmj>fo-LD4; zcRr;~Vy^Eys4+c1fW30Ke~d%U0n|9=91`xi;7d0U7@LQF=_}+^y{3Db>0arHWt=js z!xm_0mNfTPIY@xx{xgOcY)@eoUmU58tD-jD+oweE&a5f+kx(9>>)w=FnV&BUyQg5Pxmt8V~?`SyGX&pRjgvzxe&2> z&c`+M^D4~jCX^ioS!a}s+>2d@+)2n^HqT2)f>yUG>Bl@p2c%{t|tb$tWXkQJ6Gox_qs{uu!d~b z^1vWh5z7L349&_6^HY4ltGEzLc_u~{yE*hUpzKJ@hn6#oFB8Auj3Hluk31>8xoq@cLqEuv3$J&? zZraVeq06T6l%2+7b807Pt|xLPryTSAXwBwn#LnV`vD8t}*UYwZKXn!MyU5F!pW8(_ zSePUCEId!gb{?4QWt3_@apw-RS_LUm(}>zv1_3MAVIX@9w*hMCsrFax<+2qQ>4nDb z33aBYyl0^MTy;EVRV{A6%BKRg%uwCNnutd^idffRJY6Z*#0`C*hi)RD+Xw8hoTbXH zOQcSB<5=PjwS2@+>p8>NSu@|sX#G)gdTb}%VmJ9Mc|EV&i8^Et+#~)%EimJ|n>Tq+ z&+HLDEQj$_j`dRYL&spR5on-ZXxxuk-{3do4f&cw%)O)N|B}W{K7rqPwg2) zKNGRfBUXAUaNlC+CkDy9!Qb{b%7NNYlXy>k2`%AAYN6NtKHnF(>4LwAxGT~|s80Xo~_` zdNz-U-JorV&|RM2EN|)8%dYFX6Z?(&N<6Gj7*=ES9^Y~-oU&q{;(PI^p8Lw6%}*?& zCOfS7@Ik3O*Key^;)>t$OLxM)5jh=(v8hmcckQ~K`r_$^t`bgBn|c{7h)0PPXhqV% zVy8*E8s2ob(k0X53xDM9#Czhoo!0}4eLH;J&iILZE)Q$$_bAw-!1}3^G4H_9dzpUj z#!Y)u-pJR~rQEe+%n#o$hwfM|IBpAIn_}tC>od%V;P$~X6KHd4wABLbMUDF(Qp|Bai8GFNlcSFbsI!*ELG1H^eJx#& zSIwn*O;s3EU?+nra$*?oNvz$~%Y=LO*ja{VaW`cc{RFgd2-`!M!Co}JrLU^j*n!_S zxS^<=)KB@5Jd-1}w0*Z$x(qw%_{g35(}-~o$Lfzn`)E4_t1k5#TQ@t<-G4&TdxDN$#1dbS#j-op`Ptp6Gn~`d`wzQ6f)=8i~x}n%rm-B(y%Nq_Ycsg@On1dKG zd?hCAg)*4;@X-7o#`QRlP#5MJ-;!>L^4D|yfZ1xj6Zh=C;cCD?r)re3dJ-pMk*0v)i`vonXJE1GMnM<4+|}E0Em13nK9!?o&-mu$%Z&CRVJxO5 zX=0`hV>CC5h(Ds%#E!vDjtP771nwOXn;N}S=xOxYYFf~~v2i_5i-aCsPuxrbuIFqi zL9d>B^dqGb{eX7EqfIin#WN#(8lZKnEF^BxKBuw5ZH^3@#?u6J<^p{Uqc3RUX{ng% zs4irV{bOYf<4)|vkbQ}M!?7B@45dSk#h8I_KQD8+V2gsWqFo>)^)x7nvMaC>kQyEL zy081W$9jnsmT10hQDenWPxwq=+{VyOArwY^1|`T~+!`^)VBG+n=N@x-5~DU=)o8{T#iH#m-BGQ3S8hPF02aqAD}F)bNqm z5hxoTENV~cD2&+*-5m-#zLjVtv5Sl^C00c}MjsqKvhTT$1P=}d^e|QpbC0|EQpLNT z@mW3RNQVU{0=|MuDWwm2TO)NG}Z!GzB?px-XnEsnT8xWB>JYxQ-!e^pO;RCAGodD zB1}9e6{MCmck4Qg$!ccNvL}p!YTPebSE2)1Q9hvrr-4W666X6nc$Ub`GJ(V~u9f(5 ziImbx_8E2qD717GCRM2?dS+orp7SvCNV`E!&>E;d$M1*CwW4q+&LHC&WR2}#&S8Z}%b7m{2JLy{HnCqpu=n|DEv zAb?4-*T8ObqP5Yx4W|&B0<{_sl^PG5MtrSH!Ou6LTbOHP?BGwvH*byq2>cdS&uV=!ufGR*8Ry9-= zfS-vHcmp;@9q@yVXclnnAOUdMj67UZE&@`^n${9Bf}H9mJ`PSDMq)L_!x`%tzKPcX z>YMh*Bb26DH-umfH3Qnd^36Dka5#7%?&%F4!I^;_RGSj#8d=(gDu;w>q`v?sQYo$s z;0EC|VuR%Hrj!#L^2dYNK_vo4IhI+h3S7Vh1>%&j9Kt(bAUzeN16%9o03~{{ zTmgpifPs>S4-9fe!=13&L=eKE|FSfA*G+0{15IPAM!s1}QQXg{2sX3j;%R(53-K94fdX zd@M-hw|7?PMnxPmYm zc8&3ggo2GrpP=}8(bBaJkUiA{bu)Ekdn@t{yw0VNvwhjAa`M#>yQ7nVA_ z()68$nn)aYqz<*RGT<&Eltt(QBb#^~V5)1HbmxvFe3Wg4)+JO4X8F&}RYvkUosXs5YbQd&~$X zlzZ94mXT7+D76~0C`(q=keQ}d5@CHuqCU8W4@zf(-NP7G57kVK9F5T+U5o_LPsFb2 zIkYquZ8UNk(n3x^{t@^I>GX&Rp^*aO(lm4lM!XSK*Q78~zE!G`K1q$>tqDyiN)IsM zLv$IH0DR?nNZBI1?h2$m!A7|ds{ot;AA#CX!-rx;jFgroMxOY>Gc!M{G3v~KSbRfR zYV9kB-N6~BaPp81buVJ)1{pr_XV|SacG%kyXB@qYh4dr7I5}(rA$cziunT05Us7Cb z$u-s0^KdRs66XBanWGu=xjuKctFL8aTkWeLYd*H1e3=hh%V5n%dyF9}~M_w#%CAXY7G>lXNCdC1xS& zb5NV11)&l`^$jx;YA&aGCT9uX6}i$qiSGcv?lw8%w|%(!3S~}WRw3ex-j3}EX`Q0@Abi4$v$OYF77BM^$_+Rko_}J)NoqxWuVSUGZ^5jaPGlJQp)oY3!L$X!-QS zp{(awM*C8LnXqrcVOCzF#KfMR`?ZAokrno63$n!6Tr3#n5uBLdDk@Bxn=s~U1B zXBK%ID>F?)hx){^TUq1#)1c>dU5mZuxl)_@%nUQ?j_awVT=z59%aDeFJaaG4)li{C zM$~DIvsiqpyB717yb6`uO5?a0#+2eft;^E)H2&S18|#6as&&I8S7(R~`)(9k01gg) zryiJ&!_I4mwYb!`GmbAb)+tlj<2{MpOZ-f)*-6HU)B4=^!?XwO@kM>64t3M#8_@=_FH(T%yTC-_f;|qa&$dpf2L_G!7Dxy8G z0}d(3O?4Jfr^SFVwVS76OB}PlI+8na#)b*=)pjbzf}woO>!rb35<+&;E@yHl;nb1u zm@_p{=sQ^D&(c85kg5*G2UEW0X#Esv*JB5X@;S%sf9YWDV#=^TOl&yDCIUB-i%Jgb z7nJX=lTosK#c@VfqXz3EwiFwQ32+>{cHvQCW4|1^Wj<$+9$#Pu0AI)&^;fOCW8@)r zGKJHG@~5V*QggoVmJH>(EcqrYdd(fHGf(TASQYidy6bq^)VOQVEjiXC*p#2gF5<*0 zY3@nfGF}E8buFXaucxsCuDVG1EMYc8jMKW_wcUX6yPJtgJ{28S*@@fW>-COCdm85o zdxZE&?nv}@Wyr@KXAxtStAZWhg_WL~yI!e0PB80*?x~SuY9a<2tz($krSAEmSn__H zruBf+5@pk&2Idn!lNIK62O8@*0rNTz>vEx4o31hU>iP+#BuxBqjrCJK4?}+zXQc{j za;k^En|p4f#@wPkWtGA`t71b|2+@gSG03NC5wW6~Fe}2hP=_|%x$GzOm15{of8x2M z87Rylvq`;CPGnUuQ(@6U_=T9Eq@H1Zw5O&8yYcf#qy6G6Ah**w>JG}ZMLU7g+PA3T zY@lhavtt)#tnt0U7BxeO>#2_HGe|0&#HqqOn?x(bs?yOjf$@hPnHgUu%(a5Ufg2#F z)-BRi&+Re{<+-lx5_9l#g`QXSOt0>SWgOIJ9<5dyiORCj^_yXtH^YXm)VPe~QXPYn ziA3!P+kQKY(l9O)cHN~Zq&77)7qzab_HETm&jvks}v{+AAUoAt=4$9IG z<0+@Px|uw!anhvj_+3?%5$kBIoENMR6_g%ZnGQ#vsLmPM%rr+$qB+809M_DW^Q~}R z&tBrNWWuzfgkm4EIF^u7OKcdGHbB8gMLJ#h-O5r-d z$EXXvD|#f0)=XnwOJWW%^+l(yBxb){pJV3RS7shrIuboTPmmP2Kz)`S*|QkMh()2b zTdcNP%%^dTDr=17(mZzS4ocRd%oyV2Xj?P(0w|PPhgMsFD~qx$P?}ifsh0p21H{4R zns%&IHO|%-l-bfL{fylZuF6O+>m;OAf_Id}rVlU(;b0F4*BbKi4UA}!KfyzTml`;^ zDHOelllI+)YGLF{R0$_G54}TUZ$lGh19ywLqS(gO!pM(kuih(6+r+zaz4UEy3GOe# z5aeG|AdX-9{A)S{Aq!A4BMKEOF8mOreQ)DM|=EN9cKqX5=aK zMHXvwkZOB6jVtvhhOq+W)&ChU7!3&N=pUqGylC_Fy~rShd6SCy7cEQ=O+EZx4^lC= zfGbN-O2PI+z9FPO=KJeF!MZQ>q35DS7>MUJ;u>+MjB+h_51mS$B~5&h%sXSmCXCo5 zdP+!`)-!$Hz3DzRReBm8`*F8U!tK|GdM@y;%3k@A#WU36$&oOAh+{x8?vnlcr?}Ny z$Q&`(SOtuJ>$SVF7<0x+#`s!bWT(&z28?&)Uc$IbcGypF8K>zmOw+Bw`;Ii%(|B9o zXuN$9RlYTteR=HesnJJ9kt?}~RkO0E^1R-ushzN$scAbmdj@MAo?Lj+=&jyGtT`r> z$^n`%r!tsj>syu^`Cx`4P;!H}84|l#(%7N@X7nOTGPaSTp2RhUOgDcd8r-^|raW6Ymc;u=r% zt8i&9P%p~{;~YP(p&_;FPzMG(ZNkc|>l=A1=1Qg~0rOEm*L!B#iFD&}GR&M|fBbnk z7uRwv@ixzKL^e~i4r4DoTQS}jOS`f=u`eIXXZcAw5eFGFOEGG0kn>sk(m;Yf$6Kj& zBjm(kB<=R>o}Q(N#hBZ#>T9)>>-JV3)=$&7?Xx8Pftq)dj^{ovOsBf~i#o%ujb*wq zSWPzAcZA&L5&OU#-i_I1eXXy>M$g*EJS}0KxP^xe(nw<5noe=T;52vX%;VH$dmF2? zXZPK{z-}I2MeMVvSJ?S*(Ooq+u&Gqf-3$LWC*?si%Xre~E8AgL3%)W@f5A9y4Ijf> zSaDDvru{T462dB83G9EcI29}(#~1p$`fuHFH&+;6benLgPSr>8sfM3phs2G()m1aE z51U2Y@1|*Nv1?1O5+s-_x0d7l$iL7(h!^#vZoi&}QG>6{pcEg>hwhX5QeT@Jhk8KX z2WrtC#ywfpkRYK$x`-F;672ye7xRDNyyiFh(9YU%+_kIbi~dl*%kMS*&$w8l=7q=Z z54|vp%>Pl3k+)gpD|cxwyQ{Ei5BxL#L;FL1Di^YskXH80esFKqJNL<-w^+w$g~eD@ z9a)?qF;hy=tL8diq>J{_FHx#T>U;e%{a5?c90ETITennQ`#!%B@38CjQr)y1OHIXr zIL6+PgEY}Qxsq4$LSE`i(28^-zY8zBALX-pf!fBqV71C!{ecqFXOI6uZ*K#}aq=J^ z#bbqB?5$e2*X@ts6;JYk8+q!+`7INA^3$gU4@ooDWXGlNQmkmxPw_^ht zSP?o-IEk%xdD+00=EA}&>{cwA=kaBJnO?Lf&7K^)+qll>`Gb3H{?op5omm>J=_J%? zx9E^I$oReb#r$lZ%VRf1|GsTj;){Ck{}cbyehlaJO)csw zPZey@9m}IUQ;^YJW_+!oU3=^;`8Sz3M(RmvW;= z2D>m@Si>JT3q6&)?n>~i|9O3xup7`-@v;6<{=@#FU)0BX;&*us??26N>sRJge&3y` z8;@SRnVUm&eVm!OiLk}Bk{fYr~H?z#W!&dFW97Ob*A4#kAK&1 z+^JX#?3}Xr0#L?Dqj)S1GImDjiyHk=eIc&I(r)6kex`nM|MLHk-{~V$#f@G0OaD2( zw*NN2*B|0V*oBFhqphP})QMZTsokPa`qFgnOkl^6TN|t`r0?Uu>fhW?`kOFI@X;E3 z$+~y>cbDaBaT+oEj(ZwUO?ia6S(tega#^3LQ`6=1aFx;b`AR*KwfZ%pJm|eDeIu^I z8Ty^K?eB(PzUu6@o<^MgiHGe`I)YvI9KO<3W5--N&FAeB^Sj%6svo;r{?`2}Uv@I$ zi$(Ure2M*+fC5e-1+HXpH~LY#aElh_kPK#R9ltO0xjmKG6IG*4%2|5s>+aY1oBs)W zBrCC0U({*+DZGuZ@Ex7E_N>13^KfiW9Q3FU?Y?5Gxsv#nkN+&s)k^Q|7#?t9f2jZ2 z{bv8Jo;6c@9dPOl=fmEo*ZEa=<4?`T@2Qg{>tk^!_uD-)5tzCAPJZe>r7wC}V~$nt zwTJGhdYOLpzrsF8YKwhu@9X#SgLd;78bfOCf*>n{m&# z8wrdNnoYYx3+$RxdnVUn)b07h=1?7m6Zbs5bU!!Wb#r~C-=*K`7Tau_tnlUZ!6~hL2vOXW{D9CRWX1I!24fcR2D<_tgH-eBV8GBh{JL3Vlm` z0sYqrdx_oFOw*BlB#&Xit-jV*X_>LY-YvtGy>=U4r9*cjkL7`wb+cA>->UD;Q#}pm z;%)jpy;tXHjW)Ip*kvcj3bgf6o~Et3PM03fwRmIJkaO*^gDD({6LqW(x{0mg0row< z5YPQl+^A3SReEDj^(tcA;;^D(wiK=4VsbYP{Mjzjal{&b zjXlTWI6YO*^AnWh0)6kR`a`-%JBQJnyHPiS?@Q3W9M*f$ui>nU%#@PVK~v-8j)7)*))FP&llh`~7^F4-!Uz2DzH!@C0ue=3!m`VX$vBoav3mC^d*~8@CuA zPxGFb1*`^(D~&N?3;7y;pq;sKiyg@BsC|;K2UKij*S@p(8kXFqalqIC z{=KQOM_SFoRF53KC;(a4anoW&ydF8&!B-7NU7Gu^x$=UV5I7B-7NTmF_Edb5ok3go zqcp1VW-IKxNZ1=!kL7KuX(WHI(n!fr@0MZ2!L{cw^V+haAcOSJa) z3g19z@g&SBrNwyP;EkZ;O5v?rqZT2HpyPiAlNrzqzBXT!22lhxF`90L% zQl1Cwbww+|=-*-{Az^8ccTi@e(8Ktf7UTI2e$fbn8HmH0P@I~1cc7$uA}|`R7qHw# zd~e^N-}}cXNnQq|4` z*3%lS!G*CNdFsj=b}VL!*22tvZ#1bzy={76n}yk$!ZoT+^(o`sVz zm8?mR1Jv?|XAa`5UWlhA{Wg7Q&uXk8%00O!CJt+M88bk?jhnbOE4fk_y~6rqJ5`v6M9fDOd|i(O z=4^7@VYRZIx@nkplMZl?`Ip-|?9f%{>+;63{>I?O>Z$@x-Zps8)}r=cJNQYOxT%;K zv~DZIiP?9;U8s*WzOWcB>RaIEa@JwpIBgsB1`)e#6!ziPD}{ZQdE`-h4sX?R)mC;~ zqvQ=dwjKw}snev!PFPhb)R6>#-k={va2vC2;a?J76=A3L)?*ecQR@!nahS2$%2ye) z#5|K2^UHVz6>#=de`15MD^!cO>uR${AoE(^PXBP@kF9pQ($szd*xZZ+n_dKAZ9<#7%qOd>o$ zp_i}=vmeH8g(vYx^VyxJjjbfUypz#8=#9RCSHNBYT50SyW}B2%o=D93>q?G0tgvPL z41yjvm4c=XFz(J$8tdE82eb8zdAgvD5De-J(&4kvj$S*8mBrqBISrMl9A>H#YyNrC z;Ve~i)t;jrUT2&RkW)8FBS^s9SzvuP?lRtMx}AY+mQB-##tL@NRYD1ysm2#I<)S;x zdks!d#k1U5dc=%!Z#6VbJ6H%$2(@d_7d!M+s!A0sK2ES=#+pZfo@!*^ ze-avY=mjkLfP^Q3z7@9)>lX=6Dv$b4*jd3K&>91FVuAwPcI087Sh*@fro`$&GchP} zGtT&ikhxG7@haXZ_IOx3QGEZhk=wk@{h9@86lDzPCp7X;XoDGTxSPgV-uDLy-yc;I ziLtsl$FuXg-YTqjt10RMZ@|^oZWGQ!AV!;^#VC}oV+q-o#+I!QZBW498%WQ@jU&(cCJuf8A>!(0@6UOrz~-#60V-r=xvZSSE}tW%V`-xLO2SLvl5IXW>Z-EhlX~ zyh5R8&XA<=bLgQVZ*nbo&Ewc_{G~i|=WYp`R0^x@9r^)})|k-_ zb?*roYebaMq1Eb1i#DUi5*mA~C)L;u@6Z-ibmgz}y1{M^HFnS|;;n$&)O;U>U*6FR zEP4vsI6}LCwH!Zfrg_@Vnmsj>m1lcHFIlgft$@A}+GX@80-;6_kc8d`HmhObh@kKb zC>QdBmo|{?P)3QqqV3zJgUzYGgQqsPEn0EdMp#{-{?u*my;Z><3@9>Mp+motDuePl z1cf%F(a!TYV74h&ushZc(rqV@54<9v$I;tvTSK;lG1FG=1o~Zv$$}K@zmW zFQ8AzeQU1!UMoVHzpY^@0}oZ`LmT!+C|w+<{-@wo63>Bv9#{0%ZZJ}7b_RBiXnF8j z)LsjH614L4d(@;JYj}BptsMFlJ8DN67F4KNGpb={2}udwEol$f89fwASohq9+F*1U z@yv1X(H1S&qm=C=LY8DLK^yo6YO@;!*e7F5En#zqAn*)j88x&q)EdF!7Z5VI9Qar^ z1xW!GGw5uT@qCLfN0EOy%cn>~@zNW>KO^x%& z^!`Vvf&J-m4O$YVQs0Ol>F+}TtcInEcBC@E(uytoQX?IZBIKTjrIF~{8ffVI5P&U| zl+SVzLKss_Q&N#ao`AqBYcBM7%C|jCKr*!;PlI6YWVkyXVi^j(?V$OuQbxR^qfCZD5-BL5K);R``?Frn zSJ->H5*tcydzxYa#@UMNzRxV>q^^wVJGw#6poi(L=X)%g*@&}rT z7&W1^+{1|_gjaj_D>5mAVc;FoEF&cnQ+}bBN*L|OD``uNDgPC1;o+5~HecaLSAOKV zj}`7>Bjz{M+@KHdq%OFj1}UpxiX_wLH%KMzpkd)Ic^16xWtltvLQ87XbMbjcihF#q zTgi`k5<}V&2q~fPmpF00hYvOzQbU>)%)0~+YTw7%mP4NkJ%zcW2t75W7Y+le5*tcQ zy-Kb{R-wGlx8%oM2xE$I${+G3jDfHcBc18-jA_J8k0%W^DAdF;6euZ5ir4}EKjj)= zD49}qPe+P@p7(;KRK|H{jCnAo`)k1#e94K|LhJh&Q}?Zou+YOxnHgt$DJjZlEZ|3Y zk-!=uoLGY&g8__bQu1E(7<4Q7{}pO_y1!D8)Am92a!Q<6Qs3YIwGeR`t3&;JE8y)@F$I;3HsoxV;Da7wwyFr~rAKx(EL zsI>=V!1z8!Orb6`L)ixZk9YKitH@xS^6u{ulJD~wVg@k&e4oGRc{Hw!mE4LHLP$mU zz(dSH$FjK|M@a^h%#DE*0Y5?qnWP*bgqAd^nS<{6d=DptlGp>pJ2*>HdW5dO7d}!E z!w~QrI7@8s6iOvU(anONbcB^V;YHsPW2$Ipa5s09gb_+Ei@Dar--87nEbw4~2Mat{ z;K2e97I?70g9RQe@L+)l3p`lh!2%B!c(A~O1s*K$V1WkoDNQu3dxLacD?~!Cl5r`#nsL5TfAK zJ`|xPZ4si89*rCQ`)Frd4(|N_|Ng%~fI&7~jVYu?JmxWtl*kM8z=2jYNP%SVmq9M< z#x`7vt1!k0S_;sff;I|Z(1NY-lCTrnSg{?uuo|&&#}9eHT>*MH;4aap7J0%oZzM;K zy0#Ru12rp*%0nMDjI4y7b}ZmpxbB9YB2Z(YpBFMB9TH)DD>lPDVl`ysYT&5`o8Vo8 z86?45g91?qj7>(8psyW9=7Ev`{3D>QfzfG@iUz4|a8HE{@Jj{PT|liEXqiD06UZmP zT>&^i&|e1Q`ye8_6Rxs^0pLanBgo-R&_bvddQ}5WGjJ~hDFcBrp{oPR5?r-_EE4dq z02}uPYAT>kLq9X{CIdvwfPw@1SK|_(pn%ahkX!{VoY0FPrUWj$fgS_sQXq!}{1C}F z7+($T2<{rdkOQgRAO%4Q112To4(S!knzR^_;;4pSva!vS>_^zZ=sgsKI& zrC}5Ss{kQ2jEO;7BDDZC2`Yp?BS@(Q2`hkh6`*B-aqaLX?TGXWczeM8O2D?J4jmKl zC4go`psPdvAdv>BC_vvlNbLdi3|7DgrGQb0unbO?u@K$XZsK~FnakqhK@g7hljNe8_M?!?{+U*DsY84$(r*1;VN za+2uf1e(O|iC2rjfvT>B3lJriPJyPqKq6v$o*;7xE&y#i0VO-gLeS^oO>BbjMl6e1 zk%+y3Kc71EiLNDRO|aoX4x&S1aUw`NF+*cZ8AxXu1Jq9;6^# zlBmK0*TiZZ5E)5y`0i6g5+zU}SZU#t=u`&0Q!pO!R)Q}J?V)YsA*bY~}(= z#Q$Z`gU~nCAxS zx)!)4y}oPdyQlNuD`bB30ttzA)j$g(CkMRBfp2e+fgnum&RM5z;_VE`-~g@#c#%)? zCXx{QCUZ#u$gKkkMDHZlvv5@dH0{vJ3~`^#Bna>$Hcg@%iE1Q9kvSiO993Xd6~Lzw z?hrn#(B1~T5iUfK+6QC~0L~AWLRM1;|hhd=L$L!W|NAT%dU}ZxC8a;Fd^Z z1O7{ayK10V4VV(ownBe`tRA!$0TTGax9>J@2JVRmdBT{4DzOmKmxpoeb#gfYbHcv? zsAHgKuA@azHNtffXcHX}9V$UzDv+K;MiQUMj7R2c6^u;0gG4ziU`%8nS;6=G%cqVr z(pmu84)7U|I>|{d2jEGvpDK{Z0eq0`is+Bb@@}9(Y~VY6MV%e_0!=bH$@hpxD?t*H z#c{yB9`GSnNH`*r*?}VxyLHeiAQ8! zB{K|>l+2lgTT7irEO6bcF8});iHTl_eG+S|gjiJq(o$fXs18Abw*|fvt~H=}1&m?< zt&uoI^5E~bLO7`bZpl1AtcX~zH&_Tk8v|{!b|TWU;0xbgTz!b+$GW?_(jklJvhLeSPijq0ml8F+o+*8k&^Ty`4d?k zkSvbyO0-LS#sU1vKys2D5!{Fek}SytXiLz-3S+q8F6mFQ6Ed%o7(ld4B07mMI`|}5 ze2?WUjQaoDkOlZ5e)~P|AX+A4>7lI$*wuGQ$f|>Q1L1(oz65JEXof@_l5>-PWR5pM zPhtTi3-GMNk*q`rZ)CnBUi*D^k^?o8of3=UF^REcR-mCJ291!>6o3HHB>7zfGJanj z_yG@O%|-0g16rxT`^tcZ1yCj#GVvoa8u8cfb1=b+ApAY2AT21MOteGheUja1;6);< z8)jk>x5zxif^0<7B=;cl5QM*HR#xcigcfe>2`#>7gamgDj7M@s6Jcf8D ziOA$1LD~VIL}~{PLs8I=%vCz*MY0)^t5gGuBnu!h9|3<7Cg_xbc4<@sh>MS-Nc(4Ekf~XS*p-T8p zY|e;GI2U*!^L<;eI6Fl0ETBL#PD>rOF31ckz(zb4S)`4L}GQ%}Md9b2u z065ixCKP~OCdgC-K0%@~Ssj006B1vRKsPL4L{*wWCIZ zZ_NRIK7%#>6lkdmcZ9Kq!cXb143niZJDE887i^HaO4G#v;h@l2 zd?D-=oMNi9S89QOLRZl+sTuPIs5PU$`gm0b+)jDyBWQ8WkE&gZ}cAy$K&y2TqYUtW@#~2;WY6S6~;7o_qBgRuhm<1!@YL>4dOS>@DpV z4dQFCvO!?|C-E2N06WM1yX7Swr7!ip7ce&{%WJ;;i?rW0zvf(VT7IXz@SH~Z+sj=w zU+o8Qfn24jr#t7_*lU4thT)}$Q`wCRqkqD!h2E~0&XLYk=U3Meeu_9pD#mHlD&`|I zi(SWTqOVgAD2iH%(PdN0+wdMdg1SomgC9Zs?kZlO zoJ>1+p{dF}$+$oKr^v=3N#1$fUe^=L*|NmUzrM8jb|m*&QCiJbp#>YGJZ{MJ>EiXX zXLmz?%|N!6(x6lP9f!g-k?+nYi`jS*eS-QxE4hE!Wy~(xMX~sTcthGItrYJIRxwxl zjQ@c-E{N((O{CgG?Cb#%Bob>NDsPZlqqfvt6eKO8V(61XDBXgaF!>>8>~SeA_g> zBaVQ{@Go%jE zDu~E;r6G7D9!DwZ{`BwkYpEY~6PewwxfYyQon9EughVTvg*2B(^;Y+j`q;;0U49UH z%j;2(v^Az#bdaiv_sZzX_`4Bm1I^?*Hk!v+d}}^bF0|gG9I7I{w{f)gcZFUNAv+~b zv#zsDvE6XQN%tv#sy*eF*%V5dk)d%LA)A*;O8&lczc_vP9+vU+y-D zGVnvSyFXokT+RY*xO!mO?3~ZqoF;eLjBGK%zoY6u&ey!@?)ZORUMPLGspzsz!LIS& z(;}v$U;RwInLg)uRW-CEBgZ?Z(3zq;?P>7VdpGhcH!jl}__%W4nnf1Y>}i?qK0;m5 z26^sKos@4@$mlrtN?UvD7TW^%R53)l!~CasrEDh4gWQOt|A)NzCpMGIgs##q;U@;- zn`^l7y82>XRCasg{-o<|*EXN&7hoJ^46N>O)$b60{^o=0Uz5r=@hL%l+sx_Mr$L#2 zq*_MRx9%!voF1Mx!|o|7Rjt$;{2m8kzgr%2vECeLA7J&WJW}!2F`MbE4A8WcFHrQ; zc2Q11P3;dYP3_lR$AnW(TC&J`D0(aRbCd8|)KxwL2iuQ3?z^@03?YT~aIN7x2X0Yn zzn#hH96Y~Ovz7xI><(xVbtGg*`IA#!4#wOX`q1_~{DZEhV^~NB=7$dToG~5h_4O6p z?Q@*zJIgZ7>Y7&OfwC+9x5GOHoYwp-*J|5xan*~;Q>#NPXQMRyM-PuE9-6{ENe z{4a{57rHjoMmX+?&u~+S{~M^*Dy>S%&|(`DN$K%N`v;g)rn{01=h*bGo%5sXg|yeU zGA4=fhvWYXyij=ZP|#lL;_Hidt^_{+;^-Fnsok=+my-6joYJ(PZ<#qi@5a}!*++}c z6{Xj1Rp>&(Ltg|f_V3^|Qa6Y>Z&nmURCrjvR(G!s6{aXVY7cn%scvxfJgPMNT|ZVg zckgy|uv~EtDk;D1?_VBW{fSJ zrQYb>!nnu(WY~q!SDs_p1j|G7Li5Lp(2`eWPBD_cC|jg@tA1lF*LRRD0%_YRF zZTO#WOW)rN@6cdJKXY7eRqi3jZ0qEj@%XX+u>QWj(!<7G_NcFjvF@*mv!8bEw@kEV zxyG_<)#=I|D8gf<>XP!hf znZ0Y#)2ptoO2(&N{r){#4UJCP?w_N#YsOjAK55^id^=bhW@=kAMIImCDpnO7Y7F$8 zV!TcVR(>g%P@QF(Qn9IOwaZ6yP7|hWqKq_7@?6LK=Irfmh(}p1HPg&{`QB_B>6zP0 z5#se1HGv&~nu@`GVXkIxR#$ILToc%zeG=U}SJ=fq*^t@41H zm4)q0&74&=CAEWXE}3AME4#w>)%|N^WZB?-nRK9AG)=5I==R5ZC2Q?FZHO|OUmVy( z9rbNewIhj%o37{3IgCmBW6YnC&Af8-qL)M2(y_mWtvFonZ#q=5s%nD> zbCaT_Y>{z={;@`-nMx_;CVPP6scndTv7=+@0(k};z9{|X%bdCQ%>(s+=^mPRkS z-f6L4)w%rC+k{u^uWL8H-TUz2^z_WkEvR*jU;Ab~wzn;4f4W0r<7oM!nr4=R1uZ{p ze7XH=RYgZzbNhLDT-1TE3I2)@XHc+C#SN8=RXZxiR~|3EU7AsyFSK*tkU!Ui>AXBY zX(kz}<)O?mN#@LPMc3YRjjXzE8sL>6MrL%W{*+ul*;kVj@wUU6c4k$6`Ri{#rgG2F z!H*|9JRJ7bKX-%qgrB_8(KhZDX{{EvY8l@#IG*ygPOHw$8~v&2=k?{2OS_t;^K0~W zpM38FLI3)6_rIgJ$j`ZIV2jgGv!_fd_O-llj&vm;rL0J?Mwe}zu06z+$zAdXXh}^| z*H-66Q){}?6`h-1@IFG`>V5E`pn1(#w|Z%;a7--v@+S5^`)}K8)@#BGWr@SxNRt(o z(QHTCyX{6MEsO6O_NRy0HKOuJG0N=lwP)t7l6w}XJ%Q@&Sub$AG2Qz{(0*eGn@rEd zMYc&*n<}-neQHgXV%t-3I=fPKOexpY)67ta^4*G$%uK;gYU);6(#4fh=gP+gZ8)#! zq{xbZ`u?*5?;9^Ee&?OVX`iQl82qK>mv*1}XO&dX5=JO&hONO-;cR4KbpNpHzL&HH zg$*@zSWLfH{I8;a)qkeOmNkxP(gj&`KPqJML#%*K@S9zGowpp>_UX>Y zZVzFa*cd0#y_iGHVeSUIRrZ!yh*Yv;%s$t$+UJ5?zrfev`?o$`t(SLWJ<%fD#B#6v zUU_W_N(+-qI#rA|&vsv;!&ITVZpO9VI^SKsr@bn5J5_(l%4rWN-#OQQ*80i9*sj>F zICi^%9^OUw=6tw$+$_0LewW?FD40O{IDRj77qNW^(XDokb%~JU{>?vu&4$0EGW<8yjh;%srzbE! zGv3SvdJJ7n1yeg60i*TcwXe8b43mM~&ki%bzQ3@&nu`hNmR765kfn z`1`Ie4wJpmKGHG8ImR{KJ&WHX%#{4m8EQDwfsNyCa#n7Zth=m~8^MicS28c?hg24< zl?KDg@2faa^b#Kn?}aGw7x9DWCG~}zwj;g>>+JcEv4v4XsBr2$6#{>GY7iyh&(asH zriZb?vOThw+*#%eH5@_uAk`Ni@Wb7#tGTn6^OSS0>o<2#eg$Oem!ytpH+75tkGaf7 zaU;3e+)l0o_mPccXEIkHqy7x5+Mn=y$yd4nt3jCG*}@0@rn|_s+V$Dh z-JQs*g;L?8_*goDAE5J83cZPmVK=ZF*=y`bb|CwanZ$geDY_rE0amVq@HMG7;J#BF zCUyZ#){93)4{3sQLQ>=DfXYymkKUqffJkd9iatYiMqBX)G@jOSS&$1ikbPyAQ7dp` zsiW9N_~P#CN_7<4BOT`)k*>?`Uxf!Ei|3$XYCq#(Tf^G1yZoJOqpX(0Y+JS~<3m43 ztMC|Um3UTYCwL1P{6U@)1`GFurQ#?l0{g+b`y}N@KcR;*-{^VFW9k<=keYzZ)H*au zSn9gPZ>Ptrrs>;z26`-$l}jVt#g66n$+ni}oz({_239<+j<-&5BlMK{Dl1U@t`@X% z{bs#d-&or~Ig87su1N<4KlfDU9s41h)}CSC=gf9ngcGPxbT(k)AJ+2ulWaZYuN>u;*1yrr^KwnV;O{+s%Os=CcRF&i>%p{%YgfhFa5u)SfT@d7=B%J!?(wx}3tCsU?q{?L66r@7nL_ z(y~=hG}f-+_n4DvcGoPctSy?FxgouCrnT$_-sXKEYIf|{s4o7SvsUAd;$IX>U2ORsUK>J@g*=yRjZ z8lQ7jqf%zxTzFeZ+46N<(V=2vNwykciaa>S^24qkhGWI0t$8( zIjMDS2ABy0AyZIPtW{$gp8? zLmJ!+|5v}3`oqkbib^k5ov>fB9Vi=IXsDefSI3?1(eamEJ%p&Ewc>-8N1X?rou81R zE6sNerf11ZG>iNjH{RF{4f?asg=VFisk!vMGZ*LFSoLapQK9>ZteZ-y`Na?y%rv~1 zoZC{_AWq+*`p4u9w=Z@a`^HWA`iY7R;Yi#HGWpTq}|A`$CJvsP{x~HY=>wu@s zoy14^pEp!y%XbI%jW*P;jS3EF<1cxA@t7!Aib-XEWgmOL;H~_dx$>30C)X`#dSa)} z?*=v=;M;PRaeVQnTb8{)ZQ8lFG^BN-Y=7J{E5`N8csSB4 zUKh6`YEEd5Ux4>yt(tCV?o&|m$?#^whql>cY8T7x0e7N?)Eg1*^!cRe#Kll6g+s2C z+KMXgB75H1(s?z5?1OM?eR*VB3rClzE?*PZ=y#RmJ=%6A?%0Eiy3sSPs|@5Ea?Jm@4>oQy4A*AJ(gl4@ z%Yq)6S>MX?<4hazQ*Dax^MJp6+ZjeHLzuQ`outPa(O0aszprgud#@(jlx#jHt=IR7 zo}VO3u57r>_l5IhMzhC@{`+=6_QSm5gYKP*)w*o`C;c>Iyx*^(S0ZOc#s`|!vCjD7 zoD4ohzG{nZ zf_|4~w7i1K6<@(@b%HudpQNYI>!eqB-s+dqI)o$V+%F1;G#`A`u>KLZGi?fGYeH>@-MOMxZ zz+0qL9H~IYqe1(^JBQrzoF}3Z*+=|@d1OvOnVo7C@>K6tAzWDZpdg>cdJm5m+I-z^ z-FEFQ87KCvJy85McX95!;_kH$DM;1F^Kb7>M!D{>B8)kLXTxa(ORc5W;N`+W$4txM z+WcBQ6jc33Usm+dKGWXSE>pN+pLnQP&(+Re_hwn~V-`are{qLev zO5Uu^__yqndxPSMKFzq@vru^Rw1b_jcjdPJvDTBg4|S9S>sR|dFxh`Sa4c)5dnglzM=OFyVu`|b7n zXYVI`Jym+zQO5LDzEYOT1LP+ZQ?yIHp8Agu*zfJ93B+!TwsL7%Ox0`)$9qv}Obl~? zO2s|VEM})HO*KSgS7mc~c(-e!?TB@+UFJ@dVyWvCOC7}?cpV)7tY*?>{bX-p7w{Gy z;QD9_aR$S2ANJW6ILYs&#z$yTS(qD~&E=<5?6*x6TfqMKHQWI$XOzlW`Yi7dU%fG0 zor1nOD$Eh)Aln7kRk0AxA|8k>A=4OxlbCY(6IHS5jJ!TmA^z$vcLuuW2uG#1a9(pt z>L$(;e8r8pE4`94$d1ZxG40VONiDW_-*-ibyPvMv~(QO3lu|_mNp_j{c&`@H6U^)SW*?Plw%eZ_1Ogp&MwuB|9ajhtPI7Z>f?7)8Ft+^e4Vgt;OqkBU2(kofK*zUSrQwS-1__DvlHW zrTgJ!bUVC6`V-xgL~0zfU6Rms;Ra>HCt-iS1Ty2}Xe_=)Ey1&;;oM^C5wePb(haJ; zSdLam>&1NfEjRhY^q6MQDCZZPi^AFCR1NP-tzn-DmzXJNn-I(%mHd!gM0A=snwcuZq1n_G zp-8+!W2r0KgqiOgEqgE3!w>jsbQ5;4@1WMa75Gc$Ziyv0kgjoO;9=A;R6&nmnxR%g zUu+i_vD+mYWa`b_5auy5;Rw|m`ErB#dem8_ArwjveiWYz3z#obk@$d#pm$Iyk{>^jJ1S~~ak5_M z4L?H|C>xAl5(pNZ7*0Af>}9q*E{CjaaL5CACzjlC8jF(Hdmu z1#T8U!P#A)m=TIZY6`zmy-s?Xrw{ot4*lt#DIvuy-zTsHjOr7Q{xapwVXOfpZ&t>8Q;neYx@Sm`r z>Bzhk6{sa|W*EspFPDsp*^c@0kD@33D759u-33%HSB(5Vbx@j)bE#L7O}KR;)@r`UVAIteUOJ#F~8m7cC9Eg-2EWp9f4G`*VGxNHqBlYU+JX8C zedKG!YU(u}<9;fLdx;&W!4SnBLVPX8jd1~r=DjIjyp(D~HKK|I4buus=reV| zoi01-3{XV5e_{@~MLGt1(d}`zL{SwIrUt{A{X>)jdm#~cKblVMMxR9sGfHw&?ZikZ z^GN}JxJB3Uc{C+WL-*)rQaW`SPTE)CT8P$1Xe0RQSfP^s4`Rt}Di-~XIq4c|jaSkg zAr`i#itrVYr+&k;=qz^w_Ofu08Y`}(KjX7dd2j&VqIOGtVduyP#ZpJ`aj2enE*+;j zNNcGTR3ki@`dM^Bo;Md|iaY6@LKZa#_J2O3Kd4N6Mmi32%vRJ)R51~PmZnh^x&=5i zf%=d}=zn-I?9d!Qi=~&8r=+G%;r?hYo($*vo=}s}1Se3BrHPaRZ$mbz3=P1D3dVn< z=ir%7kyC0$-G!O#FQ{qQfzl-lI*WV5x$;!>1b2n+2(>~-pklxmPAYv+E>vVhK*h-$ z{2R;~o#8xu0MrzeKqW&BZie!4BDC;9|G=qlJ*bbUfQpev_z$!iWI6_?`Ok3|sCMu} zZ=gNu4{ z#m)DMe^OCI>g8*ID^erK!5s(CA{D>}px_6!JPaU7YSl@lP!)USbrNJZ>3phIfEjZmY(!d{#T zY#|>o4gjiJsH_aVxZ2c37U@D;TtFo&q85P z_mPfwKrUL0=74vs#+$*fx`F?6M|yk;HHPoa(XYVuVW{Kk4jF7i@bSlh*lLI&J17t7095D9MuYHB>`kTNWGYRJqKtSK z)aXp57NOzNc6p78B_LaVF)5gYi$4uXvOGEUZGC=!Mb=G@N-z_rZh3zLZ2A7l-0u zLL$2fzd=i-GI2CbiJO=J;h4K6)O*l$IqJ;>Q;isjSt08{Jr}i5FqUARXbIvT>n0gT z7)#_y%q~SEx!OLj_|M#q*{-5PRV`|s*PIu8wL5+O4%`cV~uOZR?{bhXtL?TWkSoXjiED}fWB@$_-k3f&+6`~1)OHS>4rX)Zxb@%o{j#E^$Yk_ z8|3oOo%}iU)6P^jbzaWy^6mB{Jr`yS_lTYrdp9)Dzpv*#T37R^C^3IS_PJc4cyw{R z?K*BDYgW%UtSNt8tf?RJ^$*h=7~N#zaFCgGiGb8LoCag5)YOFh=4Gex;`lo~ z9t|4Mzh%ez%~Il9hyTj{R8aD2!=s^37rnmz>F+eUn8h;32z?xI;t{yL13Y-fEnp{Ub&{UYf;mJi0qrC zJ*#imY*cUdh;}DSn<759p4Gm*`I;a>IY+sdds?M_e)v+zm4y2bUeEo~C;N0og5rPm zt6J`DbEL(=W@D0WHry9DnCVbmkh3qnY5LaB@=q_*aS`u4B7fmIA>eiB%;-(^ev2sZ zWz{=SsQm{MUwkERb&ex1vOJ;Im*2uPS5k&ie!2dOe4@QZ>1^_W%zA#dEv))cm8^2O zX^1(ywu_`W=Up{Y)`^mhKr8^t-aMKQqxOiS}nxnDj`{tvek?R59Dzq4oAO|C}H zGd3r$Lsx|UuG8#bubttyq8bM_)n&?Z*bd^Vnk%_GQa7hQ{WiUDM%kF^<@PO1s$L#| zgVO``0Sffl@9c)Z(F$2-g<5@I6R2sc>L?$?#G=XK z3jTN3VMnq<<2>Q|liwrW!Y`?lbT{@b_gYrNJz)aqN2n6AuL)vv;ee}`_*NXnx24Wd zo{o{`f%F+aLrihZpME;UD@Mt!6Dlf(W!!$ny^YF5C1cC4R5x+H`54jJ~#knR!Rik?0E_15Nx|2)O_XFnSC?E$whk?vK$XJm_) z;X%4d_-*yoZ>wHsri5oG%#YN$!9!wu)*l@i9q9I$Mg39pV~#dM$hun^ZeL1yX#Vrw z8ITyb(07r?6pFU~Sneo(T2fJU&9MQgl||Y&2JG3_kf^?b+Bhee-&TJx{cCIPRG`+f zHLA0UpR^xUc6?f%Mnx7?r#Gx^5HV^<&1mfpYFFg5nOAoI=lN`Q%D6X2(!HFW!^67t z>36M-EaD>j%(T38MB$js_Fre^-?S#^7DfD9|4h9tewC^osMfl!YEaRhyn&@oi;YRw z_w{;Yyk$sLKZKRyW&3|7L(LZRB73ngiI(I&RqxbB%^1aDcCO^%xNFf{-#eQ~5p)6@ z#^zC*nLW%|`6248voG@iw<*uaKVvgRdJG*m@qHJl{J(u<*Rlh__mZ+xYMwf_AkKSL zqo*DFw_O-9!kzf_%Da0R6HSfKHHBF*LRF);`n3z3?VZ5sYRtvI6{l7C3k|qpt_xQ# zKdD%)>a1zcwROXxYxNRykT{-c0F@-yX**Pz9;Vu|YpBN9>F(|r?n=N@n8C8=%x$z7 zYK8kC1D?T-MP<%)j7Zm3cP-ylf9_n@4bg|$AR7;e zdZA#czdMk6EhX>;Tw`jWX>y^#5n2DzFDEBebuE+DT!~wKf8(-$@0HADJXDuuT{ZdP zJ(34@b~TPw$}(R+?D}k8{$9F?&n`c^$2a9VRfbms|0kaFkgBwGCX?w^RRj-W<@)ON zx0!?DD%5~&F5gOp+Fa#X<)`ch+5Zfy4c%3r@OJkYz6);5+=boVP4*V{<8CjyrK(6Z zN12F>Vx%KT48%*s@yb@r;_B{s|FbrY${oCEQtMv9^0=D~)_AX4dhX|3LAJ!F6}a`! z!QB$hCJk@kt@A25^L)=kCiSzUfv*^KAR@`9iIU>3%RS^r=smW@#Y|qSB5y}SEgjf6 zst@{=;McqcfP~$5*&->Yba_)C#i9Qqq>yUihl+I%` z+zYx7HGuyGvm)(&2sP$5Yf9-^Tg#B)Kb{}iqSrX1=c{8|pDwMxr!d8YVxo69nUxS8 zaX&E4_o`Q#a;~K`>+btopYE1qa>K*VH2N0*TYyeB)sbL|G+i?PV@|Z>S%2rd$kyxB zJ~FR9nssQ3?W`%k`hxX?doHzIHiqjiJI7sOeVIsVKHe(qaCdgLbf1JB>H(Zl)=t)) z4WriMHMl-cOK;pqocGyDTs_x|su*Xn|G^Hk2WNNp_bdE7`C#&@<~vtC+G4*NajC_i z7WoaEg~S_P$dvARrmgw$-vYD$s<^{U3P^}u8b2oVlxBBMY8pjKM4D&=8 zuMN>_^}gzTR6Az{oLxqk$2p&38T>~NbJZTofm};8Slq)WxlcI3Ar9&858^o>$=q_5Ipt zS~ZR@^}8isEqu1hEA|$Q$&D)9Y0i;13Aq{HBd$95oxG~{M!~$C$0Zlc5Ai2?Bh5Sy zg*H@Msl-f-Fvc>=6lU6EO&9#QboE$mh-ROx8`V~5;=1Ns;uPGJ#N#>iHMRjag&WA; zLz~1T*BoJj@PgmPCdj6_8&&;ayX6ztdPM)#oh9!*X?y<>)(<@3PMMAx#g1uJ@Pk+V zSf6>a)51C1|El&BJ<9D~)X=(5Ap|#z&5Rl4{|A?4ep58Qs7*zXHBNlY&Q-7U_|rq} zp;or07rO$?@2Z(vg>x)gApfe`rJkawVYTSEu*^-l65URIjo2UdmBA`M z*}YU?_x~gipwY}JwVYwqRU%8k3gKU|6 zDvQM#4y`TNcF*}<3}OIdxtGjEPlwv6gJMfDOS~&S5tj2=0)tvG2U*OPu(zmL)CrMu zAHfo}%<-+_v#s2_ee&U+*&Wsd_ABms>&USaXQ}4{%BIRVpO?Na?-ySGdF6QD@V0q` zpt#yLr434G(;*>65oqXaIHNfyXW1yaC$16S^Ap@{UAfLHE|t`Pso|O{JmtY~=F(E= z#eWqBN(pe5n@s%;dlJuJf2Iril{!pW@hmKZXMY;NQwcNRIiml>M`$2=&EI6*vLBs8 zD?d38digiL(?*#T=9gK6-*&j0_n`adE#;I`E@Zg>=l&1-st*O+jdDbm`n{IVcKuXy zyQZ;yk+_jwOGQEAK8|l7yMv?7?BPBUwcNy0>uEHPtnqA4*MSKTsWUusGBG z(uJfIbbq#)Y&@GK6$>}S2x%ZZ7jT3zql4%gKhh~sx0y@M9=2cUC=a!Nz3B3&ral%X z!(3T(zIbcZSyPQkUG*YABFmhcSh0dXpz-tm#p|j5vg(wqr@Fi6Prhq?XB+;IP2{gz zhnP1xeiTdbG@Rw0VeM+}Z9l_T(H9kClf*pRyb%-(pTne5c-sXq7o3Qs4DuK7%Lxa>8yf%ctic0kVQ9j6$Sj-n* zEqPTjp!TRKxOhQsPF{6srG0_?ld+B8aPM`xma0m{TdlX(OP^21pVX&unk~BaXLFU~ znh=a#S3~In6~Z-O z|CILgiTptKN2!R*kgeth(DP7zevU&!C(73Fy_|Y_v$~t_p@{vFbNzkgf0;9jE*IV` z*;qczbjB22@>8ymx3$dSh*yMrt@7{S8>HK#uqZZZT>4tCL0;$8$tc%0zXqFkIR6oc zqe(c}{l$`Cx#V0Z#c*HM3)B^CGCC1_!4DH-=>(aM$&vzv zA6?7%`*<(&lxr*hf$oc&3wNCxs4m=DLGJpA8m=DeJ1Ht7YO{ZtTyE)FxGsN7af^y_ zcs^}&$>coW{PCrQ_UZD0#xlQ=KI8QxRI3$T)C&xMdObE2s_Rj?j%f1@^9komfrUNC zPkfl&U_a>05(3z+ide-GS!cRT^cIuxUOJdtz%^!mL*4mFt|-2~ScCte+cIC!L1~jP zUl=b9r{b6q?9WtFbXDrcAE%BnYu*3a8=)HYLq9{*#;7*_edIRl@Y3^zH=yF?tLa^J zQt6}oJNXk!4_lWqF5N-z8ZTdc50y*tR-LD7W&GmVOB2KP;15^_Sr0ky2_4{>NDm>v znQv?En8WX&_Q;UpHg}2YgEPhTQdhA4c$twMih4oq;3@Y!u_MZ%meLpnNPZ$CS)}_& zq&(@yC>{2W4+{;cO2(U4+90b^#{~4O=NX$2)Izb;(y{PNjz_`l(&1H?s)|bkiZ&I` zsyg6mtBmo!=(pQ977BNNSL{-SYNu*DYYxc^r9}H5=8tBFy|J(WP9?nXK%u`oo&N(* zXL`#IDCWt|(=}2j@elDWK1a=_XHcoqTH!J8;>W@x`roJn@HCqs&6hghLNtoj(_QJU zu$K(a1H*Y!Ds$HLsK(2+N$ZF@pES8iVo-A&T)6zh-|x<))yvB--B7WuLQ(zB#xcKo zo(@hNz&?kzfr;^4`(sq_)Z=U&43)n06rHj2^WPB>hcfO4rlcmeXK za)f013wzr&$JEI&!DD{H>W*_;#s-?r_+7{Qc@M|DpO9@Vv(>z|rQl)uAHq`VN5;I)#2jX&@~F9u9yBdou9ffb6>dcp5hwfG`Y%Mvz!~;^QEci z81qIxTRx2Yi&+cj^8Vb7f8O82lm8&h#g(q zsoUHDzOU)1{gwVm6J3w&cC;TV+4OMRwV?Yye>$Assv^|9L_Dp(7wvAcE^%GND{Zms zd}Wi;!DSKEPt48jSA=3VN2~XV^*`t}Q&oU}aSXLKvBue=9OswUMh4h&o#8$9H%oye?J(n7SyzwZpH6P1gmfDNph)Yl;AS60gN8R9-rALDhKcC%)proHxcZIHA`{Zn4&b^$+YaaK7Jk^VkHH_eZl zr_$R}tuRZz;m-4{QqPJrBr9%uC&)g+D6w3brzzJha&0cmD0@5P-R{TU+1V{6?6=aG zyEFd%;L4l#8a%!I^zpOe{PW_#*uqw}`aa!#sm1wz*ET#-(_*q>at~IR^mk+5d&ST$qs6LvbIo()Np`n2()L45o67IX zZ&WRJuG9otUIf{KFZ+iYuLv0)fB6eJ$+OV0&-#ybgJYb0L~`nq4NY`QG;vbCsFCIh zd(~;k@;&bQ(;4gOral&jYuai$XqHQ(#pyz@+Cn|O|-8pZhk6O^=l|xxAm?5 zsoGTgX6?+HMz!xdZmX{t&ii)u-|Kh5=R?C0vA$g7>gamM`G#YvqnGQ3Cr&NF-4ugP zr~h0xQkyCLA^0jKZjC2So~O)JbjkvpO3f1`={4jf{D}SGUtG?H^PPo*owC}iP?OfOI+&}T=$-l0DlzykGh5EJbi6OxF zxA}Qszj{j>-j07Wbg^`(s(s<%!la53j&rJ@9j#rfxhh3#M(E;A(~txAwYFG(&vC>0 z)cTpDC;W^br3;!lk{en1`9g&_TiSx1A1U-wx_i#L4|&Rz0^uR@k8cR05aB%~E)@F+ zh#V;&DQ$7uS}gpi-jTJ!bDSMMv+k*_(Zn>2>5=>T&&gUzcW2Y@sr&yvcO^a9eb2nu zve?v4A8%adzds@?_HxXakSE%=YSn_1xr<5$IgV%@K0o^=8uhpnG((uI*`)hLw_Vd! zJ?R?ch;>YKb(Ld;kEJ7;FinuO9@+MLgm`hJI9OPwy5)c5jq+e+gE~yOk4%aN;wbTL z@g`22r^0_(j=KSEP^%(L^_Sy?mC_XDlGRe%MbodruI_sVbZZ--oABW5;oJkh=bEQB zu^-X>WZbW-)tC(n{llUb#&3_W34dw`v;SROo&R0wYWtUBSHmd7E84NROK?g2RNoX? z`b+d*3vau=ur0FsIi`CuplilyH%e`VvC1~(fbdcpt(h%#71k3r(T zBM!Q3sB7854@^oRBewpth z%SuxtQSa1RbF5=s=haRct!A)b^}Iy>PokjF9MN{yg=;?-2P?ZhZ9S)CR5ueA3N6&9 z%2D+Pz&c;tB~6467%y*jJy8>NJrsAvq>5h*3zHka`}yG3O#nqS;Lx1bE(m7=}t-;E8@ek!~XR@sevTfV@&I>#j(9b+h zTDcRk)SKeF zni{FTcvQLM`A&K1ZXjff?UccWYQx)A#V>0sK1kgCexK>N-QRSzxLEe<<0Ct7&CC2c z*PYhw<=mn+<~2!cx)1F7R+HZ>&s`I1huG)2lRP=Kd&4oe-3oXau_R3LO%y(M zRk>S6#S)H&!UEKzLkLQkUdA?~)kCUlWd z1w?*T_*6GndjVmPcJg%33e?6J>|A5|TVJnW<&*91S9{Kz`_{~t&9|pMJ`lcl^7;PH z-%G2wd-cNXdt2n4?Ndg-9NMtG$*-p73wx2SsdlV&NmlJccS=FcoX~$8SHyb!e$c)F zAGf#pq|Y)%Df%>PUhxp;4z1Ok;?rOIp=YXkRln6=>#G-jsXbqAv1O`fwKJpoJ%e;K8&nKOt$6bB@1PNE3?m52V3_SKh4;i^SWnz ze?B|?N`v%n8-*otYrnbpN!Eno{L#tA_KVN6;wLG0o=(r&SQ+3bbdT{2lEw$sgtv^-*V}8DZ2hR&Kd{Z z@AuyVc{kuYzu;xh%_U#`AS@A<+&(n#(PzaWrJva@glb=1KOt|9Jid3Ui{+V@vyV?Y z`~3du!U?v6!diWY@D8s;bw1vCUegTS&HM*@KbSR~+@?(|j%eFg5i1{c_l@{=; zk5!3_yB1jdtoPMhl{%zotBZpN-taWoL-@L_47?OtzS0?Md@Hhh`;8;rv-f{_fADX? zZ{3gFIq8R9M+<*z~)an?CsIINAu=K^_Q|boEiUHqjPs( zuBy`d1k_)Yu({!$MoCRp#rya>D^pWf-`RC1Bjrh1woVLw7^6mSj+COTAwO7Nk>-@{ zO@BY_K-RsYA3T1RX@LuaHwQNeFE?cyceuMP|ob#V)Ns~AA-KB{jTBFQ}$;eDRIUo7m_FUe7E1d&QjF7 zrPUX|JGAfUo~wTqEH>V4P`|~0k)&A65FFe5)-`YH0mM)R78 z@s`MWKHWq=TZiJd*+r?Ba<7+P66OaqjJ_TBO?Wd)d&4f}yOQp;^D7pl9dR8ueVYE> z6E)`J&k5(YJ{w*TO3>rCcT!yHgQzcBH|SgW;e~m>&wRgk2l`tgk{NZv>F@N!hFrKujE$FkNI;8BMR47Etb3aeHB|2_q<;F;P*Vf}J=U zT{0TBv21hp%M&sSv)ZSApD9;`YkUGy>u*gu(fF=kJ5P_AFAF|Mdyq4>cBiL<{H1YC z#Gq(v&>+hPrYdK7!Iyc9$~W0pS!d{G1U1!t6zz!|lY8_|H@D;UtVK)bOmB1cz8B7x zr@s|;x47PMRO>sfGF$)9Euiawh#MY>IW75MgW>v^Op+#u7Blc*Je;YfXB>a58U#A@IoEjP2 zqSNADVeLX=7noP6%Une@KNog?5r6;Qv(>ht;R{~*r0wd2c|pCbwb`D$UZtOunyP{v ziJtxXr~ZFN+hTtUoT|^abt%&3+{r&(n=Rz&8(Ti{AK+)OBpH@z2g_4xLQCx>vDG_; zU-jes!~CK(g<%8yKgnElH_1A*L&K?)XI|@^`(o)=gj4hHFx~sF{MOOf(%9f=!YQ2e zGzy-P6L)Io{>!KIrT63R_WWl+ulCy_te)EPbES)mx8}c@H8r(w!6Xf?{Hc4Mn7KL z-}TtB#vX4CuI^In6qXtbEw(_n_JP#LKDN?q$d~r!&w8qN4D7z<)5UXMbe)>Mt&W$@ zU%X*9bojp4kq%p$Nlm9V-`Aj8{r7&z0mq)<*F%MEoy5@<@6Jp*plM!gOuvwsP_Q`n zV#as58qe3UZ93NP*1Bbxwp03wJJN&JS$?)%#u)!R-@O6D!jd8J%c7rUz4#@Dtb^^fl#b3R5BlvXwmiOe}CEd~CG z(}qQl+S56}bS}Tiv%k_lE_hbby`+EHI{DS`(aBw2{V&n2*`GS)+MpZPvioTKBYuls z72;=+5y`Teij}8jxoP*GAIYCACe?c@acqN;et$XJmoF_FUfaXb&H07>fwQy5?w1qx zT}YDI;ha>aEqbLQRIaaW@Bg9klJvUoP*aiZqs)wo?onI%P91IO_Pg`=@5=H6-|qZx zpl)x|7p*onTpykkRxfH)km6|h__uR`SA$E}#k+dl>|fA)urwfV5VGSASFA;qFF*Te zQ5U)(F{Wu|*jan`XCv;HrvC28v%DU$G(5_(M0Zv5w|0rx!e%cTlJ`|fFQqv6$GF&- z6yIvc;Ih-D*J}%$jd62ygt|_jU^yOOuvAL2Ev)>0Y-@d2daQ`P|!llG93;P~uoi6OV-s52LG5PUJ>zl^+{0IAg z8vI$z>y1uE4Un6p)!q(zvcD=auw&zejeiL1qThuGRa3E*b644Sd2;dl?kj=QOax7 z5c{~pt>4vbbV$;-rU>&BeVMRU9w*;cMj(dxojbwxwP&m}&Dhoypl_#0$cF#KDQPz7 zHaI#J&$suBp3`Y`&$%s!imp57jz2i}$Fq#`QrC9ru<2aL)J7jAIqP2$+!>$TZ1nw@=;_=z*MuDGOMp&+(kFUbfD2|Ec;bt6j(3gT-Tp44(p@LhVr4=UKJe-SJ`r?M-Qm@S8eR z+N2NEKNh0ho9r*_KYKQ5uHpP@g=#@z#|n)@J41LTI^?RV$AwO3aE!6Tg)VYJwAkR; zhnG^XUwZa5zj0+Z*9iTou+%30E!V{*YsMD6o3=Hxd09hQG<;(!@yQIh6@DQ6eai?> zgVL7oo6~uGG(Q! z;t)EB?X`Wi5yE_AnN4u4D4TA79CD|5R?DAa^Q3OM@7(|6fhjYg?0i*U>jkyg?{@U9 z23KM;E$`V57WfrLRsG<)qPEs-(q)c#9qheL<2=@-LP`)mZkj;t-{L5xjr)c3iEF<6n%GGDgC;^6B0dzf z!VF{;j8XTXPQzdFP$5RTE%nvBCe^A%a+N#-RV7X8ZRNWBk#Is-r?$|}&`oyFtz7BY z5F{u3l=v`Wf>N0G!?PtXm*l@F|Ejvk>Z9EEX%qP%wj{j3INvE&eO2jWec;+Ce=Fy! z!}TXEGXsA2jn~chw6nQue{;-|r>c>-(ULEIru)|rja!f&+35NRH~m^DCvfk6pkNR` zkxpt}YMfGk;i;#{^^JSCa!6Pyrs4+qZDf4xMD@fOf?F0ni#)-q6ZJVRqOL}*@ILA& zek*K1X5}oojZ&rL2tKIFHeB2!j#is_G|EujV4n!z`TD-bGhZZto}I zj{h;t^P~DUs+^n<7C{;}!tMT+!eqqF8sLV(pXzDUKfQxYmoO+|)?ux|@7vTb)Xy>7 zW#kbo7q$wYW4>TysWd}=LO9+N5M9Va?mz*u6PhBs;123eoyKxdZ1zO}T_yEq2gpJ4p7=ap)x3RCU;M5+~X^^!rQ}_j+YLRz)3(q}9{>W5R zx%9z$dSR|)R9$U`$l2fOTx92L4LKVu*SjTboS7f<#6MAC}&2d853Rw=UWE_hu zf+ko+6X77VQdf00@-QBtVkxVCeukQsgOTxZRXu~+wMod$FbP*tt??FS5K)D7HnKoi zm->c!9#OQxsFv6r^?753H}QE>tmqVWW(mG~4&G@c^aV!Zkf)--zC1@>$P+|vD^YE> z2c8cScHznG*aH*xDgd9PAXB9Vc_Gb_%W)T#M?GpM1Y$*@L~##8}0kuSDFA=!49d9AqSg0(W76Fdjb-f#2JJE*H<~Fm@*D ztLD_@-;{yQT44?0*bO80sT9xD166pC?a~(+EGlMyil^DW0Um3SsnQm!_XUKv zLAe&JRRC3oiQ`AZHw%giQLRcF@%_S|6a23EjU>LB6M%)Da%3C`mJyzC&rs=G3tWKRQ*<$as= ztO+f9!7xXPeL=jHx>?hhU1eCI+S@gQU0|5o#SRqg8o|+7a z#tjZPVhyY$ug83~b;JL~h5~%BcLMwP7yv)JW^fl-8(fd)D}iZd zm9Y{#If4+g-m!|$i4*3S`Pc0dD|)kI0I|T@&soTMV*iJLI?ULy`vPXufkxT&r40MX zOsYK0qyiTPKu}WmOeNrAA0g!Q;TZ)Sz}mtpsLBp1b%DMj>-H=RpO)Yxn*AKy;3y5o zV?BJ*c@dsuJ!EgqcNJ6`2^wJie%7aEZw^+sF2UdR0TnB1vko?CrV6XFU|k`|++vp( zVzLIAh0IXP1U)~;T&x#PnrHun7>vUXE)K|!U_2iNnyA8PrO3RB#5<3GXZD6@1nAf! zCm8djVWu2lQHQ)dR$^uc7E2xG8vuS8a5aIHD+fNKfC*ODPlWs@lnsCt5&uRC6UHtD zov>;(d9egg1lO%34F4CveFpr^&Rpz0k%sja1Cx=!cqy>Yoi$?|c5?9r{x!I75D5q> z@c#nfk`<&`{XHG{tpaUvhuJ}Z9jDkUh}nfswJ}x^4hTzu?FjszHL~OCxGxK%vNAm@ zRP*^F;1hB|%~W0&Gjt0aY2r}jUtzA|FZ!zq+D|=`#BZd%sN;N8(?r&4=Ll|PkhB{2 zg&fF4D-(>$6EQ{nQk~=Z2y!Dze5qC{ZwXb%9ScInr=q;2{S#7So#(pJQ*%je=b5Ee z>5J5H!gP79I9`kvI=CfNN%&a&1GOkl2$AX__v@%^uuSSKM+(!_N6M!-LF+7RRYH}K z;&t_sP@);?*s5GN>{B<$bA=INJI_3|qxiOP6?F{J!$HW?JQJQc>$&rUiJEWKiSBaE z2IB>()^*tZLi3U4syIg8D>Rnw2){YQlt*HoW|LYd-xp%VuI^gdDNK?hl-D$?ly5vo z+#@{g1W|uYXIHfD37!NgS!)nd+{dMlbi1{yB@Jrc6uI747D(S~nk(7PeXeY!uW(%R zQ2&MIbs4*;?IM`m1B4s;T0^*UR7rKORAQvj(mi>nYmywR8L0UOcbeOIPPji+S4nfV zZwp4b+TBGkXtzkigi6n5)aX5{$3 z4`-_tO0`_5>=Rnx)NQFS6}forkv)71^)j}r&0+I2#d-c-XuA!<3UF^fRDT|Ue8R25 z1Zdnts3G#HFkToc>;UEVfKFcri)bz?i(fz$@K4lwunJ}gQ}Ej%SRb>X?H=Gnsvd4% zABFW*3H`bf*_8c7BQ)YD@EkjZ9EPQ|0GYiRY9HiA_7f)7$)7E-yF#I-t*ArSNSGzO z1Kv^9-_$?w%vxbRv~+WIB;?NpXwfUE7!n1mbqsi{gZd#P#s{d+_8Ia!FQ{E$In0F} z^CkG)rcObfbrsdV@8ibHD(L-|fPN<|v)iy&W}w13XkA@^3d$kKy=;s14MTnZXkn1L z5R&6F*Z{D_0T*j3Uq%+_8svDs0~@LhMqUT_I|yS$AMtls{zdR5U%)mz0PAxZv~Wj^ z;DdVfd8qXLFW%{|zNQ|;?+=8x)B(ubY%f?uL`rZA5`-f zEFvHA2yC0N$f%wVD{`k|L>{NVI1|$1Lt!;!T<_or-{y z-9I4R_n?w|GgRg9M}3NIxEaw^outkH5=N76vp}~BCD-WRPg6j5Jz}HQjpI5-{ zzKl_a0rnQCwqF9B!Twoi@kuve_5f(A9jxHX;OfJ`&u~~Lv*9zf#IC#tyY(#mhXc@F zpJJX+;V1YaPUtMYUmq4_6g-5B;N4*GNe}2#YB(46zF(bI`xSmcDY$SwDD@>U>xPZ{ z2!9LM)nxoQq1$fO*-J6lp>$~T_Cj}1=uYtKKzL$N`1X+cGaz(BZx0rxBd6SoRb7Yg zas#+)0N>|5NRSff!1mCl7h#FFtn(oXfw^<|tr2ix!V}@pxgB7gd+_cV%$R^K3T431 z17I~4T@!S`<|C{^i|4yyBpony36f0@iP0Ar$%Wi1fRyPBieR6U3Row3uvwl#i?g3j z5LWXP>xux5OW|$3sGFG`fAV1GpTW)Gv+-|sP*SlfH%2#tw{Xc6D`!6}lnAV|l$gyP2r7%i zCpp-&9LV#RSYdjdh0_oeuESWgpx7abR%<(8u72HYAsG7wEEoDbaj<`afwy$vDjU@1 z^6&aj(GY;!!M;mq&tB>zuu}|#$SOdzdhE)~}47vbeV?agwHwANgy8|_X zJyi)C$_;+Z!TS#}iW%662SpWO-OnNCi8~b-t%voO!cU=JWdsh`Wz7s~4gv<*Bgqfh z@V?lGH0+-NyudC^^kME{{-^j80c^^EI0L)T9BX2?40iW1!5>yZ8TYZi2<(3xW?=`# zFxYpjAHfcITFkD(E(?If_yZb)J!{zAr#YT&i*a5B{SU<-4YUxg;Bq`m4>T9D`XXp6 z5u>~figknP{)Yb3U~eZtQ@sVKQ`H@y9j=SLHM`>=q#Q67gAx)jKReTDkXc>}Oq76j z9$^JsVfQ3(jPY&+~P_oN2AL)xcL{1-6BU87Z+2aME! zM(F!hVeCp^jlB;WU@s%~kLWk)4C$fVnbI z6Z^vWg0@*(gS5i#bhLhrc$)TdD0V=Az0Yn^tjockuk32+1FSc|Cob%-2fwk~6??sU zAcyId$#klN= zMIVcOljzHpVJ1ojZzU4S4%PwT&d^_Gw^eq8tOQ29-Db(FwCxFx558xYCibqRpTsxw zK?Us2!w$4IJV^{_Fh2cZdQvfRUZZ*h!caKndywMe=QWYK#~7;WN@FV-@Vz%pIaM6EPQ~BnIr4x7!`PPx1}> zA#rsEtcqQ<*b&YjPqA+y>56q+*q@btD|foKZY}io*(K52^^;KrcER+)liWG}n~@5R zLi{mqL64OY0>(zz-HkB|_BLh}8FpP}e1TP57+Ya{#`_<8>k&G7lk7mpE^VY(zQf+G z#2TX(^jg{NjCildp*+EXE!HCZCE>p?~{7{@SL}k z8RHM^B+D2JqcL0!E7*A7XCG&B7Q521EV`q$EP;(JGly8KK(JXQy z~eR|0s7TgBfoVF&}&S;VhWr+06O6>351Hc}M(m2niVl^9{K zO!f%$@{%uhitFP3l2=%xh;oo~Fsj2ipBsO(;~OOg`}=Xt{6p!$_!PTivmYe8SIZcK z`)tHdCHR2RCw6nA^dt?i?;1zqsH|YbC@8zwamN|aAx25x?9|GR*$5{$@96VwZjy_lVu}ymUnAP8sS3?8GhOc-{`X7R<;#+{7Mb38|IxhVu|hq4*cFgfp4e4Vf{dt!ykOr&(hVt+^`9u6SnJ8lP2@4sFQqYQlJFB|f2^8R zO`2fcBlgi`7eICcB=@kQ6vtv$cjA;WLSm0PgB|z0U5crzNcZGp#xDs~DWJmX5uPH& z(V}8>)4M8a6>=gwM*3h5@{zZ06{()GQv*0kpxa9^Mm4C_7f&&|NEu1KW8{;#C#JkR zz@F9ok8Ae!vu4L@J0v!{ep6mhA`o(}gs^gLe(;AQ>gJTNXT{J;oY4uKv-fKNptRyM zc30)t+LEO(S3x7mI;I%1U-%WK}ClI|qKqpB#yFMsDDz zwC;jotwcftdpn_1V>6bWi$CSSH8no>m7`bzV?J0?OINX zVb?+0*jju`%rdS{{-pGyjHEUu-WbJZKhHww>~v_#m$1unFg`h&T*$uGkyu;(y0e4W zI-G@o5*YEb0ULR026W>~yqg1Tv(qs9V%CFS));@Hu_hz-sRrX`z!H9nCv(9YjN;QK z<;XGclGu};v1<0TWoOZH;Kq#48)1}sSP8p2R^U7KET$wQ?1Y^7AP@WxRz`+BQPF&%TnfYWMdufyqwCNXFp6z8P3U`q2xnaER-`mi=bqnd|>S}+9W!x zgBCG+c5)WllZ20wpZ(xz$MM93d|L@<*ddf~{!hbtwJo`c@`#;2snf{2dfUW2imo>2VBp5M(!K%1YXuw7aS8$dNo#AU@b3Sp%ve)&hYO z+OO<@ORLgQM@^(mBfeqZO!f!#cBUp3a@Xj)Qs=RkwYO(GWv#b=t`*PI#`D1lYiB&2r%(Lh2@Nqzdf}VI8!bEPIm%(u7Igtn3yBw6 zzg1WpwGDeH(uO8ZD)Bq*BFZ2$c7~FH8l4@Jspr{YnE!Efb}407Xr4!qqbY024c^|; z)HdW;o-uK4?DQzZ-ebg_eJE+E5NE^+DUJJHfzhbJ0_)a8dx_mxd4@+@gz$0w?8xq= zSjrnS#-ne*uGqw-1Kdd-V83|ETzefqP;vxduX%bxSV*zl2~r%r2tG-VC>+>lzv*y{ zM+r%aB}K4zE8pZy)QVgqe#L*Jcdu7MT}-*gPSj=D=W8Q6W;r;g@AfMI$U ztfJCmPTHb0`JWZSHISyrE$nPb>L4Zh;%#b#ygCV93Cs~T6Cn2itKy}>D+h+pb1Z)a=oX(eSMwI+KV zb2a21au&P3R{`S|V3T$%&y08$O0NNr07Il2%0u=frrx0pqg}@isa`9Eb_i`waw0KJ zY!GseK@H0jQc5bWjQxkHlSwhB&e{CE;t%xF=>eNvHLJrPn(OqxoNMG zW2q5ouh8%1=_VfO(!v)1M{}Tk&~y-5<&z_B!|aHC(~}{3mKG z&dMDpg%D4a)Z_)iLyVb#X?Clo4MGc&Yw^NMoKiMWh7c!|<&=T+1^Fh|%klUfrLm0X zswa1P3Saxdj5d5k_VAr1i*(6T07kZOG}CwZQh39SoOCndL$ z_q_6g5{WCLMa=H-w32E;fs{*}ljpUZfz-q~81LXnv@^ISuf@!rqa8si^2&emK`qw9 zTCQf`DFEyAVupBk;)fJO&m#;!i~&)bkjuR{IqabD9AKJwWxsNAtCzYc<+vL`c#^wI zdz7o8T#LX6+yyJ-7JUHTN1$Y<#YH~`gJ2ZiC7^FX`=7F?x(=TbU?fdyF#>m*+({is z-ZA{~E$NwE<=Nw$8i78$_gQ-4F8oHVPI{-OO!{EtioObcMXyYt zJY=tMf2@JhjecS+Mx2Zt5uip=gaiCd40C;6iYE2Z?jfdR>>5|Vs=&l&1?ZAI z!@Z&HPI*epgZQAm$9<&t==JN|SQDiJC4_{xDap8(#2aH4)X&s3yx%~7_<#N=qkGnn z(Egz&APkHNQZIR>AoV3_h}1z$(K@9MMVp4wn$m~7L24(|ls421q!h0$LJ3m_xcCVn zq7CJZYEr_M;fFp2ZA>HJi2_8twLvLMJx%M5kryvrF+$9!5V1zTgc6E;NlT6zvOa#; zX`Sal+#Aw7e;ECuh0AKm#3*$%$EC&SwG+sl0oZA3Bl_pXpm{G}Fos0=K`)zh%UBJ$ znx9h>GVaF+2jv!{-?S*`%`i&IYSJOV7b%sP=YG>>;f~VxV`PbPkz7P<62D$cmhypq z0~MUCX)ajCm2uUP@+!lKVy(ssRM_yZj)LLqHkyrKyui z&y?20Gow4+2spW!FfndJO~TdD|0BHK$S}{?_$K+1aTm&z3XDem&RwU>=Nf5oIe}?L zQ8@znj+O%D94$Ob7%%-gF;*_t$5^WgbMkwRL3|LaUjLD_#>hT>ybA0Rnr>nbC=aL& zspYBX{OUXeYCzgU^vp@s0iZ3~FpRb{Lc=JnH_k-d^Ep}_UcZgn!)xbqHd^1*HRN*2 z0k4Hc%~}OIvEwajN-rLWE%G04uQB%R#4ZN_KRWC?B_Vm2`ibK(GDaJSuu#I&SE5Ft zJw}^`5|f@eq2;=0nfcf0XhwS|1GsYT2)UWIBH^e6Bq3NUqn?zB#0o8Adb!@{A$=8U zI&uwHQC-KGq;CVPQ_6bkQpSO}3*-<|nhyIx`CJ6brxfL=4~E;A^VRt2N}XT}o==fJXrEF(F-{i*xQJ;=d-~3#9b%2K3u+j~I9L~+8j834 z3bF6JT})q_qtU{pCLwS0H%djq?zIT0y?H)G-eJ6imMnLP@pEq^lqUco;0D^nj9GeD z%bg>=(K4bXOG>Dy+b3`2g;8F{?#Z!{fX*wU=-bk}Bd<3*bUl!GDc>ci8cBu7pc45 zfQ{BG<5|>kj3O~w=d~|L1;h+>3hga&1Nq7cc)c`Bua4T9_6kq=D21tiXg|^ZVU&dt za7LHt|IrU;e1aY{seyR&T7=Z&ls~jJxbJ0k>!SBY+lwA-aGl4^d%~1vloynW+(k-X zu8((4No%Af+6VNRA^T5Q2ST+>unoGi@)w5K6*OjW|;*#>@fDl_E+@-!d3ud*vK& zy;9cFYIQ=c*l;4vH)+2XVSG{)JuhOBae$YAo%XvCo~?w{t2lLMWSLyw66g5Az-}4v zB*EUQhm(C@+yS6PN#0-tg}Ypav)4wT1p#s7K+M7$ujN>m4o{ThoU<{$A>|rz6TpM9 zq5u)S#%!F1G7gV&Ntl&BQ5^2(m~iWWd>M%qFoMin2M1Q-#ww`oo?~rRM6&&WflRL1dNc6yDGt0A0<@(hec z*%pGkO$8W{_fn|!Xyx-hbs+eHwp!ylnrMu5#$s&BcHXEd$EgPWBSxMG8+W|CZgq^) z@D_d(;D)_fs(}G3{y2eOS}rMAlYm=myvfdQ{V-!7M&wQMLfnQ40j$icpcbI!phZUx zp?snQrtPd??aeWk1k8HHedA~eR`nj);J5*Vq)O*-B|Fo0Wf>$EIy|1b{Q z4Decjy%$(>aGk{D&2<5L5C}Lb@U%Dfl!V{ubJZX_BLWboVwI%eAdE>H^f~CCx4@Zk z!hPfImN<;9!!DNsUhnM-+JyB174L@gCKD}l+MGprx&~AdiIq^YGIAk<2e<;tu>{N_ zV8?m?p|TF%XpBu+MQfZMUO8|>-;J_T3#_x_N+4*hQQe!oQNmjp#ekZ&xdqsc!y0*` zk6OA2Gw{|0Z7It6LVU^_UA`EJH}EZZs~m9YL2L9AXvI9h-cho~0kg%}Sz1WB_{0rr zE(Km`|2zilj6nxr2FeC4u+aiE#u&efPiQOiCVzR|d}ts5JkTGY|H-F$7o#zDg|?gn zD+Ik7*umAa0YOawnNR?P?tPc!RdpYH=+8S=~nNL_tUWj~LDRHec}_`dhWD#z(NIHDpI89{@920V%k*e@zlYRF ze~bPTzoR9{6KL`>ZxPT+qJ_^`03{B6XIj&Y{`dh_Ms|57#7GwX1#&FyV)_~M0I2g8H^vw@Z)VdT0QZ=g-=otvkN zwAvY~A|-m`gw)rJC(ufuZ9xe^d%7AUdaWmV_q5;W*U^5UO-CD*l*afP<3az6_VA_& z&$bvp;=F{9GN0!;^rxsn8SUn`l&w5#w+;tf4S0V(}@ z?g1%?@zO|q&%LE@!gCH<<)jX;-3L(cAF)6x*1+!LEfzEu#;V9m-WAZpCY5mnQgtlG zWQLjdHV370D6|t{piRMO9xZ0t(^-&>+%sBTTorl41$b*9h4qMMh2eK{uRm_uXF{j7 z01UiY)es%w{(*$5f<$YIcbV;G!dt{i4rrzuR>8Y~lt$DH#gIJNkU=Hb3jq>69QXa{ zd*(u;{Ee9!BA3G-_syFCb{B3B>Tsjo0_)*8w9Hw&(-kt(rH;hxoglMXV;|aJ1f%c- zvl@~A9E&^VamWo|WbRvaD%s$hI_ewN*Ibl7m8NQRTATPby1<4ilRXDr=UvtAJDvc!lQLg0 zNDC#G^rNOw(?`=-num_TC)971DM~#hMK&t4mDb3eh!9>1UBuDo3D`!gMz+NkQ21cX zrb8ysbfv92P3@z6FP;>axG#E&wZX=6-4R_k<62Wg?dzUl?gj3@t!Jy^Y9eiV$0mp1 ziIRHiy6Kl1W|+pA-G*dc7y<;1)GALG_W{?N?qv68FukIL#lkwVNU}gB-jUu!&D$|z zlG;U<)NJ{Xoa#lo9QH=on?a$*&yWQlVRKbPm-Hj zXFKI?BPAJgO|yKb``@%Q@i}Ffp__#sYFizvoL^cm*>={%TVE({r?W;;uljszY9H7+ zYEjIS2tU7a{RC-X&D7k!x$k7+K&y&g`D~Hu&x;txCvuNoVWDi*peBOViCB2^6Q7>XrW6wmy`Hl5S*Qt(0Rj*XOEIyXMv>>|Va79hEk8`>v(0JbbFt~lh%&;55 zV?qVr0j5TtEl!>5>%!$ZCrg)B^e@fy#F}68PYp;585epLbwn&;v8Pqlw&LrhM~fR3 z^eTH^^S!g!Q>kz4Hz#mH@H=7QkwV}z|2UuC`mOQ`=Wgqes+{uw$^xoKRq1VSyH=__ zw7qq4mcJ~E{1bep`_D5BF|3rUP``0><&uiQwnvVfnquiw-%Q`le!Kk_`CZoit9OK`M zYlhc;WV`9CFZ7n0>4uq3`m8grG3$J8fhYRQe=9wO6}86dVstS2*ZP@eyScYd8`DBd zlzG22MlN=qwf$IDQNFtJgNnyh-#e~)eiT2{r<*eTm-~10+vT6&_nKk2?su_)e8kbt z?zC3a1lwBMiyXmnJ=GyuFuWRdn z%;%;t&zx#F;;}jV*>_atlpiQhuN+m|#!*lCOncH;&$mgyu7K`->nvT(HJY#0QJ#(V z>9t2{n$(=L{%b$v+M({0y6gQ-zZo}~#u?wyWokN$JLD6dz0Pl3*Bq^!OO@@OHO^#> zYV5A9mGe^EUHl(`dsR+NVMnY~SfP>#FC8Q>SPS=&ZVFhTFyq`oWr0Vv=ykbJh8eGu}1Y*~hh6o~4TD6Pu69 zALn&zr8b(!+KcFRv0D94DRZ`UHIfV5`&=3FHRK$sf>B$e-KJ@%`ChYGa;n3XE6QK; zR#dL-t%NI?@_giRTBMHBCCxR>BLtA&NA_QWJXsD>hM=d%BGkQXi(ZrE(kH0D`?Hj* zDL{|fFttXQsT}gW2kHN@9ElvwE9wFTc|2kRWUr+l^G-!3R1Ka|AfP8Yh)t6 zj{c6-=qQ^EjW-jSh3r+?9R9a}FTRqKk?juj}JaVu0yo(ww zx0PGyPy0G@U%IIM(0MmOoGVla0pbF2k5qu#vRT4tF+r$Q)&P!+;wdo}U1~RqO@)U_ zj{IC6sSH;}Dk6Ausj^2Is63Hx$wQDSStSew1Um5>F;ufdY9+0b!Zp354&pZTjB*5( zI-`_BN;q=R{#Ls~Hzli!)u%#h=`BsZ^jO%5)x0UExb4`53U$5om1d%pEKWskUYIyY zY>qBw*-AI@h~^{hKFwSyRH~3ppbK`9ct~yQ`PVto>FYY?>L#}pmuNF}^>oP+ zJX+-)`MzhilA`uhUsb~8c)6pT;R#Vw(Jf?=FZ_%GGYj);%Vk7YoEMQ7>ht z7_VG%z2WTOn&sZ*zOJ0tb~ZmSuQVLe9u-RDk)C+xHprU+(kbmU?F8vv;XJC}PeI=1 zIP^JhsF|qk2<{u8T$1x$(T+8?miBh89m*1EuXcf^7Wkj7EKomx_Xj0MPB4Gxwd!)2rD(;YjOLQK_I2*}JQvsL@^lk4^U!(aFXgggRy!+S$R8*%;!)|m)J_UQ zmE&E?JIG)=pxj69xuW~m!=pBf)o8l8$LGG^V@3qRr7i62l?0Y-mx9> zT^rmm0J%3NXU zQ+Yq_vTIpV(*eu6b@4fUHFD3uqm8qEHT@K0tarxG;#V1RIJB)kw)Fb5{m*8XZS`B9 zFfCzMkX0FIyJyXHopUs(-B{)4cw#n${1>eE*(8Y8*5%Xe2h=1_e{qp+m;6cK?#P^K z%k9-A)gA6m=sLD%Xy0SPlICk0KK&>3z1DM*%EE>k#|MYUCs@v9UHNy<<$6VJ>uI{T z?HW-}c1+KEl)u^97RURY%L1&amS>IUHjW5cU`u%x{7k9t=R3)#tM3-m1^bV_e}yzH z9dzezRbkhH3E89P1;6pTuw>=BKhlpx|I=ERIM2VC@8XC?4ThOoy_|L-`r4k#8_j;| z*SMX|a-`x)-npXfjsVZ6HLI-0H7P+q#7~IZso$S_G9@(sy8HK_!-3a*C#VV4vB4h% zpUwU7dUyL5{g=)snkJ8bIRD!1WlDCt z+V1`>=IeH#>fwJCjr5DfF7`dv1lM@~-7($c?rV)XjWRmt-j+Hc(7x5U%G0&>-N11H zM+@p*e=N>;w`!VZ%vR6A^}>>i-^kU;%_};ECJfc8nhhw4*1|mE*~Y({T$?NZ($V#1 zi=_6hR+;(PTWU9$Uuw10fn}}4S3`fPH#mH?+_G?W`Ulkw^ke46TX`I~aWV z`RE+#%4ZXW0UofY-R|njW4L7eyy>;pB>+d^HCfB}k zz0<44+O&rEO}SUafBiOypV|KrKlN!I(JS_>_-Xcqr(YHQE~N&yjv5;B!2V&u2>*2R z?Wf6)_XflcK0U*CY_9BFCM=ovO>W_DNyY&Q9U=mjYJLfw93CU@dglIj;N4tz+m7m+ zMQtl|>(U!NEy@1QRjXTT>>}QkfARY{`dG+Xr98L$%lzEu%HinwAzy~3c;=N>`P|Wl zq_?}%Cm>~H!pA{F z;60hrlXfW+D@JN&>VGzl6W0444bg;OH>X#;pZ`tjgOV2NlZXp(Iogp?smh)kK6lH4 zJ|6w`q(6rKVxPWLSaM)}a>1ufV+VZMt14)L&fn));66zx{NlmE%iRm(#s#h<+j?)hSDmj6 zIXyJwqnX`ZjsBLKRg{%H$#P{?J^!Wjkoi!;j9v{p_=TS?p7Hqk?Y1djyHow<$32hx zDqy_vh5FnbQ}AtNc-gQ*Q$%&hKRZKmlJ+x?vuHd*MfiR+NJlGNk@e2%*satU+AkwDG!a;eJ6&T4SNtAVc2Z{ zG5dqE+>*w5Ga`Qr4yc@;H#zQ?_tj5Vj4dhP$ikBGcMpej>A$?scWsqc{h~ez_^z<) zg9{hGz1>HV>uq>#Qs-|IM;n$E{*d9yNX=PTJyg@!cqH^?{KKf*>H=5a%pQe4701hu z)ZZ68GduWYe(dRqE9dtaJLdn#4!yNY*RyX?{T16z2IL7fT=2nlW7!e+&yIEM8)gZq8 zq@Ig^A7;&7w_I5A_lA=HUb8<8TGF_(v-9om`V}?WTHO2O7sul7kF|Xev%0k@`QOCr zVL67Js*9=NPqb+>ODBkB(ajqsHRu%hj?}fHMaA!BY3V18OASwQmKXM~pEiEL7nYGO z*Js;>CCk4qK7Ke)ulYD`dWW3@1K*j`RO<}5^}*S@H|7-#^Z6qxxxum~g-t9`^OR|2 zA!#q3`xoeHcSuvi_r@B+&x9mtfAG9p8kp|q+E{DIJW!fkFJfr-IbFvm`26wLtWCW) zT{+zO?v#R3UDM`)Lv9XBe{H6vS=xmEez`g+HLBzj?YOY8CePaRNDPjCY)j4Bm%2Uu zX4#w8-kLRm!$X(H&JQ?Zp5-abKJR(0!sq$8%zvc5eU^PvF|nY2;*-)p7w;Y9g2?B zAfwf^Eo6Q8(I~&bv#t};_Nw9s6CZx)c&$zDhzG;AH0)k9c5iKkWG$Wm+>OadimgJ)D;Xq}U zzO|`QU|PT&^@{H_-I=V*8J(2nP0sdS`s$j1RXHC%D15Xw<-L@YXCdihtXG1*YMk8s zSpDN68eM%)Gmpc1qWE}eqOH4UyQx!XrT;PkfIyZJYmPX;(ZmZG7&7-0JLGSs$dmS5%~K4a%uEE2c8Ez%tT! zN2>_;T?1@yR}HMyyKafU>ve|hhO^of{UyV0?Fi{T`9u43XN~KE>!1gB^OP};i`r!0 zY0g%aXY_fo*$scI*WdiG=3-f=>J^n!is$Fg$nniDv04o6eCzp6vgj-i{q_cI@wuqc zsmGmL9gSQqU1Qv{J(bD|RK;0^{xhPkmG-QNIx2FavO~z1|8vh#52Fj*eZvWRWl=vd zp|Lsn%O**FH5H3<{w{7`^&D4T{BzIUy^muHCQ75C)cT20VPX9vMhDxBFNLSoF{mE!ki-w)z{&e|px-(YslApX=S1 z#uZeIef0j*r5V+aVSu#(^GaC(RpOr8$JRxjY&< z&pF?Zf;)wLZpxGQ*g99QtrTh}IUl+auhm+OiZRcyNq@=nhHipSlfuN?TdKRY3mW17 zPMa2ATSwnNawp+I+P_zheSf;-@iz5oi_N{4ygIy@Gj>eqW8D9`HAw=`|fJ(|1=%g?`ik{qvC&PurVsdjGSG`<4r<~i9@#xQbjB`t3SU_djI9^+pxQx@BRMt$oO}o zy*<{&REJD<4|jTL@zZ!Euf-?Jcbcq6vS>G@!4a2vZqq%^cusLnppO@X|9p^jwREnb zne4>gVIOL>t|MHoTCY>A6KbnE6&!A3 z>3|oGDf_C@y-l4rcVFG2gWo2b5UNkzu#z|5Ym=U&y()jIXziXJG{IML9qT;Kwg>mr z$dyd~IrZ1wlBotS_N-N`{U}?lU822gd4TdXPOFM6imTd9U8+8tA1uxZ3GMDNXnlv< zs?#a-^XaeuOck!v#ayvV#pXt4xkA3{;dFKzqzLoxHSJX?rC2V;IeTT3J52rV#>y;MR zDKyMEk)4#krz+Iqu-A*gNdIlFeij~bQ$c0iQL&{kvS4l(tp}!%k=I_c= zy3b|*RQj7baf_@H?f$X5Z#7F5!`4Wde1XBOMz0@Z)Kx96C==WqBO7gK^B~&b9?IM0 z4N37&3QP(8)-vsn%q8Wmxi9W#nz%&@A%1S(wdL|-!=h?M*`oY|dCf}i8=RCe_UD{A z=Wq6DR-H8lh80%o?JD=^+$)CFzUH+|mcjv)9J-2KQ?{clYT2B?Pp}BO>u^aw!Y$fxY3>9T8}upTS_Pt@i+AQ z%QK6f6_x7#XB?&ou>NRw&UUWVX^R5&bLA6S%@5QkRgSFORWskDkaf&j1)~gCeo@cT zSZQ`DjN%C4HD6R6SJqSiPI=R{A|xo}m(zM`WM$>=hq({)N92Fax|SVSyrFKV>O+Ig zo*g}!I)Ag}E!wMWIqdH04pt5=KUeu@U7gsCQ>*)EO7J&U^9g>84paue$auPLyy3BF z8oybZNOh*8*f$C*WxDb@cUgjhDRsrLv+9#+ggU`_VxXJ@U+uHrJd_S_+brD6oPPH~pI zLfMEb_$2cUe!dhfkCDzv-q5x>jEtMBnK{f6>bbCq>cv!>Ce(HpK3IHo`P1*SXNso0 z?n8Nl(l;fS%376t`fXFJtz96`vDk0-(Y8vvK;xx3t-7n|#vT$gjbn@>%`L=v@O>Pl z-D#O_2Yq3ROJHK;UqWYburw8#O^xOC(mH9T>`m{cH4M>fNstZVA$k|Ph3ECxL|==M zPDkAm?bXav!xepb?X}v;HA8ekC7Q|_Qzs@$RjkZmr?D@T%& z(o`gMR$JMxZm`f=qI>gwj3tIxgHw%z?yPQh?F?Zjqhp6Mjc5&5sEkuBSM;N8q%+9N zH<5`)7FeBhPs*n1=tFc({v_z)TGBJA8h)OcrhV0a*^ISKwP?lOl3z&6`B!x{RTnGnS5Luu+#7z;GqOLO z#kz0;lZzPXQ|bV%Wddn0__zkr5lk|2Tje7Pc?9adyMPO73kAAyP`I*0bn+d&K;+mY z;UF@Ip-7aBHu9psK>_%_G(!Ftx^XV_KxrfOH{(ZLq}PbCP{B)*r$G2T`88iDxPKb^V7LZVLh`$ZXvzI$mvd9p#KsZF)N`&IGGzKbmcgVK9wzX%EL&I*eoDMBJXC_m8K*h-Iq?X)EDTlVCUJ0X-Evg3{A)Tb6 zrP0i1aXCF&8qU4v_i}s0^~^G{H?nNTQ~vTKX#qV*d|_IO?Hv z16uUg>A!`~>>vCdW`T4H`jtz>YCar6V^^_>HC&M>wCznW=<+=hK9K@4K{iYMf)QY1Bt zafIr*i?on4@mm#pjn1ke<^h~LpGD6B>Z>PmJ2zlfiEgw=l}q0djer&&)0g@av#Cxx zg1C?*E~GZoN&GM76Q8bnV6Np7jXgNbAjDRVnpCP{;}zvx;eXV9u{AKJ`OH^ptZ2hl zh>xZJL8tB_eN1Ri9hPF)E)qwZ#ZH)^$y6v;23658VG%81+}6_lg(hsWm_|P~2PoT^ zd^nxBl8xiPvD2l;Y!B06?l>Q-TE_b_8K(A%r@|6yGQ*2Q6t7HI*-O$C)yG@E_rwcaRMblT+3=^kpZwOGmH6K^p6)qv)>^1X5_PuDM$PgW< zAn7J;K^>A%`H*aB(V!lbOT*%ugXPQ&}s=V-)!_O@zMG1jQQT40!6cNIT?a?0I1u{Rgv+4lvhnCjr{GqaQ;1u-rVJ z4wdF94w@z@a;cMaoP1r#Wd_LiXua{3n$<_BiusdD6*8@MppH>`YM#`BxhN71#EZ;) z%9}neexeUahnY}Wq;{E4&|%a~`2U0X1>90|Tjg)QoPH!5Xdh_{bJqM?+0dj^wKLZ; zTB?ztRXG}tYrfarR$7~GiIl=kx+pE6#&WNyy<&g5uhd1o&v;Z7Z)6p#CkbJ4BjyC}#+94%RPRhN z+z9hO>boXu8qGCZ-mi` zDzi7+h2Kh@7Lz$%oB%w4lHCVw(7wp>t)WJWU8(ERWHwn^$}Tf6=OUz;bP}@Hbzrv0 z&h!|GmZ#An(gVhtcBTi)-Nc795O&gId7N~dog($82S_aQH=eXz`Ud34YT1sSDm|l{ z!D0_WEN&7oB@M9FZG+NW2jE=v)Bqr6!hs_xg%W62XnmGJQ{GFS48+JK!~wO)>Aehk zpGDBMyeIEL?#@BLpyVU2(HhS z4Cen(R-|1C>X0Dp>KWGpdXS*>33iXP1bH`6psvSL5=I8$#S*j^!M>3<)a#lMZUn(n zlDZPi9YHseHYJERf?OmRJ;HqGIUB=->}6v4(3tnv+M6`!D3$ZMgNy_lWK*h=55HkRl)PBDe{pnLI!!XJtN$&TtP z*NE4tK2lp+tq5WJ3Pa?-c#6$K3_FC{%6;a)Gw+y@yruk%cV-SVF;X{{6T7o2dZgqC zHRuV{Ynr3hNLwx67SZaKY!s_xjswJbNs+@fe(d?`KqOx#Dmq=L+CD1mRoECim;AUZ2)DPM8LG+$M~ z9}?S}8Y$iiu_`;G4cAw=rTS6*UXvuLl-o^S)O_r%)aZR^*vk7+cYj(79p1(CHtGR0 zood5|F{7!Wrknc3wNB=Xa*X01&ROw=dBkj1_$s#;O3OCuJ#5y84hdH{Ypd>lH>Ixn z*`sKBrMoF#Iib&|hvdh}@bM@)^zT&Cc#+5OAM|Zh(_l~c8&sTW7Tks@1G3=*M zJm1(`d&*}@lTV=o+{;z#3@>yEg%ff=<)>DSUu;3puC9}uE4ac8!Lmu+2;eS1MtdEOht zBImE;+#OZy?DTf*fd&6AySV4W+435z ztzpXU?fcDdd(GLSCNp*KtEO)orw^&RV%@L==5w_+2CYKK1Z!OyyfYgqxs#H zx7~Y2IrI>FmNivryna1@Z29a}s#ce-Wdo#URnd-3pE@5iyZ!3_;n#<|89}Ce+pyr} z&DsT2*>dvXs=e7me%|_VT=!U@Rjr%++4PX)>>gBrgyq6T-*BYMzx#k?5IW^TSSiyjIoQZEJ<^C-{;-iwC2KJK4&7k zMJ4&R(puE+%lVbnDWm!Ctu@mfzj?iI@@ux!Wlr+KdsB2qt~4uR#$!;@A;<0c;9PRWak#D@bzImJmUG~Un3tLd-~T;A0{s3 zXxoqBX`a5EsY=W@{g8h2%}A^nVcntG^@xGaja>Q*gPv5}_@g4VtGu%FqPVbb&&Zqh zpH2T9Ty@+sH^iauz47<@^>GRPy7u&rv;Oa2>4yY_wn}VK5}6zN)HbsGWzx3Cjou7L z>XA=PI=A(WtaEuGel1AKIGYxdkzLqORb}tkkH~W#>y)-OT2w; zZjm=_z9gh&@(UfBhfNz;Ic`VyU^}m*w`aRwIP-q0_`+g3nopk-VO#zyqf`7ke1`4R51TTfbX-#PY<#lhgDmaD9+ z{AH2aD#`7esd|U|?B=~&+XjWHkC*=bap7mL-#2uD!Y2#bbw|KS*S?Pa#%t-_%iPM^ zq{L)PK1dI|vSO-_dc(iuZ7*&tWgkWBV{FnYVhZ4!;sH(5nOA9`}z}K574|_vx5jkSi6Sy2e+T-u!O;t1bKn<4Rm=K8Iybn!jjN|Duxdh{sc_CcZxxkTxiEK%3@sJf=D% zTJJWDO0~N6;Kt%?eNfhj_2ag;%@#K%20lNX@}{gcw^sF1v)w^-KSjOB(XKVgd+auR3by9T7iPZ6pTTYW#ZW`F7n7oZz75SF;wj5AC zuu<#Q{&!uHRF>6kQ~tTL;Xz(@cVEZ;ieYVHDwWA;pWoe1K3>#9zly4|_-^art!*;W z(@z|m{rdBTlxwBOG+*4}d_KCY*Cs2ys~;F1m#zQR!mLvWB`a%}H$FFZ{Nil`A}a0v zdtd)o!@WHQKJ7C+D%59#`+Hj#gZsz!my>Q;<~s*%8_{R9SE~|n+*kL+#otDjmDWr) z1SlrDx;155v~>MlJvBA^Rjbt1hAO8?elxsWovl=M@`+lhc253eU ztbFmA;lVZa_0zrR>RUNDrO(aqR$c>~bL|hAwaLe>7sgM`I_JNC$gnZjT1}#>zXiV6 zemPYXZ`vzWC@Y+o`5kNM?|s!A_BAkZUE27%3Wwu97hR`Yhte-qXNA%HC|$p-$tD~2 zQgOrbA;B*v#I1}Uch~F=lmNA=;p3eP8 zje6B3SnHdsNgbK8IU}yJxuLbR%lS~#$q~`MSyG1|hu$sw`l`HvD#m`ObB(j)7_B*> zaH$(y{y6t$#sTK6;~IWc)qn;rz56XroAbog^$2;R{O^If@Gf^opNY+FEO}Vk?4tW; z?|;(%%FEZ?=tVI>V>b5N@878Ek1t0*ch3-uvuc(~nc8@-sg0Bk7d!Ma{P=q5!@Hj; z)x9-?y@q)f+C{4uYRXML%u7pK=L8tiR8G}Nh0PmeAuIFit3jD<5A_2&!BAnEUbUfktXZcNtJf7Yw`kpC$C4h)*F>#* zQUA`6uP*~teY^CY-8wh8kz1Z3rlQm5KkoTFi~ViqqUw;|=W)9kE~hFt{S5r}HS=1@ z*t&c4IBS*Hp5SBNVU{(uLT2h0bT+{od_IWJ8~Q4hA}=$8P``8RT=e;Ls#FoQruU+%3iV1Gns%g_Uo{btL z+nLl;^@g8=K3xAaRyV4_m8hj{#bA4jg;lZn|KzBO_EpU?3rxIal*?t0+fKFI!|Ex8 z&IL!y-A~GR-#E;iipJ(NkDyTy8vQ zN-$@czw-amjH~-{D2K zLiRqI+6{KfNt|X1!8avZj0_a>A0oHLWMq8#Aa6(Rmvi(a;FlA?z44>QfZ6gE-Um;d z2dBwv{$nohL>7k5V5qkSy3$*=MShrW@M8qxoc;{_79CiPssEk!8so(43~r_a{OgX$ zq2PyXDSe=JzZxYax_ZauuJT~unpMb3Hv<_lvXIRp6!}PAg1gJWPZ5Am2=AB1(334|04GSAE^r>4CI99 zinAnPowvr_L<8w3d>({Zl!7vRhEFCNt)+vP#R_F5XIaaYT#8OS;`2* zjIiB_HUUwcsDx*SXs8hWtO{>X;0ff!O!U8qPlb3!h|)hfGZWQe!Vj~-wUuZW4o^_S zb3snqr282sU&i=$RL->`1cTG;#gqcQs2juil@ODGycS=e`7>LB{K=^BflSs74h`tBO@J1N?gx^Qn zop>;a4}m=5tO|7%;6;|WA#i7Pj)bQ*H{42LzD zfs9N0um(`HBQ*tH+9}j9tPHn+_ZF#sh`uEu{`Q(`3Vy;uxvBhB@_{|8qq33LQwLoA zWGV?`Ar79_jr0bp2bhH(ln;EdRcNOW@Kz4VTVe0)P@@>+IJuAZ$$?#Lk9<6TP*3n3 z@#a283x>dsF2nlr8o#|q9-tAZeGFRdJ;sDy9*u8Yk)4UCV>N`2mS{T=R&O3`BGI_; zN6Qg~1d>I>9dXNF|JgL6Ad-XL3PhV{nD0cjfhbjE!tM|cCdr;hW;0Rn ztIwE7<^|E3Bb?j%T#O{MB*}b1bZdwju?Txi#$`E1C7FRlhl7lEJ$@qmdSW|>}CiZ}Euj~Dm#G^{) zCh@8g4tKpiC}9f|>p+xM>T^sI1-knAPwY6+^ds6fMA3E+nrcpqU=Lh$z)w1_Lo>I;(I4=BYGOd zUXXcCIKPB>Pb@U~mfTGk*yL(rL&+LauMS1*Ghv<++d=Ll){SVOkzOH+zx8@#JbhG5 zq3oo~QaiRQqoji5rQ&gVHWecbWv2?Gk<)gX^gr$Zm7~~RdyC3qGLexvMQDd;OTM(7 zP7y<;9J!Qh3Qu1={hD7wtq{M`I@*E_5Zhx{aGt&-#nOGm228cYQb!Rhoxo%XCT57( zh~6(x;T~Z;v;dMJ9g*LbQXe)P(U>B+xAZUgM9q==*Fqe}ILOO{c1#R2L7b>rR5w+; zAtlh~#HMr`;SCorc~iZ(E8<3FYh!yUPMoWFgP2iwDu-FbcrgvdcTBF7#J{7jGpRx$ zI8taT#M6682gR1$Fj^ERQ4#c9Hjhb{RLlUnsnB1%OzD7|7$skj=F{!zRJk>MiTVMK zm|)~g$)^5dve-cpE?i@O@fq|mIbOO=Cn-v}que#xQlVxegk0l!zO&Rpnk9TS_fS4k z*_-Y#lc*cwRMetSdasLE}#HorE6Q#y{uuzMZdnXM+G(OhgLB$#(4NHxUDJ$W) z?2LfNT4d&9rCm}_Dpi?6RdF`z!yE^`GAH+?Z&9^;ywX>iDC`%)6sv@9@N6e?gV|N8 zd(>|AJbD##jkcmrRW9L|F@bD%x>)^E8)@IzB38a`n!sPENcnxSU_+6zd`@|+UMY09 z_-?h&=7QZXmlw_ptQTthRXqC^;*aerDgD%%5!Lp!x5Y-(9`+R%Wf7!ZVHu}ts$8rD zfk8T8^yCu^iH163KYednFxxS$6tW^te_Qj#Cfw$Twy9Gy$AkuLEvA~*ROeM@Woy$$ z|47Ty<(HQp)u+${92PhD?Hu3}=}&o#1kx>un?c!Bk12~N`B)KL>QOFM2T?znW=ado z49ID`v~jUAbMI6;h%#l;h=4^zXKNQI|ugq@|$0*Axa{)*WZqC6%(?@rJhME`Bqf;t5m8yCthpsv@ej21i9ROt$A56`?fG9it0s zm+3Fygmg>4&d^40QidYCU7&WJdZlqb``P}pRhCnX;|wQvxBE_$4ZSMwl{w|~OFfb@ z>&u@x-HVTvr3>4wZJl%62Kgj;m;1)MW!Vf6Fq- z&0B<67%f{^&D5-v|6>1;I*SAJUkvH`#)5~*#oWOBNc}~&ryFWpD)t)Q(S5B{R=4a< z+D17(cjxS!Ov9=@t48O(O|ymL&#z#6>6r=(A;7lOF}}eJS0}IS?rWU7TQ=q#xj1vX z+BFr0HC5F&Ym*EPf-TLnH&kO(|606J#%X4zFsnhTPoh`E-f0lXizCZELok?BZ{w6LPCRR}L)9&56wTn5`_iS(B@8M-A1kbeiHY z+j)SaqvLGr*=j*PFFKnQ`oXp7`u%nGrWMjuNuij>Emeq%NKLgvZEYOZSv|5DYI#=c#2l11nLi3I3~mO0!$koR5@-;dV|_56YT0&d z4KtAWMl})ZcuO%(yd{JSB?9!s=y06!)-h3ZPsLDqIW>yCMRzg!NlNA;w_77~iXeAN`nKjpK;jkxy*6~d%2liBX< zUtkE9FfW+1^kw=6PSDSgUC{wI{RoHsNE>87oPu53R-DGW;wlBs)bYqEKL;n|Avkdl#cpjia=xGZFIOB< zIM-q~*Bo42lD9Al=i(^renRn^C-$0l_>L%Y6V)dNtf^#e)?(jCb{0femz<~Ser6jB}kOMUOBM-tUz`rWXDg=4P@mf3Ylb&L)2Et zT2EGUa!RXL9I0Q;$%;>&L}Jz?_DuF2WdBc|Q@^Jm=dk~egOaC^KV&CHb};0;MznV8 zOG2Ws_4_HZQzGX9Qc`jbAZJ2y79=GiXEJh5A<=1aA|*eQlMi_+*+&rN9kPF^FDKbU zk+vawK(hNFv3;TvNmONs!V3A9M1aYzu0GaF&ay;=Bhu>5Opx3CPTE;$w`## zR#f?+TN@CnZS(u!ni9RS%Q*p)T zB;z#6c}7mkM9G!xj_S`}q>V^andB8Did^-IUwPp5)&Yq?bm)lA6N6oOF)#~6yDkr7 zk*JVqaE>7-&SLDT$^Nnu*AXST8a&wv@2bXWiKy$7-73*qE`e`@C?F9{Xlv}(t#INB zz$agU#Hhp5n_@Tq9k>kxl)75~*Gu_06B+PHBh;Mac2K|V zszK&PlI4x`-hI4}!xP-Gr`O}T?{KFICx9h*{%`2dSpxs@2IJa`Y7e}|M|lWF)=ji# zKkU=Vm6q_ke1Pgo1m>QIr?K#kox>*vaDgLWD@%cY(E*XlQL|AJ6*7*pI5(bzmu4#F zuQ%TN0%sI*V)zX9coWQpgE+-B!2Z$$=RKl36ODI#$L_Bm?i~+3m6z~vRRZVf1bk9s zYAnjR9VZ7_?g|f22AJ{vVKtoLnc4{*mU+}gwB<0=&>zSeqDSq6GQ0)0=7roH8i>JY z(bMoM5ibb~uTwNW>w&*M=&MqB8$3=2kzw{7&RMH)?;lWbIfoO`7@+^$sY5{fw7}0= zwC`M;qsnlSdx|zz1G94(r>9pqB~HZY$^+-O4)7$7gZ-eX{b&zpzyOI;43F4$WFHR1 z8yg`DQC6L2YA~9YAWio zn))D3qiyko*~rpNa@;OL*`DGVtzoIq5-9aR{CpF>NS10SXH!0M5Zw*qa28tY6Fh!% zaK{yC6i%Tg)aMLx7bl`e)=L4{W#{Afk#a}+nlyN(cY&-uEP3G^o{v1yLy@Wa zUyRvz@+az!)D+izMafRcpQ&rozw~se8{JS22QJzcB~6sJp>?Cs0uM2&&&j9Zjon5a zhB_Sly<#a7DNV)Rw29Dw@yEfi9pxk?(`SHQh-M#4+1Ps@m)}w|sR+zAYj&sfn|>*F zqR&dxkvlwAe2n#C81NE)R3o6X)X-E|25p+(;t1xtkj0cCqp%;mj?w7D3$iQD;D_mW zQO!P=w#o6#QL{f=CEk$tvl~PU=DB#936wU=<#e>1Ni7sCnD(*(=Vg;rLUm-W2p`xR z(l_an942jG3{qoiI6GK+g7)hyZ)DzxXMj7s!?$Iw12NK1;U!L^=Ta@95@JbpmKU?J z`~((tlfScb`B}^&n4**PJm4@!(!GU1?x9pJePz!Iwe&Uf0M<_01H-;b>dQF5akzy3 zAdM0Q_66kxTzL{k=xatL&B4gr!Nv(=*=N)aevdqssX`v=H}VQR<$w^!CNR7dMqS~Z zIXme*@}(EB^M&O=qt__H#3eK|FXVR2O>rmZXtq;K4UPD@*ks-`$O)^tdvjjo!PCxXO7~wn{Cmrt>o8=71CIEafS;A z6w$(Iwuu-{y``PRL(F{A<-N<1R%Xp+BW#hhW@|l|GA}Y(puQ=_p==S0zBc z2psiKR$z{qnp4*}5BiPyDAR$`)5nZUxp88W*i|`SI)#&EFR=izf*H&xIgpNJt)X@_ zMeIRGnk9Jl;SFP($REWIOo^$V+S7DXafR461~Ql(+H;oZfsxp2_YsUt;g^v!SB!ncgB!<}yvk z=xyRLJog+;^JAH0c$m@!4`u@%qm z<36SmGn3}v7*!7P?znB7dSX&>;!(^dQUu1pq2@)lDA zm9MFcdncDu?FDbBm>i|r@HuiX$$;_LpB9AoN)sLRqvdM9ErYQBsv69*~%`Bl*FI3Wjc z(foR*pX|lv3m+r{Fwr+?qqvy5EY7Bn%Rdx-fqR-RK{r9UNKkN1`P1-0#)@$YdsC2d zmH9r?g34od%W=|vNkH`I6ICQFrMk&c{7_gQA1+Ufr**V*GVSoCjSvgs#}u8 znZZsu&JSS5!oOh@{OMr%DsvjXnU=DVI?PwfSE%!}yEu%VPA{eg(S4~I@*iSX`kb_j z%N35%8Nl>vgqQ4cp^Ks)kZh&m--;)~S>|70<3`H`)Or3EeT8X;b(&zf|7EhVl1cId zVIcce{97{8(ey|$P3*WvOfZv%^(&eGA6qTXl|G8! zxq(s?r<4xJ(c(2G2`8W7k|24|O2m)mW8K@z4+n$jH@F&8gi&-M(?IGXH(`2+pP^mT zU$ml?G%XFIl#D$SLq8T4Vcl9Rtfmf1CMFjClrz*_VDZ{AlaL!eh9c@rZRGig@qNTP z6(L`sZb`|A`~^@OfXbgtZ;^K6#Iv5t6#K$LEu+^!CFT&dj~)U9@M2Mqjdw>_ud#G5 z;QRf+$JjvEi4}B5Y7ecFF3V#uTGz|}P>-<6UdMi*H%@X2Dg#l-R@g^H0c*`;l?tb< z=~VizG!Be|Ca~+#@)T+r-5Rq@Ctbnbm4Z*$B-KzSXpr);Ux|>m<75QB1=eY!bV^at;&#s6jx|-4u^vhqQ(oi0tLJ%JH+(wqb5XusSzBp^-E&XB z;7%d;{M&l?xrAxD3Y{yr7P;jm7u_$NS@Fd%lfI2Kj+>l5*p0Nw)P7d!#DuzD`W{tZ zYL`{_tO;XAYT6jR^lNSJhIMV_6SB+VlR1pHtEfx)`0V<#q!jn!aMM+(tL@65zLBk) z&GaAbSgf{YqN^X}J;<1yv#MlM-4@|2+tbF^ZHz|)r)rz#n*GArYX8dR#oLQcRopT{ z%h&q7^>WQ3w}ECJNe-g*J4MD z$Dv2ujw{;m5jD@UI(<#douZp=n5XGrZ{sl0>z8+weSr3|tgY-)*{m|5AfsfYIga_x zrdw^a+H1Q`lO`3jC%A}Qx8#Oq|0X|r9%@}=e@#D2A6R<*P2S~CH*!Cos*1CH>S5jJ zR@>+8mp6WEcTLay4$KTp8%PrSU-WlY*VHYyN1beRH8HKR zRo`aKnkPlQX}>;tnVWx|S6ayXJ1KoKHvPV7)H-%-*e>E`BhG!AMUC`c_db19>YAU2 z%62of-CCD1K3bnF$8hy{(@he)gO9J#HP@J7?GZ`2K|zBRyYnwEdouV|$KsNGjQoHt=rk&aoSQoj;V}WLFiru;b3Yz55Q2>ZK^lw0b+? zRqR(jx6&}&$-lAK@?Cgy?~_`S!LNAxk0xIdeqJhP*^^H0zI}bQK0c0x(g@w8{LJhh zc?y>EGrFWmR?bKR#l-G;U3z0KvJ?$ghjm!}VfY`47jB~xd0qgksz zblv)QI@Y|oRrl=4iIIuE$?tycHV(E6X!uuK_m;DK!&H;?hTLIaAARYP^`)kV=9#;N zZ>)!v+eoXcJXaY~9GEjCC%sxDUa+rlo@SNg9qie+!1nDj!Mp8&D#iQ;Ed-m&mtH}_H^_gC8w!BGrKRGKwpxo@jd$iviamCHoa&GmS z^!zX3=`VlGu3BO<&^gaLx)JBSN4bH&TK+BfR8FJfwL17{Y*%=nXi&*zxwo{qkdpFz zq(==sPRcZt#Mb zO<~)dqO16ipP#OL8T&&go^?GLn%cs?`Ci}N+VeWY_hrdrzMaprtUG48(&tg5QT~zRJpo62tTS1nWACwf)7*;@4xj+Fc?)D`jt zT@+)i$LY_Mef8cm?9s&G9fk75GvjujxIX)Bn{WFn-#WHvH(=Prfz^J4DhGdZdOPex zd`A1~axThOX!&AuC(6k4R%&vCvT;M(|}pS${2p~HtyNmYeM6{5Y) z@x4>Fb3}tDTD@7BweHLI-$kasH5!*IuFtiW>Zhu!QgGe&inAqGijzbaE1lbZ2a#&3 z5v5;QBU5fk>sp-|HhN%x2j>?p_gpyp{Zo$aKJ{E#+F)SIh~CBRT-5tMxZP;=#I~Ty zwqKBgPoz5=(9wUM&4Fq|>f-0GKj#^KyY&m57QDH^C3PNs%rK>Vd)CqKQwqB?(O$aH zw|+~k?;9^wG}F13M^;Rz6@^ZU9H%cXr<@K`CBn?KM*ec5xp(~ZLP6q`-q!7YP>FFN0_>Zeo~0)7on zZ2iurB&&gE%e!r4pW)2%;`T)wOSrPD#gj`~Nd?$(uJr@)-~8%tTWW*Uw(`X4`Bu+cZW_oAY3_dRIlKP%7MEx1>f${w1vd0L z<1;HPw%I6$%X#Y`G`h-vTn)hR<_;ahlI^BSv8ENqh82&0q$dCTJyks;^ib<#4a*em zOLynrF1)OJUh_!*2iRW|W&;9WeUO^}cS2+jhC^wNIE=_s}lKslWEI{gU9<%{kxgHM8D1 z-s_oqioFz^*;wg**}|J`rFpBh7846R()MRkrZTscjq*K9mEG$8SJkg>rZ7u*UF}pk z!gRtS-es$ExkWdVcSWzNujbYA7HPFuB5YtjTV&YYwwNKiSJza|ue)Wovh1mSqE9Mx z6JLhL#{L~^<7NEu^~(P)?o0StJVxxpo>T_9R5jib_0`9$ADn#R)%WzZ!kPx7J$pCk zVRPB~hvVNi*5=%t!{0XN%ECt{D{rmSYPBCQYzL{f{MzdACGT}B%*mE5oQFG^)Xu_Z zy|dvff0++5stnhJ1O;a^-agLaiSV@URn04AF#g&T5 zS+SWtb#Lhf)^2u=)<-o9)n;{n?yRY-EWYqv#e3m-S^m@=`r>A0*lApQp1q~}V8=FbC><$Ze$9?XU`@c3zrK<9ug_}x#R2T7`ncZAZ zRe*MvHEr`#6HP_w=avsHpId7d-*X*QGofU7S*cTPRyr_G%`0lxRom5-2zoYEwMhM^ z;y$~S-cH?OqNpau;3~N~SJvBa^_w5C$myjxu*l|DPUfk?rBw=pw^=8RQ7v+q>e0bt zqFrm*uOh3UdvS8jFR7i+*SJh4HXfx8fKsk#KuPiS~Dt~8mV25iyYTBwca1@SF^<4Evz&0-O1B{=HcX)+dN$+Fgn5~G61<>u89Z;)ulnuf&(*l#9curMo zpXyra9At6QaH`<+ud~^`%DVCfmD$SO=Cq>^8zA>HHG`(grkX|kP{mTKR(9vC z->S~Y!%RtaQw_gOdnhq6$|eQe%X8;}?V0ycV9PSL_C^Irl$i0ZxFx zm`ZoW;X*CXhy!FT^_#Jf_L@^n*8F_&y4;*@ zf_WX!JZ4PvFfeSVii?EqIHxP27u$<*U^;>YUnehbw zlrJj1X zW>Ppjz8R8=dQW`;f@3rDgHAS| zBAC5Gpz(WMcjHk0vSdZCr4=|w7fbi0wZJ-+P?Mpl5JBf6a!8^$t*CX>X=p_Bga$mp zNs=6fuK1=A&f_JB6rDpA)eh);i@d?cb52E?o{yy|`7 zIo~ALQd_9TP~7cKZDC!Mua&*HXW)NN<}LY0{2Xz%Gz9(&C)rN60<(QSJl?0MJnAL2 z9yqn>K<6&SPj{fM(FM^{1!6Q&h_(2leMr707rc|?9U=J2U_^K_fr>3a&1m3oNzR5M zpuZvzy&_!A3Y48-w4C9aY73o@MEL-sIme+yyo36i{>cnvNmTkBbZ6C4L+G<-BYry< z80QLjhW%wX#DqvqBM@1QKpdzyqP3)7;9&zwc@E+{EfK9ExyWM?|A|CY!Ua(-f(8pg zJc-~{Nxl>dL`e!!YJ#v-!;^6YagO=G?ua(;3v@_T67ALlgEg)y!eml z`ViQ_xxfrI1&*#5^=OXRlL|ef2a4Gao{=Mncnv_@xD^o9SK#yU!qc0ecRFL7T?3x? z8kLBCX%8QvH{QR3x{LST1ZG-6bpoQfEuIuD{{`J)4@4yd#M=&|4_SPwrLLn#B}8>v zp|+dRza*MxLOi4oBFt+L-S~`kb_r@gB6&CAYwC_x-;VyEsJ~E0-~VESOAt5A0tS5= zTIK;FMjGg#+(kTF3*>nO%JmA*{0^^M658lF`u`ztd1m0rt5El1pb;mbZ)2cDG5}>c zCa=OZ*@#Oug~z`MzQ2I@+7`sroZ%B%huGUuM2K!+>~5yEV=i@pzdTPKjM(}S^!E|W zAv?5q51@~ZBEl1nXcUQSJ_H7RHZYua=*2r|X_^|3aWx4gmf8fcr)IF%Gd_~P7@wW;QunoZMpG8@^qOa4?D+PG-ame8$f1`F4@*TubX=**=EIZqZxQhQYQ!if$!qbhQJ7svFm6ax`URK|sjzN)5c_-!m4pW1YA~=s z$#O%v7b366p)8b&Hoc6|c?vysMP3A~tSkOCqIAd6dn+-5JmIn2h_N{Z5!mL4Y{sGu z|3Mu75K8qBIFBK?&I-@D2R(*#jGMQZu|rW3@HG&Fwn1cY8{U3S-UmAg1in;&5%LMo zi38%{F~)KSwD)b;#@A^3PKakb#VqUxS`Wdz&Vu)MJbFPuw6-;r%-5r*XTf5hM>}ss zy$9jyLir$U<9K}A80*14%okuC5&H=S#&`|J%r;nro%qxScB(&GaS4zHL73Sm(aQJX ziC=(HSpm7y8anNlpeer}5$-7%lQL%X3B2nJM&}M{1Z-9jR5OC{3>)0n7i--?jNOs) z3)CzOQRo{O3lpH-(+ndwklu;f-;*xLE2t>C1+*(B!RB89>ctv;ockZ{p%Fa5DVX0& z(ZUSc;2-$_dchMIiHR6jtuWI1W4sPU%jDwTjkvlYMs{D=;Mr6^c^K@;T`CvWcn>%s zf8*MT7@-%?E_w16^guLX{FYQx*t;NVp8Nv$UO>CMqVMJa(L5eDQ9+M@<-dd)498gN zf)=}jRgmOs-bclwS9W2|4?vI3!#Mv7{W%F|eyw zU{~(Rone7gcp3#|4xQ8ybL}4bbr`NVika<=vAzKF%!+nKzqEyo8;4OGf+r8etT=`l zJP6j;j(U&&azc3{VbwoMX2gS!!)sp*OSu`g4(xZd&}_8bJItZ&Xyw7Mq6rusT53Nm z&Ouncm2wxXpis4<;?eUp@?y;OURV#;Vl>^xy5I`Clnnnn$#eG{Rwe~Datmye4kZYM zWnGK1l;BzlT0bf1fqi(x5_u_l>Tl@$EJYuDgcX|sob8_&-GV$FH6^(h-@yLMu&wi8 z_0I!IaSh|C1QxL~eyTt;W$J&sp*g^(Ka%sMrvI%hFEN@HVJ<-B9Q+~~7=Xvv-@TCI zuxe{CfAV2F+hDhzC}&{awZnQj6Fo#BE6_Q#e`jb4JVf8E#3yHfjxWUu`4T&=Nzgiy z5H-vI>bEy6LORg>XAo=I1{*j8yO+)w$NkZp4E8RYF&1`W1Tt7v#!x5l^Gnn}n)-I>d|2fa2C&o~4tw-(gjJ1QBYdm|9_3|0_dTu*Y&O~J}X zV;^b2^*NYdlM!ovkAI(|CJnHf9)r!nh{fpf!*}5*<36m+B**In>>h|x+$=v zp4jPKMH^LM&B%d`r?Do4!}2{v)+LhpE*Q^mkGn_)!8>@L6;N~b*dwOnKMvnCLLI;3 zN`mJ1#JbDj`K0`2%rh6%rvl@a%Uqi5L zWUoZ@R~Y<^frg(+PHOTW(adp1nPEl$`-~vc)M%mloSua9RF1!dT|pRar0yhF8p)(b za`6(T7~ww==|Ozi?nNX{Ol z1qm0gp8r9RjP-02!fzqi#d@|zy{Zjia1oRuDKF_k(r<)!M)C=h44O)m_5WzP3iztZ z_kZektb1dF4aOMVQWDZ24N{_%f{0jv3Q_`+Dka@13W&6%(v2_%1Gd3B@9u8jd*c6m zcm6;2QP{obyz#tGzfT|o2a%CM^cga`5UYree`?P^beTr9Cn82sfe7)Th`I!38VJH_ zS8zm+B5MWNW7shwGcg7_?*-E?P$vqRZHVebCqk?Q*oAmU)B-}3Wi&mhVv?GrhNwzl zB6`%J`#PWn$X5||mC-wh%>-^B>#UkaKrR`&d%|MFNg!Jhb(2i=<0L9W_fekKj+FxU zP!$Nh4%K>4i19=Osfk8Kwh}S|wX_#xtD);)1mP)i4S|7p3%yqn#aK*FAQDxDG`d;? zlK>xo%?#iG=(?!JiXz7cRA3_RfC@#3(^M-DA-@Sd?cGG>uZXe{Yl`2|;TQei(YF;j zO6Zh`UHOQg=Fx1(yFqS^j$n+)Q&$Zy0KEhEkzt9rTnYoDHG#)qR!H1TvVx#F7ztY7 z7C1H7I>E%t;z@H0r>D^e9yE@=)gd+bg3~~UWOx&7v_H^2I9w>L5IrankL;%Ja)|%t z(BH`Y38vAKiPxo)1dpck!V~4R!#DI(NaKOeAu=_Fe!>Z==v-M$-xt)(g1*SWKm&~* zO;AHWvvAF1v^W*3rtMX%bJ!0azmLSLIv4X<#F$8T5mbcF>QLK1JNLnz@CjZZ#?z zGz?mRdV7w2K3}a z=W}@4K&_Z1j4%|@)aco%{tX_4-jG4`gYSWNi2XLxngIjw4^R*IfP+RyZ*jnS4A>$kPt7p~w}+lmML*TF zHi6~=O@T)s{}GZLHRLn|uS8l!5Um;`vGfG`_(H0A2>NzfrPSf&Q{af*NYlmD9-TxR7SHnt!A7x0PUv zPN9G!c%RzU6!eCwf3S|C=>L$2km}HUpo<~LQtf<-j>X{I_=CNmiW@SrA*+!i4l07q zgiK>-M&SR*7{CaCyoKlxauf0cSPb|BZ$R%jGn^&5AZu$NjqGfU?Vc)xZ~- ztDp?b2M9wihxUS=xxi0g4`>E?0;qEsLU2RGeg*BOoc4|mqu}M(V|5Lmln5GXCM=}6 zLR`R1`;4J^n3~Zc4?<}cP^Obs0WUE!?xEX&uOR0gGb8U4nHZ2#z-OE$oq%@1ZFJBcWea&|GS63A$9P`ULt(V^z>_A+h1Bg|31O zkzo3PHU(Y|-VS~Wd;n!2V;y-T)if%)%0iL>ijb1vsE}=tUBNY2gKQIYbOtp-QUl`v zNxTt8ZvaP-D*@F?^G$JpR7*af6BFbEzK( z9#m36^MLb%hQT+W^?=0|K{i!KnZW7CW9)=AmNa2 z1U(5^&#DfNj3S&8Y7Bt;Kyw9lR}=Ir2u{eJ0**aI_Z=jW;E-G-Oj6MTS z{m&)J_e}6vjFcBunBO-?^SeSD(3;$N9`We>4j$lS~2JtKgdV? zU#27YA8cQ6G;mqaCpb4`1vDsYjkEwoVOO9)P&jO0cy>@d2^0nS2Mq$e4w^o4{h$rP zLQ!QpxLi5CQ%&=zRH9bp0gNFrLTDG^H9ydG)Y=k|Y--*nG!Co|lmO`fy%W_Wpn(Gq zu?I+Ia7TzTfES=`&=b58fGw;B@DT7d=)pKM=$PP@ z(8^Ka$65n}0PO%$HlKJnyqA#Hum;TZK73oio~jy*fJ{^~fgxq!;{YCkJF2`0lmzbz zv8tRxIQWRu7Jg^H-@HwT-|Hp&{97YD7t{MVXUJyo4Db)|KX@^~ z{h?EU<3aC)ZmCKbP(l^01ztMU+JNSUEMlw)G8a387ZlPM7B6bLL1O^k!XE=q2KbeV zX{d*$Vy1da0Ivh+5`JI@ojZ6D#sY1qnmTp>Eeh5Fv>==bP7WRd_-TM&@X@Fk0B+|d ziB~`?0SAZY9Wosp8h&zEfvOJ#)Cu2TNDWm21Hpr!GhwCh?!n%J6bIibr+J{$0Ly^s z;F>rQ>=kwrtX4=@@FHkhcoX{s6_pZh0UD_G&(PgTIjtDn9yQy+)ltPAz87d}kfAso zREr8De;{-gXn)Y-fMr-Sq#nk#)5zfDfB-nZOtZj32%=L7B`FL&5_@833}^`28hBL@ zY~U@yy#Q_)z{{~;*dS`n0hJ%a8x78bN_5b*^|V6hs_-KL+K{i{M8Fl*M+2z`Spjbk zYs0y~-Z0UwAQ@F&3{M=i z3ut$+s#FUYng(a2L!8 zEko7Z@jSFf@J~DgIilXoz@i5|VRev_I0^KsK!rwlIq(*Ih0w^|G(YwT4;rdbp!OF$ z2GIOr3qvxg)+Idbzys()swEGMgI0nQfV@+64*2CE55VJ5Pfxw`fpo-)K;B^{cxiyG z&^3USz*@|Wy#nL#JUB6|aomAnrO-Md-@!Qm1Ng6Ci>Wp`I3@fVI7d(@&JR2j=MMNl ztAoV`?FxUqgc;zFfF8J$pCAEfLl;+VF?<7`74Fc$dqGv8NK`C@Uk#E2UNY7HkM#gM z@CSQ_{}`);Bv2&`;*V6HA}SkVU+^}=u2k(&tN}a5KHwq4w`vy&-0;BS#!QeVh=fF~ z5%_gMDZo^%fT68HrVmdtFc?qp6Ww}=SP)y@btmOJ()lS5zV@K!pOF#M=z2pHlwtQcAztSA*{L94(B^^OqV;uG8_gNkrw@J8Za(7~`u za3y%AQAH4*0_ZH@r5F)11N(r+4U7VALPmiHd&ER*{QUQ*E6GA`4T<~y!ws5Dqy1nBDiCO6%CvMhXpl55~&s?){U9eds+2f6g&#`K5=>&2|Ni<#+spz z0mA@yXr4H2Q1kzEcHFUGfAG1$g9%uIid1d{D;Kgvy<3MS0?fl1KwE|`0IX1~x4+Jd^_zroC^HKKz`Q@Q^P=!{thTyHh3a}So zKGp@=!ft^@sPhW!!hGO(;OgLBfFUSaq>%_5^e?;(T)_8OGiXl535O;V9SgA^#khfSX=mQ)bJY1Etu$7=ofwsVnpw~EQ zJ)l+f#uT~yG@Nk%@ zM;2;LQMb+-sgKTA*av1)c?s%5p=uTCo`RcMNIydyQGoPJP(04oPS4|}26UT3BO2)j z@@b9cjhLfy`m`ZMyVfBMrkw80u@30EDb7G5Obep@s&PO#Z^rUPG3u#+!`s4vcp4Fy#Z&Ez4 zjpE-KTA7J(Gl))Aphz-kv*i>|Yp0q?S@diJs_4{`YA-#d7{~_{{l`+YVcT&DMMg9)0sN91ydaJYC2;J#fT22mDQ&V zj?EMq+>+uFXHxv*H}vUsibvc;vCl^-kKh4~+JtFDRU)P{emOufmlJ4)Q508~OSN`) zQl+Uz1oh?00*ZnhK(p?qsKAC4mc}*1`mQh?r7;~3q-${{_B%S02 zl((RxXxfjMZE`wQ1KK7}VUnrd#RlaQif8_i`kH=BXPifIi+3oxZ?&?MnXmjHA7P$T z-G)`{IeCj%n@M5w*e<+YyIZ$XGg0UvtYadjvw=9@C{JH^y!(!)n>W?pLwck>>vD69>5l%oW(p@u*u=wm?= zDus`=ak@`5TZC)e6YdA;A!UQEj8yFF-vu=LobE(3?3hJ+?*yP`KG(B zRUR%(E-)ATQusq@KihWi9C@SWp(QEwtH_bj`H>GJzYOVYd8pH{r^LZ-+0nkrR8_0$ zcl&(TRL?2u-1R<}Vkj{x`gcql%#RIsg+k$bVVG}`ve*5E=P$XHZM%K6@||pCHX56R zuZ?aIx+ru;cq2Z{yU|m>a!>BNxqSYod5Lc(Rz9V^3imZ-p>Kt+jrlR*@3_pki{VYJ z@0pBT3(tD@8hdRrZy8v$LfYw?`g(mqhUc97pK`tF{fH+qd{nbKgyg1{tW_9Q75Us< zSp58#N3Sy9%imh?q|7c(w)_<|A#y;2^wfLx(o^cDZHZ|fd_mWY%XGe9c(CYj@#Bo# z+~V@M*YUQEVhg4-7Z&D^oERd;FO6vsJ>S?YdTQX3MJ&x1FU$G=WtOvIV)^+JIW$N& zC#F$UNaA0$%$nXNJ3F`hd2avGMbBKBD>CEDY;Rnp`#D)xVmcDhAuYGofRtA$#*|s% z`@<`Bbu@ErKReo2oXMV4JpT2{;-v*$Jm1*AmxmfI^6v0~;b~z)_``%W?Y*c^9mqCZ(H?%y<+mw0p0O??IQxVA>;iXj zAKjOHz}zy@(qLV!m5FPbo{#>o_9MfW(dWbuT_N5s<;U~gIlom5&Pl2;m;CE<`eXbf zLnaBvh}~AyXgwI565V;-8#g`p-4TrcZgiZC`b|xQDx|n`PV-HY{Ri_>UnSW1q;m=23!OIL}OT z{#aV&bmgZNb}xEmyHPT;y0Owr>|@xZ_eMVms)%kKR~$Yu+G@TKaYpHxe`c^Kde(!}<^W{-uGj4|`GE8UqE!xM*e(AY;y|>8z)ZW={aTM9xyX@Zc;&W*_Z`aM&bv4%w zdTQ=u=^XNdv5BFUv4Jp!^GV0$Xzx95eUISk=egnR;rYe4-TSfFM7b^h!ZsKB^4&CV zG~={?2y1lT^L2y{I#FJr?C1NkC&gD($91OCir>m?O-_ay0uF+ms*2Z`FLM8LHW*ovGQYxh|X*()rDtk$a!%$7IMyeqGF;cciWA-ZLrR-!bQLmFX%wcXEx0bEN_2G$T&6fu8?e53hPW$|muj%Y*KX}?jg@=SRdWuweecCnwZ zYp9~!4t61R?+s&j&~q=S+s__3k!q2p%l}Yc#%6K_wff#F&!fz~Iiy|nCH<)*Wxb4` zivG8lSCqw;!8~WSQcr_vL3E@|1p zlz|paTE%n9PrOZ8#EnRkY(N?gLwN_6Nvmr^7DX9l!&oTi5m^G+r2EB@CKXTG=YO;t z6Tvo%Jbs~+E%TE8?op$YpC|pR32BR0DQBSxL7FG6uMX+MGG$#LJGX$eb9lrmNXHdP zKa^=y#P#z8QQQc?cZ+JM)ueUe?$$>$!TS+KdOhMIpo``bTuqd30Q(rW7JTRt^dBr3 z+(E*t1G@oHJ@BpI8^k+fXuy^&o1kb{E18)p$T==M9{lY^Dn+R4rR)IC+jsqSu16ez; z6XEfIRs26I537LXuii%>#t3i0*9U(*b^&h|EH}Ubeox%r!uy83z)JQLMPWWzrfUBL zcyd%b6HzPJ9eggTk1s%cq`v&C=wS8;7XFpOi80I%?Atuq=E{Cw8n=RKT~A^^=ekK$ z-#SoRPT&S}{!k6OZfL=KvoMU&$9jRwRlJuLnLAuGjr}gnesXtVbbWW-#mniS^d$p&T zoWK!zGt+>5U+yeUW*)J{Y(35?&1E#)Bd&;zAp@P`>nJw@snQJoZ_RaOg149V0avJX z=v#9?1*UoD_`5J)2}87tsOsY?@pu1vMiBnfY~%)u(ca&EpDIm8OpNB~vNC zCr_0as$ZMSO`!^o)BQH_oYGV9ap#rJl2z=;Nsxm?R&0j})r7Y)+{5a*P*g_o4^kj$gQ@M2Eef~X~u~6(3 zI81f=<_J&7LbOUTtU~sXmlb4>f1hNLN7MaQEqOb$n7hcIq|nUaFL3!{ zhWJy!!1BT&Z3%0T$M~b>KSHC-)Izg`fHV$o`uxZ4viKz1Y@*Mli9X<)u=oB5+&y2qi&W;y);LP!_Pux$RW- z7dck-h`k(S>nUrbkib}J88e?7sToW5YNp&*8Nsy@4lo{ZibOr>**xYK@q(Nx&Eu|6 zkGCS(A)gTsQl;HIsU6wepHs(*zU<%JD|Wp!Byf>jPgL84q+c85bH2Ttqr{3sm6@zd zqu0F6H<2exl5CQ;i4*<3sj6c+7s2K;m#7kLBY7XYTe7oREK608+esB-rc{rq#SZ00 zasx>BSRl`qhOka{u~_7-kQN&1M}8S|B%~{Q!d_9x6!xrG=IzP9G0Zlu)3lcj-huAV zy-lPA+)vsGdcSrHpQ=m~U4a|YGbWN>E?neC6W;ca_ejfRnQ|H9*>Blhl=a$Ao(55?o>lPBDsFSZSx-T0&SryIQDwm+YEi96r&aU(}_YumVg zVrE(zv2%SJovU0QdB2sX@Q3xMjPDuBHHF+^rMq}fvQqurO2#PEqfX49v0pL+sfzJa z=@021)0eI0CUJ|DwNkpYN_P0(;m0W1@)+YbZK^#d-|gKT{i;uo$piW}*Zp>(?vLjA z=a0^-c$(Pdt((op#N6cui3hw>`~&>o+MC*c@wCt!2@Q=akD6{?udJYc%#EF`_0=7Hd`IEw9NOypZ!nKSN2VTtA^K> z4Ut1?{S~#*G*$kt`cz@hvRLOOxviyVXuc&%_mpes8}B;k-{aXA$l)$(qS>DfgOm;K z>&8-MX6cclH0f}1{fPx%hIW0|d2s{gsyOh2cYp6SpUoN*-R=inr`!dP!kP{Fh<(seWDQ zsp>zKrq*U5?t|xC0q>OZk*#DQ{BhDr83gfT8fg7 z2)`QUgg(=@)t6d#+K*->Kh3EAwRNwrgTH*xYRC)B#LQ2>RhZ_Vk^D9D?icYXMaLdC z&wS_AtGFKzyS093bfo^7S_`?r>xB;@A1^O3D`yf;BsHq74X6A}+p3DL99MeqajR^TDZfkSnUlY8#ZNqknU*d3q^x`IJ2U;W9G&Me z=W-k0)<3RYu(D*UcbTvvG%am%`$>&1hq+4Lz1Hs1pO2sU?#1+I{b>Vjf|j$DT`P3u zp0C*J*de?$T#4aBj)ksf*OoV8*H)&#^ydC-IMVUTte0P`PPkMv(~H&LIKSxAYwm(i zz>uIG_|Nxb-LkVeA~vGJ0zyHlmgk8uh+Z2D)*|feVv2#`=xytRNxOT zZ&H+4)~9lnH%8OYC`6nJ?hslcE^z#!NEKl(9={xK40N-7cWS0DCg&vfRJ!JGZ%!ZS z^Yp2$8t-E>3JV^y8S&Y(a+_CQi+IxDqb{r8lEPDqH{4xzoqN7ssuxz8{AtpGs0muH z?}w^sMbpazRW{#5?R$}DgMN*wVvjig;4*Dvva(;)*8I?U>D<3(W+vXK>AC&)rl+ns z?T3w-)aT>$5!PG&v}#9=@4x>ZXx@Bibu``E=R%v5aJjVpqk9j&&EDs8nE1G%v6n*X z2Iq5m{`U42Wn)U#R$Z2~*5AVTxSw=_SLPl&o4)w!*(LAkHl{D`e)g)-H+Qff-}*n^ z{9dD2)ZP#<9v?gukJm~@@{Kc{!yckdo~&K{MDM$ z`I|O%e)Or{nYOaSlJ=t;N5<|D<=np?jeW@Fex_WDjcT~5>FMN^#*Plt>!h4hh0|S~ z_}!MNp>feO!&>Px#cB3eg=;IiIycC3gl*yVtfATr%Pn?7;r3_y?X^A7 z@rQ@~vSvrm8@sEwM)=Zqw(QXIaO%{c_wCCwuiiiKtf=y?sbli3hSO3vM!aGZ?DvWr z7j`HeT-AlkuuhFy9oswX95>P%Q8~I?TeaW!MPP}hLQ_{aENo)%Y)9YxpB&@j`*d-1 zTbtC?e((N<%hJ`R5Bg`fwP)$1`0}*#DZ!Du*}IMt<;%;**c*E5@qe3Igv||mVf{$A zml^E!J1mZgo_g{vzN@aS;a^>l;8B)KW5iWr8-J?whuBEkr}Enq zyZec~t1Z$NRaNMG;%}skVOOytmnazdvFt6X=&#|D*?2aAo4_q*S2MZH2DUeAqx|%y zWcghqy|x3{!A`Pl2heRs8>;#78&zLv$!w4Xc@I;~rSi#q5TC)OQb&kjrLO$Gv_%r7 zwp1JXZ#j%E;u?^D!%vj}3aCc&K=O63Cx6CR^1{!hdy5HVaeqyB8R--ul}?pN(kU9n zLiY@~6@+!&n(l~V$tKd!jS>3cz=npE97h(fo_@!jEBbVnkWZqFY$e>ig;JG-SLA=F zLpp_q?lKT5R7!RkPx+$`vRDxlf;&RQ+gNL=5!k5aK^5Iz;pRAq#)%>5hLD908xS_8 z8kG`8)>t@MyQSn$L3aNm+L4YRB+|`IG0m4s9-3;h!RylBs4|3DJmmF1t+B~7$zKD@ z+(LI#cJgreDVj`2?^RQEAM_|h%qpV2vZ%sE8FiC|^=hP5;l>fRr=9j*N$W)<9B%uJ zv_?I7Z4_EX6s;+bpb}3jHPYya@~EQ!%E|IX#7{2S^RWccD5_Z!N}ooNt!yJ3KAUc! z%IQr%ts2qg=)96ZtH&M@g9hUvdqo2w*S>Qa1m^=>NwgvJRfQF9O53U2`Z&DODUZPFabHdH~~CcMxQeT zS-_5^8>vEqY$QEXN~fjvXhDn(ye7B_haZ6_-wxn}`1(SEK?3c?MsTdC*=-6v#na~^ z?Yo@DM*qn|`UW?s;e-u{7YU*NhY|K6J{n#GtmIOU_b;bygBgFz|Vsy7n~oWNKq#Ox5w~( zsNdLVWr&S}{|Gxp1gaWmi&!{#H4sCE+j#hF(7y<`_G>snC^DklxRF4zl6#wT%LL@Qn)!~PMM+aUa#6IX~c0|A-+661a%HiEX+=PX8 zh*-I5dIR1X^#8=Wm>vJeJn&c{CK*w-$R$-HaBu^T+&ruX{u=nPR390l0&s5*EJP## z;+WvGLxv2#f#(NjiC8`OlhlX{#I#@}_^1F~KoD^OYBdJ>2mL{WyLzLoMjHXfcnk00 z4j-!q*5FBG)xz6`7!Y+_jD`3g#4I6t0eeFX0{l$)H_jKg<%ly-PZrVf@Wf%gpcJeJ zc}Cy~h)w`!R^#;$!vPvZ918kiA#MS2>1s?HJYR@JL|#}*Ni3(n@``?BZ*!>Zx>Q613f*1Or&&LLloV= zR}$~@g;Z;39PxelhkKE~K8m!Jzv#B$8}i!Mrf7trR1fiY>cSOIaAAoTS5iH# zX>^mH#kfe`|4dN=Wu(_!Wdy3}+DnO`E;!?5)Cg=zweGS={$>+|R*EP;Gs-l1wY-ub6w7p?npCwY3SbB6PQOsE`mXYGk`yCp zeYcby@+E1a)KtF2M6d$)nBC1jQ0B_iy-|7~`q#>$^CcDjF>OI5h0ke8>uTqRAQ+n`BG zx-ysx3!Vx1IyQd_PkH(`>9{}1Kf_l019|L@lkcbtYExds zPTtnj%1G&B@k{wWAID9liju7~?`xW|pGqC&qtbG=mNH1(Dpqkj**EgjKr4#>s89V; z6pFGaU^WRB)*)svJJ}4yCVnjLXNR&eboch5@)`4ia$cGw9_2##Fm9o=S2QsF*%&T| zdh=w;-%~}xKll`GB0pVRDTXtnxw>LIakBg__42sDzL6U9OZh46JdK}Q~`TX?+WTG_^mcw0M{P7JX=j`$~JWoW<1nIXM(dzB@Qb@sN7?`&n| z$K4&|gTh+V0dtsnSx8t=gyy<@#{ZsspX2N5s;c9z9a1B1rO?6n(EQq@GxgSfM;@c& z{#CB^&i$@iz8?d}l{8_EHowT`Qqe^x)_i-Orlrs>6=hf?LH0q@R3077ljgHE!7MbthZ$C*eO? z_R8rGGk0J6{piJc&u`}}^L<@Q)2q#}7VVoiOsF+3G_!2(o$?DQw@1C)k~h-lHX9m` zek-l*PqlkSml`HHCS^~#v*6K+tQO_B9nr?sas5-rH_Axzg=-9TQodOUVWI@t3l6N z3+1ieLb;hicpkCi%9%}6s_c)7Yx13_XWjb^^rt>BT{8viI~G6uuie${&l*afnkVxq z!Cy4#*rHj=DQ>nqtFo*8pX^Vbbk5cJez88b+=zM-`LNEG_)oRHZKsO7w!e#B7WL1s zD~%269oIK>aZu~X%ORWinN_|rcgZAolBc%oXK}RtddN`Aq2QQ6t~4U(OS$;L#ivZ< z%+_DFb;OL-KeaToF3I|1C;Lag$Jv!b9Y^`DwVU)FGxW2@mo!`aABg|Gv0S_S&*7Zy zLT<#|$P01rH!p22M)q@d%AcFR<4x>~?_M0N+7mLbmLuUx)P&gM(ckKZRou$5z0sGy zYj0BBT$&hGJ7r+vYtsULv5>CRwY`3|w4kYHwJ=+^OV`P~Jx(9HkGpD16Z_cL6?p@9 zJXc@Tam;G^dDmN=C)Hie-}KC`*nfWVrrF2WWzP1-1m98yn>9}SrP3)igc}%i(pJoL2+A%Em zo$S?>-%6Wg8~@DmQ|$Ekc7~2}koRlvzs?~QS;YrE#ioVEUD`#)13^A(3h%0VUaj$F z%B!j_SC@o(tUr_nSI((x?b@?dj!q~ntA5|T`PTXU+Kb7KQDN(%)58C%m+;Qd&C)f} zo3TahD@qEsXSXdh>0YIHQiX+;1P*)C z9alYV{SEYu1MNKj#+FzP=Up!~B#du$y!mBIVbN>HQg`2b`+wi{?{G)^h)-ghg$_*l z;O#$~l#7#dzsMVD`=G2c*IN=3{8Rcb$=6Mf^sPdIwLMEmQ^%3iKnnG?vj|Gmj-+Fu zBjjPuT-PU_xbgwT-F?puYs`Brf0+9luNeC)LmYMOV;oyN*NB$~l;P${p*{7Bl&%3L zP%U-$jdfg>sCunQ!wvV%h$yn;z8sbNaa_yRPa18v%C>XfeF4|4afkKy8+hvlO^-?m z|1i00ryi;0wpDNHmzyg_m82EiwfBmj*5qh-q3)pdhW0CO?^5scEya`d)3m?%OU-F< z=@CB|wmLE^&iOm|T@~wX_xMJ^KZhJNbmm6${WO#PeJWQ}FARLfCThOteQc$%xAA9r zh*;NO5f~t8{cpP;30)0QM#@KXm4+-f4t+U2>vY_@Zk9G(LN8ZDRxj{;ck9HiGuMxZ zsiE6rN5yxpH>lN#dbOS7v;N8(S~=2owCby2(?B~?e0jfrEg4eMBe5KBkv3n zbal1&EM*~)+B)vTWdZv~Y<+o-_oDc|DJsNfI3{boPbrRIg)77zDn94C>9zXj)c>oU zwwZEUjPmUAP={2*J^4fFu{6#2v-W~B$n=7hvZHdg)hg+Ix|h4oK--=-#_VO6x9{0~ zafF?XUDBvLIjQ#Z#_uQZ^xc1XICEf0Gm7<)d`&`h^}R{d3)?lx*;?A*e7ERS=|ukT zu!q*+)aT1;nW2|`8%kDGbId5s6nVKnNf#Zw#xT_Ple@n(S}2w7R#yjx=}+kOntn>D zG?2~X&IKfIf`5y=MwcY4<6HXNn*LlH_YUhurvHn(IpMXg^cz2PWlBZKhp(r-YIUW@ zuK1H#Da(5ok;-B9LU)1(a)0Ro?lm1R(f=-o>{;%+=%94)Z=p_-*X65pd-s_yo}a;&3s0muu6d?c`X9@|kNtnjhx}>Dk z<=XBa?dj+_D_jn48S%NHzi1A4nUAF(o%uGS=OgWU({$ZJc@39f_)XaDo9nphP2qBd zdU8woG1pn^6FnrGw@tf|%`6Fv!v|aMGkr_`c%04 zM<+1Tlm&c>woucJ8!t_f@6p{|iLbttANbN=W$dTlYkRNg6N9~R=-Z>yH*mu$PM3dJ zx*&u9*L-zbOw)qGb!j|(t5?hERE{+auVXSg($Im+hA)7TT5zWN-^ zHvTF*h$3@#D5(Lfr@v_P4HJ*jo&GM)rd#R$r+R9zwf4Vp|Au~JUT11${fAF3)8zPa z-{kVI)?{BPNUj<$X$?`q@sXnw1|)8a-x0eiEX1&tTS4jj6%|7H^)gR|!+y>+H1HPN zQ@6)xu-dI>EUW1*u#a{lb!{#2c-@y>L)<-Gbv(wv1%+pqaGz0!@kqk~-BGPi(_8zT zuyP{BXQj%keP4_Jcr~7TfsTRawp*Sv+%W1UChA&icAD0NesBIqJ6e}693?w#g>RouCTh2Cfbn~4MIAItYFZALz>ryQzv;(LIY?|`OU+(?b`KRqnbxX&?s@+u|IU2b( z`+f_QP)E5|nlE&(^clu0rU8~etXC{AOuTu#aggpC?IB?pb^D8x{r-Kvt6rabox7g* zD^I*f_={4Sdcl70NWZ z`lqJzCXe_L{xRJ$*f4zE6Ei0|nw{ zah|-FUCJozX(5sSkw2#0L{SkpG}p+wvT&D_sX_w#gZqNiLA#cJOE{#dE4*(kwT#h} z5Z}`)0|L)IKif}MWmbP+Ur>3`)~VX=Y~$VNEAUg^zF^YM(%m<7GYzqHvMw>VGuus8 zQ-R*D&ERM99oZK0LNQdV=bz|X=q>Q1P`{oJeIfqY{-4P)H(gpporPC%8`x9)Fut5W zC;X_%WYaZ&a_hP6!f0-k_mMnCdqp#YKhJCV`}*Og!_fc<;z}NnaKtrVqS=VoIiM)reCp^)t0zSr(9b2o60bf0idaeLfpzTy7y6!LaLY0qxqW(Xm|Lv5_CxBjB$p7yw5qPDqG z%%vLs)t=&aa87oB@V#~tb289AaNB>}d*1z1^(Ff>$EVH~jufZOCHVRW>dJ}CQf`DM zS)XF;YHDlVZ*Ff{Vm@kaXKbn;s++9&jXlAnPF*VRtzQjPjxed zu^jmhMMvO}ubyX@d$Rk8)9T7`^>Ld#gMFp`hT<)<;POporfbi{ISelxXa(U#{IK)aRzkLDG}JP47fckSEu9*?H9c!qv`o#LM`3 z|5PcHDqbJpj%m&aTeMU3tqhHHif*WJzV<3<4%@XBZHi_lAIje25;T;T5-9T}`3gMM z?)%lBRQ0Id>FnmTI^TAk@b(t}qI;-%T)1|H;cL@q(|B`RTE}lxiXzWYUmvSmEIeTQ zDksF4z+1jsp2x1Kt|6`tt|cyq`)|)k-{in#X@&AOo5c+f@-!QDNxBd8r*v&}bqw$5 zwy`>{OjAIefsXJR_8fawaIgc#Jl{9I&%8f*bgu90&8xq4ed3zq+T)(!offE2=CXI$ z3qrXr$=Jzs&J-|iG@Uf>HEq;4)BT`HBOd;zvO|2}zwIya_Vv7UZ**^UZ}qJ3p7&1k ze&)P)JSK#|f6r~f=IWbInCdJD=nPBc~zP9$9E>W|C z@k(>#j;zc%xuzVa?D605oc5Rl$C(krPGL4zi@Jy_>|u(Tq8LT_nS4)bP1tZtNtI@b zbEGO+lnvB#qboa~JI9t$CV7`|J2mbMP^CgR; zm8tACu0MG~oAR9)t#l)hAjT8)J<6ZlHK9W2N&LHkQYC#SJ_$6G##2Y^+5Bw&8J9pl z&<*lD@hve`DwbC<%h&?$BmQ^p9Obw@l!i+Kr2EoPiX_|3UFW)UL)m5wulyo)llDpt zDdKfC8_g}`T5*@Dqr_xMmR3qO=@3EOuUuiq^P@Gt3isLdN~OF>(gqgzuJ~t=j2X_& zr@QaD{3iAfIZW&+E|KoaS4fL&&HpG|;NKc?S{HataeI-vP2wfyyp%*uZr5bPYe0jOtQNASCrd)zM z)aU*q_JpFR48cF;>cDgIrFPXG*3H)}m$Z*FtBe2!(c1Ke0vNx_^%NK)J&=(7qJn__OS0<&b#NKiHoy_F#H( zU+@YaDaah%)rj)~n*$Rhp5pp-{AOXTCXQc4w7g54>yMODDJLRFLvmhrNN4zT!&6hX z=2OClY0^1Q4|{WaKTjI_v2GM~#rjb9r*;H0&^OdI*E3xn!B(Ad>|cHCTZR_R_m^^o8+Ix)?%UmrMF>V9P88WAc`#@?|V4&A~4Qh=)WgDW_oZf z=u{u_7nz&P5V4p4JIZ@F>HEx|Be<<$5mPKF%ocw?Ur=?=Qh!OdBUNY|)YKYpyl(L6 z6uHF#(TKSxY+S+a;;YUKF3UPTa&BbX;PKjn zzLAv~r5!7FIQ&X$F z`x5mjxruG8FWhoLr=0zH-;{3`>sqQ~o7Y+#nQTZDkJ=*gpXV>Dr0yB!Tyo&o3GHp} zBF(n*C6g-lIoCb0n|HoV>IHV>`$ ztru^exb*6i(0*+wXW{R#UUBHkcNn{Amze-}@!9PC+Ox)NC#_ET_YO%tYZb!2sMc|uu=Wo2Y)@%h5f(?1w( z8p1>`dVb{2&6}$azS-!wWs2VM&W1iO+a=a-5+CZ{d8zWq-KSRnk0x`Xre&jc6PrvE z0$I6_N4|KOomrC4NO7Mvxz%u7*jHjv)#LnOFTZ>9Yh^1<{g~L=Ph)Mtg2qzapkQ9X z@8uUgM!ub8U)ZAPt--9Y*Ezy@(l)2)S9Xi3VbO>Zp<()a*#noQyk8pgKznb;u^AhB zot?wJ-LgmbBb^LQm)CD^?VG7Nm2&f+;+0Z;%i~&^ExLD@SFesYGHcoMw%Ie@>@8*4 znE2_9AJl6R^pq*}&Mj{AqUEc1s_tlo$eWRG!e2!G6CCT?UQm&@zM`%tP8=`&Xn7KA zj-l@Kg58%>{)u1q^~>m+6(7$H=rAy}S)pcE`7f^*T-dki<$+Ig`2 zCQF60S>HX1qmukFd3W5KB2!xY-ui4(SCfrRcNOJye;S^1&31&p67)sn{CG>P!NIJk zscKrPD{4^ccJ*Yd%!9*bg-#7RXLaeK{SE9_$}`HRS8jHXcPH@cEhmk6VeiEZ@?0;` z1$9sRAUP`h9@jchE}bhJ@^9SL8M!}}_NaIh_{P$z_T)ynbv_Rn8&umoQ~aTHS3yEa z8^;!ZGck^z6x<@(9`cdlneL>vOCZm&%KpgS&N;&0O>(iUVY#`s{($zrrajk4{@wSE zr;n$x@322v8lf!U)(C@i>Du6 zil^rv&8u7TqUuecsc=?TVCfL9ji?Th%=h*4H34NY#5x8pQm?d4zYgH?>!_ z7qtfMdz6K+l-o-;)Z3H}a;Drwc1r?v8thGx0>u;=vxIUDrqKQR-_!}~H_B3*MiD&8 zR3RBrDiYn#-k_YlV#;&-KsiL&@N?wz@^~haTg`tYbP+}ggL0M^+D1yjF9ntpDjd}(71XB}c97Ub_G^Fhjg^n-x=C+|$$TmMozzIEA2`U}R8GpXxMXP$H<)iA zZww^zwdLFFZ%m@RjGZq>bAQPa`$*1WxIjbU9eDx!im}R)a+A7JJ(uf}rp+l!{G&A6 z{7xZ3oM)`8OyPOM3x5&oaNi1fVjcb~ zskJ{@ciewo^0I>jG4O&rD<#PFh5w`JD&VZDp8u_PU+>!vdg*SIMp7CCln_BcS}CPL z8bnbE38e(2OOWnvN$G}VciDPfH~;h9`}@O(*!S)|XU?4IGiSyseW zI?aEg7Sj*%kNM4NNw$WTPQH0FstfTgQ$1WnpD1LjKK`bBl`W^$<*KSb3*Sp!#pX&2 z&Q14Ps>r_x@s#oQ6T3vcK{*L?_>0;=wlrmrmL_Y{W?F$Z{We;a z6+~XLGmA{O)d$jTQ*HH;5)rzwUZoFnlbuWXyX1i~8`W-F6~3!BLQUYh@D1dm{8&~~ zK4!n;gJ3wEizjHxahrHqm8e3ZGPjOQM(sY)yT4(HRdDF=5c^RdRVyOLFW0(Ij!|W*A99_ZG*N%W^2|)C@v(%vq%2{-Vk>JIOh>k;a-Z`s ztCh+6F2Sb0RTb_$+g$Zix3On*YkCqzwngR=-AS&*4Aeg5taR7+H|o$giDp_ty&El5 zKjppJj60_vrJKR%z4w*ALNjqry&Cc97WST2ocz1NL|rrKhVO7@B;ENvK)1Vk>;Gvn zRH39hyG+X`$R0DLwM1qQNkjCXoWP8s?sJ_fCkvf|Pcg&T6fH^>S&r)`)p6`By6^ih z-M{`@V<}5#gWiz6puN`<$U9y{HwTB(o$80$4eI#z58b+MMt7=nsWYF0JkHf5RjyD~ zj2r9&eFNRAj8JCOKF!WnW-sUwtrWA8@~YO8%*omk#vYjQp5R@zI#^mV<9 zHc=Dx!`c@07wx8=t!>qwQvxDokP&`A=H60em-BS1?}RpvB=Kc+1;0%DBATe)vWzyz z$kn*l6ptOG-qkLM|LPAy8$v6THR1cd-ExyjWPc}owI&osf(Ox(n; zqz=*DS(A2IZK}6af0K%;Hf@ixN$yNN9LH&0bSvF0oWLw*D|6{wb-F9}fb`oq-K%sr zCFu?QjpWRj8upptq1@S|9j-b`Pi3ENAlt&T&D}h@EHo{5o_jf+UG<8j$c_0`;ze_= zIo?*&+0=2ux*}Hfebj-)Jngh<+JOl75k+ay?}dMG1PaA5yMZQ(>M^n&*Yj z*d9VT?Kdt@oh0=akI2ou*MjZhs>gm5xyC<8*_8T)K1+63x9T&!*Rs+))!f_PH_F?a zA0OE&?O@MwVRJ^@#n=&X^ z;7-=NjI(c}nTzt@WD9xQ^`4g1Vlm6hluN}2CjOeRKDl_pJgdat)~iIug%$)D_rSaw z-m~GagBL=1>NwL}@ttXjZL2-knq{kN=|bG^XQnGo`Hyg$;45~z)b9OkceMnm6nXWg zEvfP48zsI}o&~;if9$@HaqIrzJJ(*c^zHOI+$(zz&rA{j{q12!0jfypm9VQ%- zhDARJew8!)ZQQ#!@AN=9pBx%aH#kPd?6hBu3CI2wci0xcPK* zlZ7Sxso+AdH?~2|4i$F6aADI@4Co<|~=6+P)}yF?pw+nU}}kukcsplf~MK--R#vk3^aVHr*S0{QGl7 zp006s3a?YXF-=U_Q{#ApoN5!(uDUkaRtfjQ$KQ>56#r;U_MX5nDNU&@m=kUk*Gu;= z(%-ehbcH*lw+^SccV~Grw!Lo`IIJ!elK5?oe`4-AmZViq_&oCb^|#^eMITqXQe{HX z;>?gdmsbv+dNc9LtYfpztiGQcOo{E6*dbwAiH9{0e0aCU!{VJyd)?PEWAi@Csrj<< zv*KA*!a-A!)B`2DrV7byk$+R#+wZEwd_~_?eI;fOavu$T8)?mEnB!yrO!_I|P+BwB zp1`HI7T=Qi4V8Yc->%9}reJpYw-qv5K38rXxbVx#gIA~I&5T`8c437@75rt}l%89z zYsucu=l<*$X;1YR2Xjn;r%_e=LAV@0tC%^xebEEXGlV4?Y-?>GMwE-*pE4%Bxc8d%y)%`IJrSQ1`-Afj$LBG{T#`9eUgm3; z`&({8po4s#KP5O#?U?3V2k`-a!a2e^Hh45E&z)@lz0%cIt6EPeErt)=`~KXrb5-wL zcvbb)lINXYzxFP$eOS)Zu=9tXrmwQ^lSb27&k&M8Z~c*iQ+YE3{aGP#d$9vaV;qz9 ziBd)BygJpC%L>uvzWn?;fvQSf+ut!Z$1$;2G=<`OdxKp91##fKp{X*xOX8l~%O5P^RE{W+?yb&~(WeeiU5bZyMTa zsg(Rhv6n?MW8IwWJL2sSvB^!D<7^|Tf3TImw{$@N+dRzqlFC5*!jAM_&TSdYiv7CA zPwjF$JgCMp1MYlwVDj$f$2;Hq`|Xgtn(np!@!Y5srRIR9ryD#h?>85?x4$a+x_QBD zsT7^qH;tYQRZ+s0s;M(djx938*U3*D5iCADU9MVmR_wa8vI z)GGUQZi?V4ce<6Y`>=+yEf*d%+B5&pLwizg&M0WBCz|GP=}Zy(@Zz>w)9PQV)+Tv; zP=5B`z17cr?s@DeSGCx9QPC&pyLibtG$khGOY70d$=t2)8s;QKCYw6h>R6IYvOGZk zm^sEiiivd&j1GL?I`6f4aK*!I6FxouK~NuXwfyFVYeIhydpI&OM64kGNGa5VV#k#6 z*11*Zlad3u3mH4_-MZf;o8v~rj!Re?Q^C|!|AYO^-X*?e+!FJ;sFs_RQ7P|&^r`4{ ziuP;VrDRdp*cz_<*sZoXLR+egbIMsOA;+;q5Bf&s9D3i* z6Q`^8F)<}=U4;JHx8&jcBOVk!2>qx$3om+?^xCehs$J^SssrYCtC+a<%C(h;mJi%} z`Gz}h6ZaKGUXLYKs3g^yUSm!1f7x-bPv7!Cy6XAP^hLt;#N)0{#ff~L5$&bLZ_&ZzLa z@_V~2`h07f*{f6e@^j-_9Ep`No=*@X+~?|3n$7E~AwGAX`UgDYo!OxOF7S zdM0kXdf|N|;>5N}TO#r1Jru=Cd9_H6qD=BRt>yB~8r;m7PN%YH}HaoaqIX{DWFjD6WV!wL>ZMDYdq#o_DY2B8x7t7{7qw6g9qvtHC z70xx;@WI@)rqQ2Y^|{yg(FE^0+wiz@)}}(HIHm)wO=&t-JtyYm6i+*4gR^xh}XOJU)xfB zch8IMUiS(1REubt2|Yh()@IHJ3HCu*^PbFm*8ly(&{L+QcuZJqEt|5aRHS&i?T>&X zCy@Qv{U}sh>B8R-_gl_bFIunK%wmRmF8JK*4o{);g}=2C!fbO6x6PL38Xp?|XvSNu zLfr6qLl>4C@^sIkjDt1K3fIRy?44Q6KY;I5Vt>QYtu9p06((e4y~xdaSeP}4# z*>)@TLCV~cT}r&Q_VToTHzntGfTfEm1$t$1v@O=Y!ftmqG^ZkZ4cb*G`AH=_zQGUzt?L#J%Sbw*|krEdx+_l^*anJSqTwW5FQ*vpOVy*92 zn5&d~`zEV-=w+~c-i7Qr!4>umMO&5bTD)@XDZQ?Lfp=5z?{M?ba9?^jksBD(I5ELB zN4TVvmrp7&%Kd2d(C48tvXvibzimBgn#>fFTMM^_>$9p>KQMa3(D_Bbxbydk zY1hu(-gl+V#a{Q+Jd0y?rLoOon%yZCmL|Q=^=^hc? z8!0W<(FdzG%9QwneMVVGHTfS{6F*3;E&nW)mD&n<);qzSua^Xc8p}WH{PEd@7de^F zc0B5SYx>p9TQ}a+3)!tw>abEL(gsmK!)c~Y&=tBP zYtzfn8B}f4IrHF9=-r&qq0;dm)vw(nrgNm7Z(HW``{VB>ztSmzw>f_x_NT-Kwx!xb z`IuZRx;s2WNf9cU&1S!OpCw83a{KiTRH0-u)xi8rug47)4zRQ6#Qh73tBj(0A-L_j zSBsE$oz9LV59l%7Hrz<3rRnSd?yg>1+pUdZD^N%81gd({muqM`6aG2BmmVqEyUO~s zOTuqda5$R%^_!RP_lI7n|F8w74@Hg{5_uW2M;W<^x``cQ`p|3^llc}D*Q!d zJ;s;dYqNux)^sCg0`pqyq(5dWaAu~5wqGyGPS<(uxc&*Zi#6%+Z1~> zPIu8c^;pWl=tlW$DRl4G6@2Rc!<3x9rPL(HXyxyaD=^19)#nc1R%F9D@ezDfS%25C5eYTN%2aS)2Nl*JqDXb)0{x zhQ|(yG0oLH+8Xu+%QM&2arzZDo~fk$s3&u?*x}^E#gmWjp=`ASfq~(_Y;RKAIQvMy zN4l!1dZxlFx79byY3{6cAhJK2$edul)jm{N)ar_v6lgE&bn z$3}u@echzu!UpRt?jz-3#HKCh=2A7766yi{duqysAQ@mb`Ud!#`-jMaQJC>h(3=0&wRp?$gK*_2|LvL+9si$Sj=>gB@b6E zFJ)5%;EJ+BU#xVEy7>YA^0E zH4*CQWy5aS!*$e4u-%lE;i1Yc)x*1Nb;T&NQ&NI+)q28IimP0a7c)NgH|~OdS6xaO z6H#eGRHr&Ozp}-ticwAJ2-S(JqvZ0xn>$$I*%*n7mSI+kow&BlTj{R4KrgS46;s7* z_PjhfT2*hx{b+J)KPJqAefQy^E!IUJ9+Mg8H8Sm0cWa6s%(Tut=xWqvAc^cX@Ap zwdBT1SGgs>*7~KToi-~_+Fwi>ENm7B^4S#ix=k4aO{GopMkXNSnO^d<^aje8T0HXs z-R|$g{K1A<2luIdQ>mnC`c>{jE=*DNx0abY+0u3(JSr(U!qn+{KBFM zBHM?Z!M;`>lO8C;C7N0DIQ|!{Cq+9tQQpQ2{SWRIUx{C*Thxg1HA%c6`!n%>X?85# z5!|C4QCrbH>n`knYzjM%B3JG8i5jPV%9LV9=yL^LkithibM#tip)$!u+Ow;3551Ff zN(6q0lvaX#b9-&aGyZbu%Yvx4pEBJv(t5yLR~#*zU=}O$qh+K8>N4S&rKI^WZ)Z9y zF6FxVSe>c|xw59QLMn4q{Z?78&ZnxsR+i)Ha^+b?tEXO2=TW4+2kX|3X$z@(?*uyI zSgnXEnkA$eW#{k4l!ye#HqY$Ur2gvuG4~UH zD{ZMb*LKOq+LxPebM55ap>M*KlmMS-u1y@D%&QEi9+L*ho0VK`9yeSZVw%I2Q#0lL zba!wy)j_bZEqJPi$=%RJxvAV)WtmCBF3Pm|n9fo@(cIBSablbJHYG|IAK|Jkugh-sW`^6#)UfxBn-cfPo=mlPyG8c+zV%g; zmk4X@4*P7X^_8bQrrd}aMN=BJ0_Ef%yFDIXB;b<&pH{gxN)QCzrRKma;rm zb4R=TMQJC*nlWc%-&>D!`y)-T4u+79`L=$QvYsIa&-T$KjoeJiJ3Wa+XvCBm2cFYULmu{_M-0+ z`g^xrA9427qx$0en!B61tMs)zb05zx`o2@vncSR+C$@OmH)YPmKMo(rev#QXFC#c! zi<+k;7E7z)>c?#MM{*YBl@C;77E;dnUgraAzVJ>i>T6$+?)ybwWyy4$u`c4hT5Ba+ zF0Expa}*oJdw-6R;@A3jJgS**t~z*dpMf=!7ad?`o?5c;?%>#075kJMn*K%E+%hYi z4PGreR^-Tx7wJW=H}Bh`dilou9|ghe#_tl}oXYGQ5@JVI>Q%c=$%<-?7c>9UUbhdA zwtnP#;93&DFyW@tr*6pl?Ai9WZRC~-Z;N$F$uyUi=YJF8MQMj zohVhcgq%E6$@=fBBf^<&`K}5V+a7LNvg`-iyT6Yg4U7$)oJb zjNkv;_Hc7a_j*s$z#rk= z%ID^o1WRft_N9K(T`{X(?xj$Hd7u4`cr-zCZO-rT@Il_!l@ARqGUA`o>rOH=`^>Cy zS~oAQm0ELP`hP{4B6plE+@-GHIZ^w*%Tl8L_iYE(X<{Fcm;P%0tCHCfrt+YjkcgxwEr$nkmU--7LTI4hUR| zrbHjhHP{`(D0_X10u|^pf&)B{sIF5hx;1&gdXc}N^sqlL)y+zMFvHuZPPq{|1M*Y1 z9A#$K`?>PXwlPC%9;wnV^~0pUioA)d5Uz25!C%^tKtDom! zP>aa=GMA~;-qH=@&jr>#Z~6RnzKI(W)7aJ2vC5igX~I{Nwt6b&y>t)M*E+| zTa@R4&ib9Op__Bx`|F5-Q7eM}qVr*!`$8lA_uIfZY-*Whai349x7iMml5Bnk2zI>&1+ZZ!R;9}=ta zgS_Xm*9QM6cC+>Q_Vvnl%&fRmU-A9EtgMkmy3{>YyKjl2_AnQ#Uk_`!(U(PDe4KaN z5-dBVR-?)bV}qWhFKfKW%1)4`n$J6abBuGWa}IHI5JyFi=eN!-lN*jawB1Ooojk+Y zU4Ipv>aQ8@seGaRqju8HvIEUi?Pl9mwo$Zsuvw_JvY#nRIg||5fBTe9N_#M$sfw~y zDycg4ZR#rP3+uV)Sa;1}-NfG;-fF$7!o%DO`wss;ZEya&Pl_#QRH4DAC2t5*{J(fR zgyO=}eShX>7DUwPN#)BWmVcVqUwZrQw-;Tre9yKf1%8lW_vn4d}JG6>uAH& zO4XfrgG%mQ_t%kD@?VlG+#~#i-5+y3?RL>Fu>rM6{=aYk%3c$CE53X8QUC4?r*zrkSSrP1e5pER5l+zVP_f##{51A4StFCk z79GZp)lMlD^>SZYz_Rpnes3x$Kyfl!Y~?MPOrR_JukqteXLy0@prM84e?Zw9#aoAUfqpa!KxS^G&8?_Jh zTC9ovfpGYmJdd4}@v)42=;Cx%{FG`__^BSyG&-qlN~fnS$eKM%XXX>A=0vtWgn2_} zy{GlFn#!$aK2$nKTPWwnX-Nl)f1W(qTrBu5t5R0`{Ip;hDNP<1?JOPA51TfVO}NSQ zL~o>6l=4)LwxJN=MlcJt@AYeJ8$O0k#{yaw2$QeLtDUR& z&@O3X=Ne{%9Nd{U&uJhd`P9dmTu&`E@ZYdo0(-~)z{E(P}S#O=p4BRWeogF z*)I*4(&UefByVJ)Hk-Y#Rc5wv_4Qv>fo#yxrX0En9cNo9Se0JUm62zWdEq3gfZi^$ zLrKzh>IdkAz9gNWKP4-@J=cx!6~k6ye`C+E9ofNTw|6G|^kvpjm5%*Xi|7D(AXli; z#!mepb$o0J{3k?MiIC(pYo)0#4QR#KJkip(6!m>EY|GP<^r-fBl#Gw6Hmqlz1- z9{PgzVj_bs9e+}%k>k3b$$%rY~H9m*7EyRcK4#*`U6fubd=slLo`+W+b# zrEKg{Cn-OoKGRAcP8dxmiujIdoIR#z6Nr+i_NgAG z)BZ~I=4$f%dg;U2-?X1-<-^I-I-(xqH_J1)6t0STO_`(&XUp4vi)re*z?ERu(QTEF zB~kt^+DQIG>7tcY2Wc0SzG}YOPwz+iaGFk82UKCCK68<6!MtEA&<>=thbZT32ixp%UeF++u&$+7Oj5p-iS#RFC|)#;`jmcOZqTZdIb3iH6L7T96q_w`4n0 zEtJO0r}|L#d#x+GPdiC5nU?xs&0%UG|6|&(WHYxYqx&n$>86SzbY8xVB={^nolTkI z(#{v9{GrP7b#v?JkET@RI`cxNy1bNW^cizdU2M*Zj4*$#P<0;l1HQBJ&hkt;&(G7x zNQcN%Y0bZ6ZSn)tf7*WLfwE8KxSH&D%p$#~_L#ciEMZfqpUymevtF5US$2~bJBjsc ze#-y2ubR25ikBUr9x{)o+Y)ambLxbCTmk|X>K%5=M^EaPO2vKg7OQi?cR zEo+hK{?usZnOuU&;A$vt_P#P#-=*~tzUE@IXIeS_hLXzORi5jMgp<)X;&0klT5GYV zBwD)4t(ec0MYv;xX#-P(&r@Er zTiJ=~k9;kv)Do2zamOT!ZC$9hS&(kBZ{*5chSr-8$y3?q!X>>8?~P935~<>Hs!~+= zMe4(`QJ3ko){FB}HSfXlJ<9Y-Fl}ezE()r;=o9Eem2_`2+D%3vttd}N#u@cd!z@pk#z51 zs@~jGgJMXVmGAj~w1RLys>gqT&ZiJb8_t%K=IFUnMN1>OmT5`kYgaLO3VTI)9lg%* z!q>`X+ZXPM&N6{p)?6(q>Tx`Z&N40awzT}C)|b08r!0Ep9JAI`mJLbs=?2wc{=v3^i_!cCAvi%=)NK*FmAD{lBzTk#{~|$S_UqKf7Q~M z5-v}4pz@dgYfPrskuWv5i>({TVvbrBItgqRy+LsvjvY)LeE!nvvR~_(Ei8}Lsw-QS z&+LtZE$owhcFPepjwK&%*Wil7UV3hw5FutI)!q z>RRNU9=kB$=3a9?bJ?ZlSd$+J4ZVR(hOUu9H%82&z zE@mGke;*hU-Rx?}&^=Xco%cgWU2Um))A<>DF0@#1n1`Cq#wXEZV1!)UBeoLK# znYOWfvOG#W%C`vbvCoN?v|aNZks6qP&^AUknm^{RdlzV&wH3wqPl*?~tAUncNj78~ zlKrhc(OavCBY&Z#S-5*b1z#;k%iNXmowII)~bb$ zSWkxTYEi13wTAqnhIE@%QnyGmqFa<#mS>t~`O}kb^@o?)(zKtneSVL%Qm|gi&@5j< zllMQz%?yu-kMZv^FZ3>rsU2Bw&kkHSPmAs_Z_n$PbThjI&18=q>yA3JJx>zz{E5z( z@N$v!pNe_rO}8Ej9*mh19&g&L+bwt06MClnkK|Er@s0E`Vk3VO%bMU0+uG>xn6xs~0 zyI+U;kpBzkxJwatj8w8Kqj``2pFM55B7s1xzd9Aj!;#sJgFiV|aR-%8iXVl^5K@pF2uZJ}^ z4t?#Iug>HDkvs60IgQBkdnF0bf1%kzSzuZXT@k6?gE1_&3UG zb-uPn+^+DZ>_{2P4_?Lg;}hkr!Ktnld3@ZbzK_`2&IjSejwQYX{zRyjV}7)fvyP{{ zePei^WvDwY;eKu%`z$@v`Yy7HvM=A5X8K0EJb4-R>5(#y5}vr2yl@SBl>(1rmH$;- zmhU@DIJ%4d)^vp8PpvF3^-A(M_&(-zH4VY3KUH=QDSw;(;pzePYwRDW(xpFK&c&RA`YnGknmL z!Dh*eiH)zsH1 zrLB!UjT5SPK65>KcO#{C@KDV5{6+Dla(i0yqUE(#uJ>Vuk7xRL&9;-_rj}i%(`qfs zdN?LK6pt+^79^u}3w#GNhcEnHg9ZlL7tihA7%*_h&6wB{! zS{tq=tO>eo*Tb!oYeZIY9i^$xR}on$$^8=<#_nU6hQ=q>4ptJ!GXvbaZRJC2EM-hi z_9^97_Xsanz1C5_9ceRP)GSds<6XkHQZ0MB(wJE$3AXv(HOz0^CVoiZnsY?7qw`Y6 z>4bv?J<^^O{9-w$UWhJIr-^@uHgg|FdnOd~HjkMk-;;J|EgV^H-QGso;P^c6Z^s6u zw53-563Y$?7u_IlaX6KkWXYcoTsDV%t)1;yCMia!1;UTuJ;b`2k=s7x#T@f^!rt6ioYqpcoo$PJB zgrGB>G4@1mF*;n8d$I#o2Y9V2B;M}yr>7OqmXKi@%m z6<0pk&i1GKSKDmu6J4|(q5SAszSU-4`AEMZCh8%6xLj3QVY?Ze$L!@w2}9WP(TBnl zb%wclL^PFChH=+|8?;@fBI;awx;w+!(c9LZMGbXRrBQT`@}+4tRYzRPL`{E$Vr;+2 z*?L{`>Bwp8yzn(9F>=Y$K-Sa&kuh`&wmDlh+Kjd9Dz_tMW%Lx^JHWAjT9${0JKkt9 zp>K57Y6&*6T~V2ECrdYV5_3VZMt-$SrRtKamCNE{?37wU(rW=uG!eTYR$lS|l&|Euw%Q9Q) z%%w)Ro7O5_#dh*+<~O#te8ti+w1Ao>9}>Qk&WJlG!Zns#8(ctDuLkO?&6DL(gr}{h&|VuT_6t`rkD)GR71>&BwmMAzR%_0j z=j*Ujlu`U6&B-iRJX8m>Kew5>w|KQ=F&gP_PE)UIWwm|Ww|aYasB&3v&ei0P$fbp< z`aN}=7O#Ip=gQs4cW$V0T;<3)%1`9kL4rqrr2fOXqTYfl-E?@s zX3{QA(YAAssME*>^-KOo&B=XD-u_G7MK=d_(;4Y3W+Lr;R9z!jv=&^f(wZ!WgLF&Z zME%UVtIMf&>I-fI^-P^kcQC?K{rUh?!0wXSn^;pKmltjdrX} zo5!4`nyi!czIp@w5JfqT>jK+UAHw?7cI-mB@9=|0Cka$tz6&mSo3yk2UepH{* z&58{DUp855!enR#++uAUcZP1uQxzn-dk`dV{JgfAd7_DIak?$_4c+FbM=|HQ`XH*v zV5eJiY1DOYAJs)aL{(~gQuo`-RB31yZGf*@S)%HX5RxFKyipCoKFG7Dp1dWa2j_AH!p5Q^v{UU_11gc9M zpu2G_eTN>!1$3h&i)h+IPkSgP<)RwGiL~MX-8_sX?1@x~J+H7vatcAjQIs%_W_wv=LpsFMOE}9iqoOeydGOiy^gNj zs8^gwKP!Ya53LZjw~Y?mQKFC-`Wd$vQA-*X`BBpw9l-Ml#yG0jj9%WTn2onAvk3aWoFZp2+?)B)-XY|2C z-D|vu`q-!l?jcz5H0r6ND!S1{4iKaNAL?x5Tcch&s#UWTSp>}JX^uMIetH{NbkLK) z5=I90P$M5zzVQ>@_R(Besg>Ro=}8-Xjym1IBI?Wkf5&vx)F%!Lu|zu!ySY zMqO?6YCy$p)U?KGBlIn1K?Q9CHq?s-+*BWfaEglFMm=#0L5Z5^=vI$v`1ll5fqLrb zXKqyK24txHj=I{|ZL9_r#IdIaX0QVE>jP9OjRtHu>1XV7gvPhg$^aSayNBp+K#qM= zXvQeLi3;*&+J9qo&vi zd%$i~7&rPHCK11&uSTeFzkoFZcLg*~nBeD#tI3Qf>IZ!S7VHdgjZx9F5>P-gp;kKT z(#wQ3>^Ue6{T*!MtxKKYGkbxp&2!D}6oZty#e#`~xz)YUP)f-jV9fhBw z1AvwG2=ouw!0Es&s^+5u0>;2jVn);Sj0xIT1M&K>TOzbS)!d@HL<_KGu3!EYpVgqnP zLW5(`V-s+p11f$Qb^9SNQSIMBKZi(?n+PJvBFGEO3rVcg9%64m51?Df7OXx(W1-I` zBnNsQppyl-7`U<1IPGNk^XzV=306sA) zG=+^;4B3xegN6VmflqXfK*tL71wdyDNK))HbPC3Ul!RQ+$T|QtCVB!=3K9?0k6nlS z1tkM3z#`07R_G-t(IEj)vxRyQZ(}c@wE!79dq6Xww}x4<0tgOfS!R4g!BPbLH7X;@Fb`eR1L|7?hL>f zGz4Zfu&C1-fJ38`3*@GQ-o=x^8mQjTPKK;RuLekRa2e>!=$}DHiu4@l3S4Yh5ujO6 zC8Q>>3LJrdA;Y5d6P>)!&(MX~e^4)Y0dM1bP^Tf+V8?*!3@ZWr2F#!@3T&hZ*0|l@eBd+|oi1F37)&6# zgm%CVfg126b{SG5Our#PA?YCj6UZt{qGzz%0kW|`-BzM0*aYYx1M0`$z!dfpw2n{0 zG*=3}4cMH70Z4ocy$3CYS#oF`bjbjv0PlXXM>A;#bi1|C`cmlGn8LS#Gwg4WcAEX*Fm;9=_x!1$$>f1xr4IH3rB@6!mrpu9Ktg5kzMJbKZbq+mqK@ zRxDGk3m?rwiTd=nnMQZfr{FI<3*LdWM@J4wHLM#F4t;@u0m`GKeFL?+Xf$v&WV4^1 zwHB@hbO!2*q2ICewx8wz4<^u0z*C5-Qxwoj0Aq--iIqcdM(K~4^ex`OPNEhC=mFnB z?qS?mT05kghdza500gl#GN{_%gdAGEi98VW+Oij74P9B#MF{czDZHe?bY;w?RnC8kOICAJ;@N!YgcqlW20jH%fnH!wLCzZ;ZXEO+dcUBvH)JKWKe$*UTtZek zXk4rSG6%E(o6?X~&<&7T20g>R4bixHg;EjJW+vFNyJ5mEc+^7}hHOBmZR|8?A059S zksY+|WSRwg5~9zbu?@U|+QChbXqZ1rdky{oRY4b^Gj<-0ZRl}G0_QDzRD{ zLFpt|VA(+~q019yNTL0PF3%&}=hD19;R0Q^;E7=lc!GvB0*AV2z2H;WUEm>DOwgn} zy@B0=Rsg4|ggIF0z#&V}8#bYX=0k68Xm9MVo5lhL!70!+(2wXb1R3Bh+znvIN4u9w zaDw8%*T5b8BG5AACj48&^MK3^(*HqquEMoB=qePwx(as{ zmJaZ2*dkd(OSuG@hwu%10{RxR1M~_WilzO61t}43K_kEqtYCZ(dm@V{FO#qVN)qU4 z=o)AWA3+JahCObh^{503`rkn+p;J2aDQrV4jRcPtTBm?MhnEA778VpV8Fm7l(;<7H zL$K3`9AGCww^$!K(*q~40>RHtf($*%04GPYgMMHq+G*dS1V`oGmfhv5@Y5u_jJ9(!rn_yXDCeu5gb23Y`%z>|hXhCYQn z0T+Tc(d!+aIdCP>J6R;9upgK+nPe&S1}F=h?xD{C5o}-dLW9nO4GL>CpY|2&gkOn{ zWbg)oM_5p>bq&7;_6F>Uq(aU%GzjxlB8Q(A5zb`dwR z{Ezw}?+6^41r`P33fKqiG!VqWSPJ@u#S;d=*RT@|zrf&Q zLn1-e#?V-hli;j;g3qwMpmQKYpf~X^_#E;O);}yL@HXCr9Sgql(fgnVU=we}(-YA2 z7J3#Cg7+bvU^zgWBi3Z6=b-JwgdcQ31Z^985F~75&^w?Ucn`2@5CsA~KwpE7l1WOy zA2IL(sRtR1@so+};%Iz>0>Gi@#|8-qX$n2!p>c9ZN@G7^#~_*pY#~wwuZn&ooIpyO z=rcfI`1sIH;4wS>flUi};Gq=&GFXw2^58>Y6f)QNzhR5Q>Hvqs{sjcUGbBTp)(QEC zD2THVZ!)dkO-}&dpgVB8wUAZ~Ers5Dj>3I0WE!j&Gp)G@&23m@2G`)H9GVCAej-5( zTEk9bHSmg!s0AniTm&Bj|A&nai2-W>RE`}$M>YHm>&Z`Y0I>ns##j^V5!gSl$o;gF z(CP46V0XjHM6Wf_w4MG3&H`s+uR+ULC8DgP+rzFyiW_z;s0DHbod{teg2K>+GmX{<84sN! z(zxjS=q|Lgg7mMK-U6q?s)5G=jSs$wko^X02fv^@;SIzSbcmQ?7x5;fC+uHn?;IL2 zKx=}W0G}EZ0~ql?>=`6F^dI&Ey*;4`ECdbYlo4ZruLvy(4d|s2!Ml)T&_@^veiZaA za1%psf@)O4EA|2U&qU+q6aQuvLWl0KkQG?Dp?M*<(9aaK1ltF(mYBjl0>|JJH^B)B zXZY8!^q~bo^Uxkn!Za*xAH8YFByd}Vo`IyY)2=&c^^lWBG#Jzfn;RYu-T)3UJ}3>E z1C|B21U4dUCrEd6i-nv)Ow@?&zj+#7%M^PD4+6N05)6<+i0J`#1JCg3 z(5;o~kI`t@QOJ6D;IJTJAsLbd+8P=cz7zBhOXm(zf&$P(?g7Id`q|Jb(1(cf8IlB; zgnmRHO!(}O&#?Ev6&i5^bPx6y)Cfuk^#LPpqSRc%9cV0$=n3=!uhZCX&^PQaiEs?7 z2RH_w7NOZJg;b1F4cHdoWAGg$CA2H#JYtiu`(TNs(73P|pzq)}3$#P9`XSLEHxZwL zWeJ%G>oQE70L#+YEl2}U5vT^c3M~m~3R@6b13ozHc0>?>1K88>q%b<7lb`?(jrfLE zkwYuq5XZwS{~%=7IcxM1!RU z4nTYsRs>=Qplm~?V$I+MP$J-k7J_{T@9s6pp#s_+Se>v-(OVSf9#{it3K243&`Wfs zZ16xVMGcD4Sg?aRk|@A2cn|M`6A+)X5j^mF5G{Z|?JmS0C=5~v5v>2WQNXvTN}59N z!Xh_LjX>kZ2@j;LR7e-b%8mGrn;^%o!J9{10DnMJ@J9-0R-C#TF>*sM;&c_~R$ii1 ztQMRFOaphoGiEci7^F9Rct{awb#yVtZ_slt;TM>-5@*9_w$liZX@~$L-ebh=jdKC4 zGejJoLHP90Z;q%Yh5i6$#Kob}K%a&c33~uK0#t&SlfBSS!&wfrGN8mM7i0%C9X$O! zS|PLyI6xp;2leLAZi7?c`GU6btb=fhSPbxCBg#P>5Rw!2WlrJlqpvzJhZ7uVI-LJO zXC%`fc)XwkE6oq@0kH@8m+%ka|DanpIuC=JfmP5o-gXfDh<$}>Q_#Wi1Hl{6RM-_*tA-DpOV0sbdp~F1Z1n&S+ z8gU5tfS?8F0LTaIDPJftEc7>Is!D4{^bMA8GQo&b2iSy&uA%ci=o6X>@IXFCXhqPF zcn;D9`;E~fWCI`?0{9`FAk`puu%b9xIXqN6i6{{$8~B0$j8#BS0ZPyebR?t%d%Ro)8^NrWuUW72qB63!DKy zhm?ce0IvqND0CzAGBk{Fb_^Qdsiy$!IlL&+G2;gl)m%tClE}?6=5k@{!?xdUGT z@i#~!=u7N`VF4q{23ivshYSaA;1{3=Ot6vgFHRs~RbgKc`2mF+{BA_CVAo(pfCA@^ zSOx51H|-kYrtm`0{T=%ciiQsM(f_e}%xK6xP!#+tzzn{@c?v9XWFJtgKbjw$hi@=~ z!Be1fSmuBRo)~x)&jSyzt&k-GsNq$B@4zrYG$!|4X>1IRMipLo;gcaISaSRj4jF@T1R*fKOc{8;clydPi> zx&l@&JbXkk5VJKR5Jq$h`v++W4gg=mDh5`uv*1?rnFp6b7C_=677SSnxUnwG2^s=_ z$I%?1ZAfrLSB;Zvcw87ClnU&FBV*`W=y^~I-Zmh>854FIau!)u22SH?WSqF;4d@AA z2sDqr_jdXmQDayfF2X6KB_dL8!VI8>uY>i#dIse~9%8TId*CD(K3pb!1FdREwKRGH zvq2UVr8jxXRs(#Ht9E)uByP>2d2nhVQH~jK273gN3`AAo*Qqndif}m58g6I zH;Pr#c{me-M!;AxG&isZD##}d0_|p{yuDodR-s#*fRm%2LFp`6!&&q>;4h#|KL_)M ztS#6w7J?IYK0}#&SV=X4NT!n|ji57;{&+)>2WVc<#tRw=TH+o3!I>9Vn7;=)eM6r? zM#L3rCQz80))A%rQD6`n1Mw#84Lr;^`UZGK#vStcz{{|O;AKIgfzGlC!+x@#5ktk9 zG~PgT&#-GC4?w$!mqJzq>21STmdJj`897b|;pc!~;|LnqTd@5=FR;y^fgn$zw?H+Z za?lMVKddoGUf>-TgON!SCb%I}ASYneK%*hn1*;EsJWgKyG(P^1??Ex}N1>%blg8+V zuEKXdnh7H#?he}=`5lmNnA6C00B^w_fb9iK2$3v&hg?E zlXckjfD|+XZiZxl^ux+A9%cg!fDK+GXbBvK5#eiL@4(alFS~WZt|21~t&MqbdH~!( z&LGlfSd2ynBHo9^W8fB&95x-eA5X(mFitHE4;eFZh4B>RUf@|s0(c_eMOY_Tts#X# ziGU1R4$>S?U>$f4{tjd={BvkkWD#Orh`<2P#_20OI-H6i>JRG%XArP+fGbFI$SdqO ztRBD#D+-bT>j#FQZxIc}chIJ=>oGTE9>z0v67c}g1o$1Y54#Or0{IAwAG?8d8X01+ zslxQVk*$c>4&XCp$9RbMz%qq~h5umC3Umy33zQ7s6EY3I5buFkf=>ZI<}^-@ps!$2 zL8C(!g1d0$iQxFy57E!aaY5t~ryI~7;80*5Qc@r(>!!8C62%$BW11iN!bNB;9;(3*C|qel z;R+tp6L!k6rYl#3v6A#Z*c%MZY@-@!&}Zmil0)yqI&(0kXr($?Mew+hcLNy?-H8|+ zw75imE6!$J^v6ph;gk=u2bNGO%>a7!)1JW3gS{3dSd8c#Fq%f6z%IpXSZy4=1FIMj zCdB>V_ZadFHYMbb@V0xyHMp(XGHI0{k_Kf?k6&4a?Qh9F_bkQT7cu|M#iVBsOY zigBC-2e=Z_1J)V%7LguECx0RB8P+ZA7Faik&B1$w)q>yPZ0w4mIUr>q9Y6zywG4|9 zGC-%9z%7UbAQp~Yfh2(C06Z8v1XdJ0oM<71;}iq9gKj{sG9u5gs^D|ON-?4!CfZAU zYMgl(QpE5$pdlg2WSScmGM)m5L&F*R5VM0bA#fPXW~O227iNGS zG<+Pytqp4xx&Sl@`vcZ2VlB`N-~~hHfP*2^j5wrWV}iDfQ$_5LA+LcS$V)s24F|Ze zCL`u$oY?^q$TQFyU^P4l&xkma-(w~ub!PzUut3va$G*g7^_;}J` ziKH(wsHze4A>wu|=x!1`j05^b!WvE#?vpObpqYdEOOiHSXmmGKIilWWbbF>Kjrxw} z(Dj4FJ6}+@t!Gr#hwh^>TM2?7b;WwCccR`|uk?F#_o)YsoKOG$rjH=p4rc074WKuK zx7zf6CPAj^(`of)>SoiEX8BS-N$-A0@b4i!Vqd8O6SIbVp2Kt(X)r~lpmAlrGTr%F zPZek4NDoJ-PEb1C*xE+B2%F$2)n-{w*xjk0A}qj)sLYI~-F{DFA0`YvrTdJ7nWJw6k|Bh!~^&M-7bP+v-GJ;wBAzNR^r(Z7r*A2 zZ>Vn43jG3gJljq;<%&~v*A-+_tY@Av!}aC#`FbWr|3jZn-k4S2L{*qRriw^72_CQS zq5DW5(A}*JsvDF?<4>gfXqWXb=`Pk>eJfSzd7|ypv)MINnJ0njHHGLl*EXt#I+ZP< zMYOhrn>SRIc?&a0Z$-Y^L#7oon!1qvO8fbLG<^khRLS%8v+=mQClH4aoZ#;6?z)S+ z!{Y9~=;H2yU_pW_GIX*RZVMeykxGGT&aT7?shDsfv(ZUy0O>-m5S^s+WH9M1{t%y`D{LRh3U!el zpcha8R(3B|sE5>@_(hzBhWii~(UT|=*=@6kwd68_!PoQA)o6<7Ay%O_S^)Cwu3;Xn z@w>^W&2$l3XM;>KGpgIhBL6Rt*iCjL*GgMNFCv&cAkGq9h;8H;X&~xOUq*&$V?1{n zUAyjzr-{y#idco7UH6C=#2xT69Z-j<4m0~C=Ao7{L7stRa-pXuu-3?GB&K7mm(f)= z6aCp15>aFjVI_&^e$;`;6K_i+P(Me33fwDDoiqhq+j?P)hs4&X?Ocm|xdB**UZ_C4 z9@WwaK}(II*`zWhjfiM=$4_$f}1 zE)sWeFJq)|GDWn-DsM;5-U7%9cz`$?wPMepBG+ePJG6EX87@5#yQ2Db7_!*@L;od{ z-z2T!qRfDa3tqE4B}@*tkqTiEAnAL4T78vimmf zj)#<$)H2$cykLB&eNxq?ZkD!DWkt^kTqj%Iec-ocOD;(C^3_?ZdQt>92 ztm|5Pr8cXsYyHRC14dRf5_+mZ*2?yj%{S|r>L|^9bw`B*dw@Ky|JKk)R9BW2%`_~L zhsgG5dfT@4ThYkgxs`ekzI&nkU2bO9v2@4GNk2AcTi3KPpC(k+VLp8Wg^1UU96~D_ zC3z&;w_^U|`qxY^xsfwCuVW6Gn^(G|>bdzpQm@W*-0RuM^PJlzFQwBl`y;YHp%#_R^4DT#)at)yqRQ%WWgRNhT*cQ61{k&*y;u z1@|(~4EH4a40#rNksqjSS$!+7Q`vv@i;6}R?rz{69@q|dCVVzT4U3uV_0~FC{f$ok z)9yz~YRk0qp9?<9((hG|+C&0 zowL6d9!DiyEq%#pu%9aUYv2OkX+HBkT3UbQFB!e{*(HUAi?e2xKQ3xq9?lDfVpgYO z0>=b=X!N^LSa?~})=n?To(6OEvD7K=J|~`keJ15{vTKgku;1F9TWZ_d@VInS{*OFOhWn4?jK?KgbaVBo zq>tS@kBi?du8rq#MHLP8(28wPowOMzpfUIsLeMnmwqy$W2kqvm&y5)S7X;W$HwxJ0>Q>L%&FO1 za;EG^S>J{om1oTH=I3-*rt+$e^Vau8r$?Baodn>K=a_umEpmr@0Zu4E-ZQjN#N57~$ zflcj$1B~I-?!UxXZBdm&v6!~xMRZcycSB}w=BJ`EuDk7S_d_1m!9mT2HGA1u>+R{? z*JY(T-cViHPurtxd%?1-$%RFgBXxcC>kJcBZ>&lkKikZ7Jmfan#mS~x{z@LpY!@Ch zm})W%x3vDI7sWUAYl$ZjLfR++}U z!Re>6-<9Qxw(5oCFo$biBg0<>jPq4{HVyvA^Q>|JQzT3jpVm&Um|pOwHoyE*c}k_V zZVi8pcqPrI9c)>feRj*O8mv#-C28);B=IL1EmSvrGIy->F+G+twD(F+oAhdXr$m?2 zvU^@@Ba*zHsipO;5<W}p7Ge{+syF_G1$1jhOVLhOiG=Z)if`v;C}hwngDjMrkCv$hyGsWUeI>$^0pL!DA3xq^-B;|EUxy@XBa>7tGS+h zDcwx%FS{e(C@)uUmix#&q&(s%WoBjkRO5PnEWeb~u^E8;hAIU^SLIx#5}i3$6JKp( z>{h5+Gx5$Rop;zC<`y^fF>R=JEoq;1DF1!=9z2d8?My#-}w_l=Ch=HaAHp1XpQC9jI zz0G=RUqe2li08^E|lOA>a?CTH!(#@ui1;JvU`i3 zNxI1r$oBLxrY$Pg{!O^!W)dka6h!{MI6~||Byjbl6FXW>H*8TnqSfX(aMqku{Z!5A z^KwTk^n_C$7P|<2*m%QpZEWS~>W@1Ay1<5025;gX*-Ac!l36cQZC6iM?Nm&X-Brw@ zw~4-}H+on&BbYgX%R-+&ckuu^dJZKwqN3tvB84hLPs+=<`|{*F>88|8dP4-k*L^7R zgcG01oH7rgg6RL)3jP{3g4D}f$Tv_qOonPPgI=-xQ*IlV$E6q?%^t?1=)C-d_Z0>S z@uUHr72Z*e2s>I%pC{*%w$xRkjItu$;?6gVI82V0UZQsAY-tBMLoA2Ckcnywz0ql8 zrua8mEq0eSp(Erx_*+@1#t=)=k^}01oFpdFn}xIdHHo3R$VV!|m=5Tde4Cy_BnWlf z6_)3cxJWjZ&*Q%EyCI_}+~yBT1R0AyCYCzUZOJF(MARuQAl4HBC_w*zl6Aw`< zbUN_^Yx9GcK>P(SZ6s=Yu7h7U2!5P}^AU!~O#^DKTH+59dPrx&`>lmH7Ku1dCs^5R z{9OR5SPX<`JDyxYeWJENqsj=>{S~{29mJX9Rk2hIlSaZ*h?6>@>gh!IL7(A=TEYJb zAv$AD!*T2GObme!)f4_v6nw*W=q})o_r}4y4gFuF$>PIXuwiR_-GW^3@OqpuHdp*J zg!lrFtvk@jrudEv5lwcXR#A@BKd6&CTG}l-pho6+F-;6W4Ux<6qV~hXy9VDT55Ax) zYNYmup7ew#*#={YM3sy#_--?dEfn%^27k%o+goCK7QDrRHN07@oNS~?=tR;Pok60|S0fLeyC;0!EJz{|{;?hi zKsR{4^N8N?>;f=PPkbu~9(DxY_J7$U_&ksy3uEsE}}!W8)o8%Rk6e{E&RR3(7JoXamYFY&wRwrvT)X$z;~~QN4_1^R8oO$tVIQx zU}*m&sUy6`HTbVI^f!1yXE5gh=;yrvv(!Rc)}d2*74elgMs$Qfe-E{i&*L2_kYI0Abl!{kN8tZo zmHMLk>lJ9YKm5)i*cZE?odLufX(p<|oPkVzp(8Ftk~|1jc05^)YE9Y1PU@p9hL{OY zHl4{NTuB$xG_eD@lCn~sCbGC1l&_ws+sH(l8Z)uV`D{=5-@;&mM^B%Riq~Wi*NN+- z?=BtYIx&y%|bLY$%sxN)}v|8-yZ?;>L34q~Yd$ z{Cl~lIA5I3L{NFCd_xl#sd+*TH;);EdOOG1q3ERYNhuc^xY@!>daukLJ2{G*Mo*DE zsU^fZp$q+lKW}bM58*2W9r>?pt5vx+-TZ_IqI;vg=T2raA5KM*Lqvjm$i0&C=()r* zg*9~ww&sc{Rn}f?#3XV4s9KxE)S+_|>Uy&aE}TPF%t?VRR;6 zSyv)g=!rfs-w6kLl6XrDB5%r$=#I)fsC_~NH9`6%Zlh`1mi;V`5g&{5_%70O*wtA9bH@OS$tRP=rt_nHWYT@n?v?>H9)gV~~_W-KK6*&gjhjn;%D|NX44A z(p7c?r7;rH8rgjFQB?%_&^TE+Pns?EV65qQbE;V{A4@kehMUh?g>!{mBQaO)Et&vq zk0ZYs0_A@RqU@v40kiwW#qvFYk@S=gWH-`t`Jd!{!iMK%cV&;nH`E%gm$|Rpz`r+t zqP{9OQR#-RWN+DRx+8s`&(ar=N$h(0bb~jkFf}1>b7oa0tbvBL19-Vm8o*QbncM+o zsMU2@g(-r+q3BNclsy%asSJ5G*}OiV=`HLsq>J9HtKLc1Rhn8i-*gzge6Gl=RZ;eb zZF^Z6rA~5Ionz#LEd5t?n88XU%u~e4)ebc(oxj0X*3xQ%B2hIu8%xfTx&C*>ZZJ_U2VK!Y);u5 z{x;W`u1WRgj)uh*J8E0jo~_HNSJk&xC(y&yvwY&MHyLI!CSN+z+Pjmjr{f5h`N}hS zOA;I2*rjerqtjBehseW%&d2TyD+zxVb1nL?^=9qEoVG=}-22~~{#aM@P1DAs+GVZp zqR6r+h06e8rFM*NafwUDs?=$PclZzTKB_#cyB=@-4!hN=r=e!~M&e;v_o}l+2Mrt5 zhj_;#wbT$ft6O~IWsaM?D#At8@8tEDH$FP@Irm-C(_7z{+XcmqkNXh)vHA7h-P%u5 zOvojFmgU|~>-t9X?ofr3^Rr+#zfZwmTCVCe*DuEWxX81t@1Jd{BVW(SxMS>L-_Cx4 z)6`Hy?9%86>xt~Xy5l-3{okBDpO%#0vp%G}UXrbB(c{MSMV)*5Z*?#7uaz90tk`^d zcgMS~FY^SZlAWvA(}x zKX?6f7FV89d*AV82dl9$!%jDm*`K$5ATXa#-st)0eTun2)OTjC1sK~89&)i|m0LTf zYsRlX8^65wxYgZ6cqb+{yn9`XWt!MP$MIE@)a`o6{^XWaWaq^nwtRWZiz@9EA;bP{ zXK9_Zj_kkKYcK60_-6Gx9e4E9lemg`RC9-=VYB)vrn&T$d)GBwsQ#HT{@J{HjqY^K zr4)^Qm-^0b+M#E9`_QN}#!-||ujeqhk(VQRW;oQ7wtC!L3gFiQ|a|qLKOMUh7L;9H#=b~J0Fz?`5 zHez$Lhj}xzi<_<*9p8BznfLWq`B3^(N(jDt<%yE$8+^q+#^Jz#S8HyLQ>%jWccw>I zMihU&cl_y&ijSdIEq_Oy473g2)$+IFy^4cxqCU^h9#S~C;$hi4Yh#Q<+byAy>g9~D z)YugNXGHSq39^D-~7&(Dgq)ipW( z>-skv+PAfv^Ih6r>Rz$oL-8$T(gdU0uBVsLJ;5)!*}oyZ6%WhgxsU&JEgzJ>t2&CC z?T_NP_DRj`UEM!EiLdl+KXvCUCpTSI%j{xfrlr8$`Y#uQl@D5!H+OFq(|6>YZT+)s zxupG%#=o2KGcltyCrth@X4cTFUF?DvtF8I!+Sch4~GoHKKPyKwaz_%QpCs`)(^g}t=dH>zFEF`HYw0o z-mbkb;NJd`GwRy@RdemJ_49eZV+xvQUnrdCda!%apl(qQRTHHiW|xXfU%o$G@?D}1 zxqR>$>{aC(;9KcgLJZ1I$vId`)b}r20Dr{U{_oB%KEu<-Cfy60Hh0H>8a?&qT4}n$ z<)e1%jXlQv4o%|Y-UeQ6l+fqc=vThGz9rl#O{uKT%sZIbLMn*S_VVeF>9UdK$S>xB zDXt0MeqO5Yra9y6@0Jwe*mSF(kyu<-nsGeCA@@?5Tjf2ggYHXQ)twDdnZKSt8|POs zeevK2;^w!CtY&7LUz0XxZ_G;X5HhSqN1wvr_>soR1AX1IQ@*asew9D&%gnC>40WM3 z9hI?rf)d?R9Dfq$GTmSFfB&H966)}3t=IcpiJ8(=<#>#}U$dzC;!nGDW5!tNFPi{z zWo&%(@A7^><6{plSvL3tedzVlUn?rsJ|fmn+Zy{L*4w)E@}S4DpJ&HT9p*PT-~a1> znQebAcsuizuWo9Sw%wmK>F52kacFQ?weefgvl}T}3Mxt;Xq#By2n}i$5%R{}!+O1b zVa=C9`;3U6)3}LriH-{YtC?68mz~&xUU;|1JYx4RGB>__=__LWw$1_Gwsc;-<<|E4F0+NTUNO-D`dHNV!WBOU#~xaAx8?r2g~dSZtGeIZ zzh%JLJEh+0U{c|j(7oBLpl&VgJQ}{6c4&RRZiuJ9cVklAm%8qbx35!SMyZQWl*yZ-De_acXxTtR1U1~rJLXw+aq=KfmR)?=gVwm+qIWIrN4JBEGL$$t<@8} z`bX@H_}k8!-KuY1d$p`v-kE%TeRtcf4v|VPt0a%H&c4EP?Mr>F`HD77d*2wMzM$?y zZgF^LJI#=(ooG+__|r=EAycV&Z`_>s;&)-S&XiEszJ811j>mPkDXLS7y*95ELHg-c z?;2eAwQLfnrk`0A*z$6k{>@w=pBuO7GtBomGk1g^O0QNeK$nzyaU5zNewBE>E%`_` zQFP%d$sqY+GDdJ9x6lW~M?z0@+Nc*C#r3>{@JqNR4yOha-spXLfc{s|af?vXaw1_M zL#U?Y0%xyo zVuMMzVYQb&qm!zM-b|mDrix$5T56V{VW*R^jI&UKn)hy$o8T+F5U)$!#q;P2+McWt z>xqAiJRpXH>rYA`-%2s*h|X zbzfL01=1^}1l**pC>A|mI7A*hNDQh##!)RuXKA|hjqo9z(eHC3;Vqu$D^R2Jg_KIH zrhLgC@XI2k6d_)6B7Y%Pb`=rRqlB$!3&fYI0KLEJ-oW# zcs-U*wc+qLzoL$&r7lZ3qUM%ZxI1u)$M7QM|Km;-!V9$24C@abZ9TAwQh1=2+KgWC z0Lu}Jw(v2vh_yu{{`wOhvmDP`SgjVehJ{;egLhh3LKc33B?sjH82CI80t>Uil09nS z4_LTWmTEi}Mu&wBVBvaOIR2iPorRrk$x;75exZf^ZQ%t}gCStaGPQii!l1A)eE*Mg zY+?OcI9V1JxHaN<7G|e~VP#=ZSTcGo{2B{y#PT%@3(1n_V5yg3VX*ukZ@U(=uyFD$ zW2*Sy$SwKfdd$PZE4JVPme~FOm_-tn_ggZREzDpGGs%)Y6p0s58h9d%;0qmd{V-Cc-E$l5zwxOjy=?9=qkMTx7;29Q{lpj`I zhxO0Lv(Z2dEV*D7Mzw|WW8s8Yayrm&<_>+y#gk582>4?~EQ}5d`@;)QsqyVfyu}Xk zwgo>T8Dq0la&^RNvKT`l(7+C0X!zl&-}sv}{8NCZ{qdv?zVQ}Me8bGvMVgdAJ_v+#?C;@DGK9r2frf~ z@AX8zTnTpPFwkL-|LKFJqEH6#vr4HeBJ}Im*%ZeE8Va|yMFQ_vNm88HTuO9#8d8)I$^wDqt5*^i4rLHk19mH0Y|(`GkT zpa(iGMG|X)OC z5(`3BE!Uo#C7=Di@X6neyDnmD~b1F zJ}|fY;vdxQwIUZ{y!(NB9tXdJ!FcvdI?*hxA~Xe^(jds!Qgz}HbQj%DrE}=96@$)XL!cYI zi1|bxpoQBYMSJNndJZ1})|Djff`)E}eyj%iza4yzk-!RvqYq#{a5qb311ng2i_Qqp zsba|M1b80PfUUQ~nvNrih|$=+rzKaQhGT(MzQD;`41BLCM*IVn+1o;z7x0@OU`18~ z3%m%;jfYMw!k=W!_&Y{=O7g-QzlLquiFNLY(SFAarb%fcx=~?96;d}~=a2^W+8=zs zSlS3iQ8iG;CBSZ@@C=JtJe77pztXWo4r5n45m&$h=?HB99XgtC#%&^oxJWdiPcoC~ zd(<%Uhj?Cy6+C$t{s?+Ax}wXKCw4?DayxmD>_JtN3((0aiX4woD$qr29}vlT;4?Ak zR80WkwN!E*1)FEddDozJbRFzQ9uQ$UctHPw-&82|#h5G=R(k@=^&ufCF@`!v_G5Ki zENNsk*3k~G)>(=G+Lx`;FW29#jnHQ6IQ=;TEkuzF^+h&WS&t~kbcGwUjG9IjOBcjY zsgw9Z=p=2$X-<&mAomZ%KhU_x=qWb_UCDOid@mJ$K--$(?0ka#fqDSwHROkT)?eTt zy@Re5Nvnw};Vm_h-e%lw;Hk^jN1VsFwY4?T9%7o|UCrpqyfRgJy>_MXH@A>Fr#z^t zP=#qOs}9Q6qI=(7aRYx%a1j3pPox{fC*m)1BK3s|r}Dv;Nx%q##rs%+x579`ey_Mq z>P*grMwgKLr7HBn)`5leRBDcs>LdCiCW+Ue7u9@QW(adZpP_3@&2pR>5E(GYt_iW% zbfxZSd540Dx&8l4(U$Pv>Bj0QHixV)+KjaEQ}_~<{4(_0Na3FejPOfJpx4P1@>9$P zas|P{@=p=l3l}*9|AojQN02V4@O_U^P^VC9e1y0GI(`$;rOjd$dJG0Zg5#x+;$3jj z?vXK)nMjC&dA}j@4glJMa(WtQO&#Hv7-kvWxgFwJ#6;}KapV~45Pga+ zCm!$&zm>O>p22Ee5Ee;`$zx;y)tnkmd?#c;k_BNZ89^lRw;4xfcKwa&uEKTS%^kM3 z$#5J}?fh#|+Wo9W85wE*dCQG5r=OusL(jNRwzXCyNEgj{+RtU(s%9F0F?VfptV=W| z^%{*vxks`w4yx;0f1BGNZkH}nCc2Y6Q2AA+A}5KHxJ~9}{1D*^w^`gzX_$es0_r-U zp@T^+D*7jK$Jw*uMV_at=}ls(l2MGQJ5nKV`XHg#@pd*=H~z#VnLnQU;qblLFQM|H z=2lo*?9oO!ZVj3UagnaFsQd3j<>O6-vhns=&OKa?I!&?uDLrZ!TlcBjPItsu#HPvG zXxywktRm$!EbtF*vMIoLqru3QlWO^1dA#fy%~Km;1@H4bH-(dNgK^W?O3$aJ%e`np zFf+f%%~dXi!#G()z>vY+##%Ma*!Jw-7hh9){WSm9n%rHV#>BNL487%?K)lpemu$-K zn^#kDT}ZVbkgw>9rNrbc27Zb}n)CA%oR3wW&py^H=7_mzFh*x6*p<4PM~8 z-*$zxs9vM}R5hzQOxuI~s@UMr$YrB_f0-Kiv$_6!gPlIy{8q}8{j083U66HWt-|Im$wi;H9a)W)GJUk>*JA& zdv1>VdL`eXHi@kDT+!xSr*=^(szaqN8A~&76iW54B$-WP-;h8b?|U{0JYVBi`n7bR zb_M%|9IM%AU+T2au83Y~exUW$uFyX;uO>p|_hlaH!|HVOWV&ir7zda=g{xd&;xsu< z-buMhwvs%`cSncKIF6MZ_-gjI=DVty{-3gD=Fo_qqc#liwqKn5_UfCPS?@dM{3ttY z{^5S9Rb4kR=8bh;jrZ@7d9Mpq<+pX~WnDd|hxQ3cb67>3sykX?uF9=c)xO}K$htcW z@i03SD^l6Ub*<|cHk{C}G24o}6bEgNST9w&5qH?r=B4aEY`ysp`&MeAG%K7H+o;}B zIeO&|Hj&~?mNAny5$d0YwDLkjbY#?c-+rI%qrY{yntpG^NB-y7Kh5;(9f!0T-D7cV zkwajxhe}JTYz=05o^5-F&-Rs8jhKgg zf#HYNs8bq_v%X}!e4*xu%@XxvVmj|`Y-A=_CEJ)^C28cR6piHvm?2UF6~|r?>x}R8 zZ&VW%_w?^eqRdyDRF405K(@U@>Y`i6A8vd%=UZUTA6>oMw00eO6vQSvtk$~oiK*OC>YA|E(3JM0Y-_(47myFybep=W&qGF* ze?wM%g~YJH>u(NXJx*^mY9RM zFVc9X8$D0af|*Gz5_Sm(%+0B$>|{ef^$lfO?Wdx6s&Tudi7Pwh8|@PxKd5?jJf$o- zI{OvZK6G@~w2m8tHmm&DXEptbo@J!uirNU(7_VkQz5SA%PbmFZy*9LLYH3_me`9Nf zw_P`fFq=WDc)1M`Yua9OttLsoMm#K!m(NjMS6@-AARqJn%@3 zayf;4Q=@*(udpIUI^S{K>b=YBihCPPj`?(1Y~HL=x%RVpJ$27!jPq@`<8~bwPUxY_ zsa{z7rT$pM7a~{XWqsK`RT+U@)X^_Vm|GFR_m!Z;`8clKcqV-i1YHbYvGE*Ep-1V*|Yj?_y+hi!xp05t7 zRT-~RQ`EKA$E_}E`X~;P72Gm?Mg1rJO{2T8l-Z){rpi_xkuQ^(%--T5qo-~L6HNzH zOs`6CI2=8w%Yvx=QuC_U#lODwe0As5qc4v2AKfAXUo`3y9S2t3TA6M6wya}$ZA#Lr z+|27$rEWU{{`FmK&&VUi7rN-O;G*H>XACB~pQe|!wL?#bQ`VnpAGT}l8f{kH&xU85 zJNdUVUwztkkV=$gi@n&nrUMPX4JD?1L>t;uS<0N1zoeq%rQ$=wOJba~xngyxm1<=u z*QPY=q}5+6U2`Gh-!}tawEMQO+E$hCIxdij{1PE}-%tt-H_F}=J}YQZ=G4%Uj<#Ro zQQ?{95^Q5dx*7)76jm;&YNYGQ_K+>nT(LP}^GU-i{+0$BUG*9IW=0d6!R;X@C{HW* zDFnq^`hs*4iD0Rwcy0`TMp#D%$!5~i6y0R)#JS9B%DuX6X*5+I5YWUkxWTS16VtFi z*X{kDH)UzBD?`Lk%`DG=@V4QSx1<>^wA2+<$V+yVKCA^}-})Ea_-T&G_9xWOg@Ag8 z+V%A_>ofF$>{OV|q@}o9l^G&epm^W_#wX=hmp~ z@I{^zR7XiKZi2SapTI(Y9sFG7JoOw0d)N2Qo~j|j9>bG{mGwupOLP>Q!gNxWsk)%M zdQas%x+gou(B3@NxXW0_-6vMl)yj@a5;A!~o|b(0M#e?P8GWn9BRM(_W3ybiMRNeuv^P z?E{k+`A9R`rNncA^CtBWY6l;0cu{?)ynEek)(%l~V_M~<%E`JehDbfj4pZxG9Bi!AdzH2FX~f@#H~QN~W5akeAwDDXs4c36>W9o2 zxi$SkRG2=o3C23y3_2NG*mluuD?ePF=C5g<;Af+GY&YLoZOr|g{IVjM%UGN>sZcJz z5a0aGz-njkaHH81``?=RszA)*{QbT`fSl)9<;LISW@UjSl&n2rs z)848zWxxOQEqG9xY}%s?a2V+@&*g+qq@$;70mqoEbu-G<$(|c(;<7PG7uF$rr z)fna&oyQd#=jop7hMMw>Y5aJ4o7_+44b5-Qn8iT(32}BUMO~3bmCP)8=lG+^44+5V zZCy8bGb*CQBe^)mJ3As%{CTFNMt;mU&BxVaRlwn}QJ!0f&JEjZ=W07wsfsR^Hx&n} zLsgHg&N$6;?r)PX8zlL#+4V*pS$Ds_rMaUpndzW-q;OaNr`{xsr@e@D&fl1B8pMra z*K>BlFlw&sJh@X5BKP7CsO~E2s+i&zRsrEQt{hD&+qk#0A+*)$hM(O_^GoD;cM8_= zhn;u2yt7w3KlCc_%&>mQZPm9j`?0^Y>nh^(0u`Z*WCEBt>+$waRjBzUoFjG$t&Pfh z-q0B+L>pnHbX>kmbxbBBlgZXH1(n8WICn0W&*7EgeDqzmqm0sK#WBX*5LZ9ks=cqZ zQy1BFb$6#;YR>SjEVm@N>}uKalFX7|zaXyhOAG;r?>O>&t^#|tR4ujOs-1uijt2(Y1*4b^eqeXtKCVC`Cjc9E z2gcMBGO%R11p#661>$63q*OdgIF~HKjfF`#FGTZ|w zZVXUA*Z=*S!FU2N;&vE?y`@*YG#$?r00~+J+%JOI0xUNUXl^jNeT_!%u^hw~!imYi zU~_>n>4B+w1NF@W#%0MbG=Qho6o0c8(p`&azzDE)9q{)A5Q}4{@U7(3KI$xhn!zosaQ$`X58_ zF!0V&Na72|G!J^@0~xD`bHLO-g8?`Udi4`hD3G=gD~OxWw_X3s@cRU*JwcSK0{MrI z=<(K;n2Y!IK-QrrvI{vN)+)?zzO)$#`z_3KCe|nod_rr;-V$-KR0^~Pg6s%vKN8q4 z&Ilk@2Y^-$#VY>-uJ%w`285U)`b+zD4^q!#C2pjw#I1h zOKFG!nGwm^DNTl6MG@big^M6f4q0`_hz4;kR!xp*p&2`EofM9rGayff2myPOfc~g~ zMQ##v5vj@o27VJ6cm`<>VN3duv5+YNjW~qx8t zQ$ChF0(^gx(1iSo?vo`_dof=8fbQ@E$wQJ!bR|8=CB!$;8XDz|Si=bPNL)&ul|G5Z z*dbBWQz=%uDOQL(5L+lBT8X=W*r6F> zFXA}413NcTED~0tFXd*8|GAiqc-DHd6|m?1kXZ;iU&fInxdkg)hOE~yWGHbDtm_JB z?Odu_oF`pIY~nmwNG6J_q((#@-q=ChEe@1Yh<`;}V7gnuy?q59ItA-9PTDIi0ps2V zdoPlFP27_lr8$y<6s2p(HeD+YLT|`L7{f?u9ijtPi1xWjt4Jrr>k1ID4uZ6Fq8zAn zqDYcXh~W7FV{I&bMP$OC+$O#NHlGf}`jdDLXH*v=9{Hg+rR}7JJ)A35U}tS1E{oyV zw^_ijC7|f-rP-t}5iYrt5twxk(pB;$k);Zz{vN40GHE|!)TgoA|3UmB1970Ousnf; zhJ1{j`T$mN5q3toWJNB(zS)AT(mSxp&d5G^j$Df_L@((qX{p_Tt~OE)_S`oyjJzVg zmHtH{`cuRuR+7ghdyK9bb`(wigST5E55EyBYk_z}E7;-D#Cl|mY7uGCiTTjejp*;F zhfK0z8?u1!4nW4hTx21CMCAP%_SzJjn|VOvTLFvz25b2hJ8&5Cb|1o8wZtC3P7IQo zNMo@NLdb>a2>Am5dJK$K__Ea4gK^rjf!AV|rEoI#w$ z*8-#+*bn1iZEIlDM`0b#AdZ8qWLTC*u=}l$4RDa?Csl(tumxQZQe#L?Te;ZO?gcGS+ zS_%8@3H!YW7B&fXY9ILQ8L)TDapDZaZ|Go$|B;ShOrJ2{g;-AlXIN+Cb(G+zRNPxE z6?!e~hAohNBJ!5OpTYl4ggo|RT`nP_cM>x9#w`B9nD^t(a{?nuh20ttZKPqV|KK|t z(RtJc+PV{~cp0&tV4Nbb#CZE)X+Es>Se(`Ka2lrLG}?oG5RUOnxG`+PS>GA)-ks2! z9f+)UB`!hA?J){}*!d-pYz6Kg(~(P`h~2bL`T>n#Ag!&K<3U94ni82DX#MjTRsxxPXi7ZuuI4?-Zz?a;uN(BR(4)Xzr!v_m*U(y{KV zh|B2jdK7PXgc$KXoOaVN6C-j%cEHB&gQbKwE$xC034|qC4tstOZ+eaMr~_^!M+hr1 z9ruOSh%}?ZHmWEb$M_fHTs?r3&6UkMfnm17k(~k@^#cd}Di4g!wsp zK~%~Hs1vMaSS?hB0}tIQ+~IA7m0UP`A1}8Oevs8nbA`WR5c3}uK(@!;L$r-|<#w^P z><%G{SVncGm(pV>IrWx!LOmrJoU$#sIqW2HF*`w?g!ps|Wuzc8w=fQ7BW*i0S=6Q= zCerh+uKd^PFS$vBQ=@)<|CN^cr?j^?(nE-y6*s7rb>k+E0y&WLu0K@urf6@rM>boW z2S)WzkC%S?yoS5~W!qaV%0t8#hWM)G#Ztk-iY5A;$eWW{-?RN>4G>(ssZj^GXU=QZ9WZ=6%A{uP(J=KGZrf8ihdkDgCGr+B!#PjD}AEwS^X z?rSxLf9J0IGpDjhui_YKpX|NWQWr1pERQ?3zvNxa)eRo{yjo*@aYdIpuR7jv%eF={ zRP{%uVfK1Gi=EMtZF<`JVrlHRkx9arxhdy9eR})u%g=&HRdnRCPG>p~ZT=ys#Otv0 zM;kdmzhKMP18>fL?N$UFMD?$2d&iCLV}p|-el=?9!BE4hW*5%QJ5v->_Ph9Wxw$q- zdSd79R}(PX>yl%*b#KLcW}#rOyMCe;~ja$@iL*yaXEdE)kyZSE%!(`=-pQO%ZeFAH$ZPZEpLqNDU0=qOHt<^29_R1gmm;sV{n(}` zl6TA^vg(gkkflFzQ`7GKn415tp-_I_fpR>a1 zg?g8AnOId(o__b+*R*$e-D^fRtT)@!z7BW&avKi}{_J724OU0XYlN`+%cWNeb`>XA zB^VOemSQ2Z$7-z8QkPh#6zc?eDm6nI#b)b&)g)G5tRoFGcqOcbm8_krvF%@WGp$Z5 zI@9-X0~p5U=>_8-otO4Yok_T3{oMYn!%5pos)MQ<$^t6T7+iU#lr8hG>8K0U_clEc z-pDwcla4aSQ#OyR;;lX_f6z|_E7RD9KKfCHKE|EK1?+I3h-&#s#U8~Rd60aTd?)iS zxk&8G4Po1G8@U9ooXulP1yrl0;^=cU$#^oqnUl;FY9!9~cVcrcjExf8)2nG;%8Jay zy>%75zK-G#mNI9X!}x5z6>s1Z#BAaqwT0e@r(e=P=p}R)x+`u%g_2fOh|h#Daie%h zXfN&r?_(3rRX^Z#6xoVQ!VP~mEN3g6NL}E)M&o7?EltI#&Ece}$Emdh{}zbdxRu=% zXAr)02>pt5B3Hu4krRJOTg4LIhTqB05u)JrC*U4Fi&##MqZUw&sR}Zc%piM`Ti}uR z!hKyMQIZSz47SK1y9{q+4zk1M!-G7B?6LF639H9BRDheuGw>cP?6wrJqCzp&0x;gN zF7S*a;Mcap-Oe69f<10pxj1_sAt!I8)ElS$YTO^d48T(s_G1kG^vA7W1bnj&$VO{~ z+n9yRSBDeqJI>1j+zsY~aWRtEia$p%g3~ysT;cg$!>ODE@4O5*1WV<%#>ma2aXOWQ zhw~otv)tgGg0E(&x9p6!PQ|&Nig9eh2(I9M6_2}z96TEa|5$ox=fnFx+5kUt67B%oaNEkkt!Oi3 zGZm-z7->EH%UST*@^F(lj=S+Q+%g)ZmSj6}DD@3_qiRxwFZW2iDSi^)!CSuu>EDr7 z!An|$o8WVDJf)^6stff2=lxzGOE>`vrbar2`|LE_iH}02Kc)Y$b`eeU%?3shJO?UT_iD!}BYmdQ;D!Gd}zb zb}{jXo<{5tCQEtbQpOQk;<4fbx`CN3-87Eo;;5#oDB8dtGYuCXDdsSPi9M!KLJoC` zsiUs2YfU~vwQ941mHuj|k@{$66K2yQu+Ux*Q}{q}fXtg1E~ccd zy3A}Pr-*%Jccq>DMSi?EQr?l@OZ)^YJBPf>Enq^qX4ssE=+{yUF_Rung^Pzp8(!qD ztJbm2aJ#gVZy<*ACBk&_CFdX#G|habDow76!%`ROtZ4>)lNicRB#z2Tc$4^!?n2}X zy`?Owz}$zTDZMyea-%a$iOdJ~7E?-|CMWQXiQbG8*PN*3pHj=|WOE}KLj(zpWov}t zv<=%|iYN1=p;RNTEwxiHlN|_7cuMI>2VNoNGgk>0VL8}L-}tXYNB*XwfICgH!Uq}6 z`!ccS0(l&thE*kmi7Gc_WzOLf<%jtV)LLPba8YVZxe}4W7IG0iNbD$d$Bp}e{H4iL zeo=Z&g_yU}6lbG$F@Bc6H1DInu>UdBg+S&AJ5UwMYsvS*4}J=H9e$3Mze%*9+a~{(>w0OdL(ba=qpL>=OFCm@14Qj|+v=VX200 z&UIxPOwr0a=4G@8nlnxGiP4WRX=PV(+-oYL9!P_fU@f$1SkL!rAIE`T0N zb5eV*lDbXorL-m;V}fPz<*mp*(3vRqt89$ z$S7LzGs$#9q@Ez&Gh7H#Ofp8(h4dn_LGm+yCP%{8`$2kgpXq3`Sr*FOCijTjm6>{j zrVDZ{I!f#;NNKvzcc?iFlHqLKjdyrTfGV_J*u4|AUFZ{WirM zsR%SHkeAwA&`Ee+dB}W$36ai<95swxr}|({lo{Cni2wMB)NZi@Gnx%%Xx2rR%oVE! zHgr=h<^Cgzge$ZU-&y&BEv6TMEB^_ev9+{b=uIA?%Y=ROa$|yWy=kSQhVvjM(^vF+ zWufG2riO#{=6kDyxiRcP)l0!cTFiziPYHX)3DO!a2At0Y+-CI`!Cp$HuE1_(>SL9; zhD7Qt7+cMmKIU+sQ<200MrD2`_cr!bRIr%nQkit z%Hg+hfl?%2BM%{KStXu*CU2?#qF_y9RpYoC=?=A(s+VS(yVLLZ91&HTq(!m-Hc?79 z-&3^ZtW}xDR3=QAN$S{tWJlO3#C)w?()hRLJG9^_lEi5X`RGxI2?o1pOlZ4HrEzytSgtKHDWIsPgsl&BqR=&k_l{q1-k)1KMQuJxqAUn(* zm8G&{nIn84DHE^DMJ|zgES;pz2&2d+L?3cKUq{rFbBPi@QTi^dWSsa!s*d|h?#{lH zWto06Pk29hHs?auvxjMoNKmZU9L(6;Vt;a?Fo6o9P739eHEtBMaf-c=^kk(lRDN7A zQ*ypqx4%vMHEF8MPEQgQ4tXf zs3?LoMG+N5kfwrwfKsK`5PC@O+xyIX&y)TB$uHStcWyiVoO{nbhB>i;(tDBj<@;lx zlBg)3h@F7dl&?J^-jQ!a9yHyKtW(wolMU6e1cOUMjZR3SfHqVrjE#{-$uCLG)K7%8 zh$=oJOjAZ88nQTQmK*6s^0&bCoX}NW)a#^q(pS;xILlCASdZA~3}K`pPrDpDrWdKH zro3oVLms3}cI<7rQLMjVs``&KSNBOj=^uzIa2vyL(GMxQ4EMGL)l-P&xkRgaL`c&{ zOMYz%;;6F_hjT!87Hf+kg(KozeX2A-or2p#PKh=R{>i;43*54Cv zVc%i5HWd&#jJ>h0(ig&H@nxJsZmazzwB)X!77_|^7o7pN)nLRl_96Dw7`qvpcy=DQ zK|GEfwvqZ|970GCmr72=bB?M9u-~x^v6B^u`z=G>(+Z)R9zcv^x3Ct`wwv1TINv@G zwD^^NMfgl>iJc6qyx1^Y+n`N|ZHzvSnEew%3-NLFyf#D%BQAUv@%N8VZthNUopph9 zJ~Z9^wtJzs*j?rN+EwIrMc*)eoLHF@N&L+^&iIltU!EX#jqdZc^CWtjhUaS!8FG|S z$`49dIbk|%{-5Dt!4;VoED8>bERQ{}rfXBQk-`IpT4S<#veHRDAljly;v?#pv8kbK zVZP_Mu{PY_knQ+UJyDnE@(SPP_DHgDN;Cdk!7#p z)mR5Dt?ArHmrXPEJDPao((7AB?^^xWv;!ag`Rews_x^W%VfNF*3a9+?)b{)8nl#Nh zlkkk?e{M&9i#=cb{_m;DrNeCRXZLNqJ?HP-&zhICn%*>&lIQDq?fm8Ji!+PXRKFf{ z1PXM?u{(8Kiz7`N=5@Ah(LeJPR;AXIyU!Q>78+RcMc^|>uJJLsR5@>J+o5P&Z01W3 zev$S4-6mV-{qp!PEq>m)anSmMyWYEWB4PRiqn^u}aeeH{d-WE9bibopAnmgK(5x+Q z>?*hvtDBbeZSEH>0&VuS`LD~fZC`EpqV?_aoc!tM`k(*k`inLFYNLTOren^stVJ!B zG#il}cKj*N@NM_~S@ElPN8zKD7h(j<=Xf?q7+`-}7GJff> zLHMTOijf<=N6%@K`gD9e`-R`1SU<8+?@)(7bN<#k-JJT@$zLyTR*r8d>>f)=D#)m4 zF}%y;{W=UVcfOtaO~`xOdST9a_tha++_&dcH1Wx%jX96CY}8(8zAoouTe)7M-BYu* zZvE{}H=cEUT$fVaIk4Jn>GIdOr(WJLaZl6R-hQXg?27DoV@v7!$G`nybLE+c)T{gI zNkb<$7~kxHDP89_H>9OR`(5kwSHTu>XV&T5np|Z=s+`-Y+3+q8_vzHPvi0}2Q?;|N zEWa@PQm^Z`Z}+=%y~=Gz^6 zCgHh`IS*T=ZXbKOMRwr%)5msg-_~Q>>ziNQY}tAGY}45J_P>nn|8(QWkKRAI{ZqL= zJ1pu0x5pl?+SYITeaBuc`PlGdR`+H{+O}>#v)dQlGFwe*kQOMqzWP+;__+(WZjGqC z>glSTcg)J}+N!GU@>X*)e=)xiIq3eP{8V+QWNuN9s#o02>y8C$9hn_k4el^u-bkU% z{;2!vUk6A3b>ANEUunBH?mcuSzqT@Cz&-6A8#E^Cex-w){g8c{=yFZHdEfCN``aIE zdHD(Np#*=EHLVx4nBMHQ#=9FgY&gZaC?ponx!^gyF#l-Dcz3tq(7B80SaI;&-cui)-Eh9_zuY6u zPjtDHWB9rCt$Y0s?CJ4#(?3&<4#koy?{uHIIqFR9sf|~Ct~#?dy*T5KwC7T$rHWZ{ z&d8K5QeMrBTi)vxMQdDxV1HNa6Q!mwTTbd!f4M1?j;iQ+rJ8HLz_oBh&t&d4qYH z(kR@dyzRB>{EJ2R1zTAQQr}1!;#g|!XuBt|I;EZS5pkX8Tv>YQbG4I0`}N)8%i^1Q zA8E09Z^9=@*B!&<%-AAtzGqBS(5D1u)vfY2Qj!`y-K%~7o~_TD*H&%4`o^VmSFhgq zvtY#KrTIA}d(@oFSi4ZCWi9QQetUPbWNM;xi#4zNwW$A{3FVg1KgO{MO%sROmKm>@ z4%^y0L$-E?g5a#$^y<~_L*b8vucZCLAhksMK}ohXcDAvlDX&Im_!maM){X`Tcv=Vg zD&w+8bUEMavsOdx<*qMp6kl3-<=+BJ{u>u(Uw*FWy~xVc-&$YnxVfb#dvfwnN4`}z zZdP;ao+|EHD3*8fd!#>YP3)rOP4gAoy9v2TGwf@m4#9g}H|t*Y&I%pD?Nt8gRJD_| z-t@HXUweD=Gx9ODb;OVT!s(%ru9v)LdXuJ z#p#84;c>}Jn>kz6N`X(b;P4=r4KwZpm0OWR65iG7w>mVGc*Hdee> z^}KgYcw2N(tT=KdmSC(&Fr*eI959a;MnzwZwL!dRS7f(ux%WSRPV6uFQ`66e&EhuQ zE3Y>!FdVjI8up>!^tjNs_KJpETK(R{>l~{7FVNq=$~B_gdvo4-{cMw)W9#a_?5xzwRBuOu=bhVHs+&8apYojqjTenZok? zSZa80pn3RC^kB401h=h58VgnOTuZWYzx0D~r17wNe4Wf?n{_yKW?c}hD%4I`vR9xTJ`DB zqoFI2;}MH`Tz5%hj7i41hA#}&asat60db}N0V01}a7UR@>lIt2JJmJX4tcKhd*o*D z1?h8V^VEK6dy^E)Sc6TuA>AK*uKJ_WKTGzNm)5-OE^@W^?TYReEEG_@dNC%992lUwS9*1%6V$A6|72 z{U2nB3*tPjgIX@Ok(NY$3yqSe+Up!1M}PZK^DCyNrs-ny;BMDo*9-0+U3soOu1CGU zhOFAl;{T)!xkQ<5nQggjde?YT`CazPx8=rSJMDArUz}XntG%Mn*WS|B>PL}VmX3Y8 z8`x3(5wXL^5FaeYDUfA|)jf;-=T)#OZ)mTI8^m4VwV`%~bM_aln)$ZP>S$qIZXBhL z3AOYeMQOx;>xQ|8`b>c-p%&3@>W5lm>2bpp!?W^#h7n3b#cCKR@0120@B6Trj0j>! zag`WCR-G(7fn9jqlCR|=rZgP3SpXS#9>mgA zmV?UkO0H697-@Lla6#xUydc&|l{mw&P@f`B7N;PysdN2KY_8Zwh!|#skLw1}Qsprm zvkj1kSuWfXl!;lZLdD46u&OUxRBe!PYOEquq`D%Sm^xEU3O7@pP%NSAT5HQNv$v>q?8CHTsUZr5-EZh+ zf4pW?U`2xh@vho6uvmLKu`Fth;_Od!V!}J&*MisV>Bi;$)!NbMW6Dr-N}bCzR*h*t z%As%v<)S@Yw^ZDsZI8a5oKo9J{yueD`SH*;Ykz%!Bi9r1t z%IsBQR7W-axylmyT|Vm^t&ItEaDGsy2N#*H%THJaRqj@-*`b@Rv|iH3RX>@mbxYFT zGF+&ftqd?73G}cx3%;&CVjn0y;6G!!Y`U*%P{vYU+tBxcuAa4djon`w7lbQ>XO+6x zZL99ivad*%Z$6s4M{8CVY8I~RZf)y+!TD$g%`u*D~ro^|v|-BWYQnNaqjajRuRaILIL9qU#) zC+n|-K1)1M_Ho*K{@=78oc$_yrq8He={w%E*NvIB6}C_H?Q($^^}!v_1W|R<`bD{x z_FmmXso65u)VZqwbIHsLi#Isz%oO6yS7!vO7DBMTN-_q|7T=NLYDf0 zEiIIrtk?ET{m}4{cSmHJ^k;%8)TZ*D97A2c_k(7u@=qj%v-jQIATQ9XlimypMO_-5 zc6V@PHTFd=1bpIIS9wmP?sDuv!o{+WQyclpYDTp@SN@J#F4t6^YTc^jtqS$w(xkr>(1LNM|DlAdp^T_st(MF5=JHdL*S#|NRL#8T8<~b8 zIq%g-&x(}1`>&mG{G0eeQ41j!gvUI;~nB zR@k7;BUP90?(KFwe7w%5uh9Os{T%vQ8*V=5>mS{fFt6e4lE>Vi+SdDADRZhf+fsvT z+>0~Z9(zevi(l(jnLNS=uE9Bj%!RiWW~Wx4kZY5V1Q!HGtIm{?+S9&=Q^#5UF8bEi zKI6b8)$m%#w0mEYBJ_5E0d@mTaJ<-yoB>987ANB9GdAH}DmT@A&7_w7Z2Y5s-Qh0gKN>@AFY zV&8-Zn@);P1|s5QM_F`atc&S|$jIPu!xck`}7CWWSl*-gOC4|33sjjs9#bKAmSoQXVt^e=0d)> zQPy#mZniK?`$_r5Ap1AgG#7?8dbP#>QhLcb;`4GZbrvqF*m=3j^`@1H!Mo~%l45&2 zy|7WFVYAdq%jeQCZCS+OXq^zk2`aP>Ah#&-=k@vG0RYE&Q!m+ z={mA<&#Xg{YXiLoZHD-!Bd_(Yo)FA>dw|oa4(6K8D29FwVpG+WVz1csdP8> zE^2muyYR)Bho0Aa$u^hvmNGA}{6dp$gpUFuF0t>izSAJDXW!8aMosE?%h4iw zk8fw)dv~{;A9Z2wo$Eo5^{M1@4d!JJ$?Mo;VS~lW=+Ha0x2pdrUsYaJx!83i_OBu( zE^qLDQn3TmF$bmmVBhKsp80{V+&EcjoL^g4@RO1@A!BaK(Nb!A|GMhE*W5=BZu#(w z(ThLa^-u7PCc9ftZU0!GDZ?HedZp);^hR#;mBXi_mk!;jxih~s!MDU&+VW(_d)uwb z?wlZ4Tk6-{uNU2O>tNxzPA%`a|DBDkcNU%Kc*MKQzwf4NU6(}@w>^34frSkpik_@%jiSBn?WS|S(zUEp|ol7 zuIjasoyLIusPhL)BPCz>&9q0J9lR0sglyndu;8HO<(={ zzf0}U+OG@~oAf{X^cNHFcD-&MUedSV^PB%v?ymcy=!v3Y^-ANNz0!Jo)AUQ@n2IBJ z?yZ^?dO3Ku@^Z!D(3S*qUgzeYWtxO%s?JuWhaQXF6ZU(4^1c*1Vj17S)S#1XNG#2p z>-#ZA+?vP9lf_4idNQaJdRH6bt6yOiL4Gtf8ir{#~%T_4&# zD52@|{=oThN1nLi^{3l*IM$g@I8w95H0hgjzkRlUZ{f=8t4scgnjFiWqVc5E%=}5h zhYnT#IG9)6v1+^fSD~|`+`3D;p^uYB8}j7#au7SSTfF(c`{gB;6vKH-n&lslaNSxv zsr{Cx8bA45yCoHCcWz%>wpqC}F0fQT8e1oSk!9)Jyoa^PE>*vA{M7CIv|#t7K^d14 zMp^9kk%S4Mq5zHN6UnsR*WX7AP~ zPu;0`5Yg$b^1hTCExvAhwc!hL-_j$r` z)*RVus!JH;oM+CIu4<*&cbXF$7xo7hM>-4Ll*X1^_+!^&&7=L)Uf2~VjP;6^M03Rl zl})BRWk*!djPixhePt8slx+Kult&wP+aokR_sh;-cm93yWO<8_J2uzQH|<=@_ga;u zkJqHq;a5l9%=9g@A4soD8RvM|_KUsFnq%k|dAV**g|GIuHp#gnCBt#Wa8^^Jzs0)h zx%#f~hrU=~l(@`VX#d=FLij8?Bm8M}l{Q{{M1Lx}J@$e)(YzU&rHS4-*j#%?`8E1g z>5!_+*_}qMnDAlyr$h!_v;Dz+;FvbY2cLjlXbD} zj?zg;Qd>nojwR#F#dz(-*f7;9H8%}6osz1e8>3focdSkBWILr5-hHF|VBU}8oD*BL z99FaTc+)?g_%rF8(LGc>;~DB3n=1E=^>Sps9PCjNxCzzo$+zrDmMvcjPg!?oPtN`T z1=|-?O{{*?l@axsw;;2wE6z52VqRp?wG{tu-@W14@W4A8c3L_bZ>j^LXT(Xy7sWP_ zk3%Lk75NC~ zm2=n2-|@9{&kg^aUC?iA-_z+^y}L^~lss9{+*7K(Xj~(i9Vp58E4&aYA01Y9326?&2k5*z%yGz|q0%*7gKn3$}<{i>{6~ zj;&$E<@_3*U3PX0D-wNBCgj@eb8e%dfp z>89-uNfEP(YDk8&hH8D5_PspL_@U?zFAg?TMfo{-G0w(JP==X)S2E-#THoOLz$Nu7 z@vYc`pe=Guv>V?N?}^M0?us2SD)x8GorM3zUKf5c{$Z|?yX$AQCD_@y6?-;%B;t$o zi3CxsdX8y=<(8pN+aK-_-ViO&jv8Jv|1RV7tTq|vd>)Mb5Pmj#3-|pm(Dp|bYYWV4 z9aAlPg~s83LIt=PW}oC%8$=(7&etQx*X(cFUop+p-wh1)_=2~E15!Wz-dJuV6#6=J zAv`_0E_zqrVHxA-U<~T3gRrd0@K#-Ec5AG4fRCnb<>enX*ne6nP^2o_5jH!m-(!CGXPS5Z+Wqo3|VCgy~wY z+C6eP;0qkmzBN5&u}jv-=}58or1_2#3>)gM)_xaip;R~yItG|-io4}3%V=AQX{-7~ z@IV;nMAV6~w)!Mxhk2Z2^|>oUb$8XT6svH+_f6e^K&8CEmT3H5`#>8b{ii%)Ibk2< zuvh}}Nhw1*fK$(JC`HCEg)bu)V$aIwjBN}9V?DfcU55gBf-e85-yiuSvP7Mw;YP&3 z&z{Y}4EaaP9>c?tzx|V<^W-6h1K0x%T3aWk+6Ia@Vy}xom6`|$Z21r z-WQo0nH}vOy*D~6_D?J))++K*_-*Z7!$(Smd_XFPZ97|B5MCYrL_TKQY;LTc4(yMv z2V5=-Z-r7q*Ys(MMV=RZJD3*z5LFaf;3UdfWb;+wHpM4|-*Jbdstr*Os$I1XT7mGK z;Tt7Ix(SFl#Ek~K{E059Z6hCq?u!}ZvC0cV|8POj8%vOyDqh@*-O3VCHt0KpdC0|` ztxqvDlW*c=;B4g`-F! znNkGY`XrAx=XtzG?VTTs-pA4y`t~vPQ#~$P2zB^Nc&!TNV#lSDh|>f(F#!& zphUw>uflBj6hEoM#Gz>OySh`mDE=w`D$Nx-Y9qA8h~tgY+9I3gpzxEpU$|fW6tyOf z>fef=VvjiocfGHXEW##j5cc6eH#Ar5@;}JoxrGd~4amK@iqml`kZ<;aI#0cTc;uTn z_xOOYM)U|B^-r`f^y@fZi5v2TYhr(CykwTv;_TyY-7HQNO0_kCldF-9$lKoLV+ImzvKpLoJB3he?xG_zc(@_ zuj08XoO&FCJhX=~0#8nEMJ0xb$nNCLgS>T5!R#JIHp&3x69&*$K)%O5WVlE;2l_BF zP5!{M|Dt~*@(_pPDJ!7JDiF7@!gk20=!r3};H+K)%;OG5+>7&`4be6YnIPvdKC4~x z&O#q@5C-AYXf5u_V@3G8SZgO_yD)cycSOc;#+cQln`7jgz#{9eXW?c`-euSWXILG; z1@CLT0Vro7|5U;GRMxCc!CzN_71qNn21TS|jm$Y^)y+&~@v!D+2F7(mZ*n%g6Vip; z#xCgHjgzaE`q{)VtL8X&R*Yv@-yybF9I=ajX{4>ZKx9X+&SQVL|XdPF7ZSATsVjPLB~8D!g~_GJ5BG3i5ba z|1%Z+D#$+#gMwJwvjli*0m?7|G6Lp%11DI+$kpkH&*~6gKLuO}pw!05dNiV^TFj{k znJ1~xEPlYA)xKF>n$?OGMC4PEb?L=Dn&~*(l>o~202i$6+ZsKj;1tIV%)bHhd63Kw z+&M5Z@2tFw`6gl|tT^rfE?5(tm0nG_7w$S{n1yj;IGM0-<7-01j9U~d$! zf!0#-UI`#22&|s1q6Zc5ug2&S-YLVg%`m?Jpqo^Gu9|gd(}Cq&z>l?D(!npR-KzrM zg}_52%;+}WH{vNH?m9$Zr@mKKnbm-637Mw1Ff-!2q@H6~nKrK;O1$^=Jk~6tZDWkh zO0OES|Eke@7J6x2Pv5Mfk_R~C;FLY92)jX@wX91<3!AW=(^wbJt=7Z*3;J1O0YC2YR44BLWKePh}CxP?IaN@rT7|BE* z#aLrD`tu?Ct_@ax0=Sa#+Oj?yxD{r41}iv<{%>ODqmUbr1bW+v)8ftW*HxUW8ir>K zczyshkq;8qulGTwAfb60v^5^>QJ)hz+-EQCNp@W2f;KS^~S$PRLjRTRl_a6HC z0;75L&Y-6g$UQgXHqC*MzXi}yzad`{cZ`VLg2(k|}+`e53YWf%1c|rX}Z3u1# zoq}Ape#leqiu}1HI7OBwRtdw!DZ(kOvG%^^(LJIfJt!h)9;@tuth|?y4}VE>X_t{N z+6$cVBQztc2)RI)qfn=4Gw^QG58!6$B;+Um3yMw>x*`u?0`8M+gO$3q9MHfvWCeaF z6bkR+^zts8`ag}k0p8c@)XlgPuNSb3TVcg1;! zuE@r<;fBy4G9~sSNA@aCtf8W&_>9;?>?w+<5xZCOX$sENeFNHTEao8VdkO9^eHZn7 zS87$rJlF{9=Of)|*Uw6R1nE}h98z{E~nr;znfk%+L@)R`O z4vg&7TZ7v!BV+X?@f!5f^T^&Pg%#2aRFebgk_r3dFRc3qyA zgk^LRqyGa-ZE}6DEpei+9JpACz2=udQ;#7l;}wjx8!N0qro=KleGE@u0FF=N=Qn7A zO7IG~ARW1|3(>O^+BN|GI|v%g!rclYpm!4dodo!e1WmcXYgd6oX3A=y{GG@yQL&qS z1(wPId?#XlqX6d#uuw!u@n0}P1QN0s@~8_|)C_!<2fC?-oJ+v^Scy6job?l|o1>7* z9?Yi**bpFT6QTEV@lG=M#sg{F19Q9|tqWiWT>)1#g?yo0X$Wpe!LwQD--0`gi!dH7 z79ZqH44g}8%v+EfK}s}&{^Sbw)$5lsNRftkvLm?8gqfU&WpWI(NXc~y@~{eh764Lq zV4V7v70essH61c44P!fj9}}Kx0a$pTLrMVGyO7^ba6<*;YfJRg6r(i(b+fi{7?4W9 zTI!Gy)EBbT2i?#FQ2h~*v|?p;=rrEsoeUhXs<|IBum(KAyd2)u+yHtm3$|bhXn#Cx ztc$R)`vU7Kq8*?wiOwXbB%aGy*wCe(zV@>)h&}vKcoCavJ;_?9G zF&86)SA|8}7NeyB@|h z=qG{^+?YG>N3R9mcz1a%pp<}BQUlUjNe9Kaf$=nqBx1g--A>!dj=w}uND$DJuo}Kg z3y$}{Gw+PpQtP!ZYuJY{5^LMn;?;_lyz^bcyUgSg(5nf5M=>|niI>r*1TDu~-Ff#s zPWEDkBKl<2c3Mun3tq-J%5pkBUc_}hmW()Nwt z|4--&XooZkK#Y_TK)<}3pa1Fj+h5-&S5F9q@DArC;XmR-#QTH<;lw%sgrSK4B=pKv z5-w3tFh>jHm9XK;tmr|)D=XZa@fyVpi62$~AQp+IFrFgi@>#x5?9*=|M-jSqtW?KL z`M!#=V|b4%BWyTZ;()Mm;BN)+HrCHg0vt9I5aC4FaXl_zMZ~9sp}8Iktna{T2dp+pexmI3;WMs`wIoO>q#OE{0zT&|%$O;A z7x2Dnj7s^Q#Oaf0@C1hf)=PsFE$rUh+D z*{m2ry5#%<^?lN}B!}>M^0tmO(>Ekf(ytfrbX;zb7s2s6a|WCfJudzx z57^MZ0V^j~$zinK={H$1k2p>E(1t4`K1fHL0eu=XX33S4FUSSNxrP-`4zXWinNZ_; zNLQ2+9;_q^Iv{TBXz539)bi|))WcbkLtyfuEqf)T2zBC`D<>_JT6m`v`IJ0BIp@RE z$RfjENZ7;(q!}Ia;jh1XVKmO4a+A`{gO-8%mZTC&N^&`QB~Ja6=7c|CM5>~O zB(5kYt)M~bBHkPo*8^-7hg$%j2GE-stD(H)I^rHDB@HD5@kL6|AYDmotTIY{q1IE_ z|7iho8rPwNQmA(b=QwpyGLd`T_>5YO`iAf(f5-Wf?I@L4S0v8KVQ>~@0_T#5Q7MyH z4}&nJ+@Z9Na}aBukcP<>Y();HL?MS!4il?!t;Y4RE(&Q^MK5;z6|dMz9;S@2patb4 zsfJqHhxdf~(K!lfh4ZD1e zj!g)2EY??{B#dFT0lZ7svu*%uldJMUIy>=7%}!gEv_rb#D2xYCH_m%p?k1boibQKvH=MOYAeezb|pUp^bEUpF;cy!s67Ez%m-7{@AMN7zt8 z$!JZvM;nOTL1*i?>NUdBAEk>yxN6z~H*;{<1FxDGJ3(kYH z;VUsiI*j6nHfx3Y*u1A5^cIU4IK6MJkyeN5R-j-j1I_{aH+b{=(y1WKpQ zFw{$a%6-}Z9I*~hat3y+m^{qY8-Z2ITT*3Q3X#ewo8t14{K$A`d=0d~DBH+Ge2zRs z%u~107S`|%@k&~c>vbJE%ZqnXvA$3}lsGcwn*r~{ZEjk<@#h(>Wi_R^7r=OF9r`21 zkOsL@3+$!@j9&wvss<}gN7RO~0P5fx_=c6BMm|q_kkxy9;1uG7v}3}%R}NjW?* z+U=~V%vfR&<6J{5wG14|XftoHqF$t>>Bq{5eR43V*n(9OW;XoC`!*w(KRs)Hlb;#a zwS(>*^_Z^2Sk#{6Y|0hFoNFcB6Pnci#C%-hQ_AApFnSWPs%DrqZCuJ@C;sC2QOqAl z^zp?1S#Y#z-SCh7(5QqxDanLaVu3VAx~JXAerWIV$6P-{N>W-XC5W|^gQ^HG+7yg{ zP##f7I5Af<*23Cdq+?1TN_J8X`JVO2!}V>sGRltlciggPg(%AE5N2V1mONs_{b&T8;68Sb4mb7A(o(zZbnY>sLul z&zMII+ORqncali6gaEZ8Ei3v-lme7gI(p_eG48@QeP{N~9U&W9le!|986ioEB%Uc@ zhzHsLY!v|Y6=PPk9_THRmbeyb1$wk@%tk~TL^T0RQc(i_v!V|Ne$z%E{^M2JXn)Y! zr0val#yv#du4cm1j3v-+A|%-(?KsL7>gOtO755Za%gu>-(@G-_$c^-9;yxTLSIRQV zF77?iV~pF#wDlN0kM|na9K;7@D0Na5phP=~8k%^czeYckR)!VOO2Zu4Cs$4>O}mDA zg4%^MA)WI689!#p8)MjCEn3rypxuxJSj06p`{$aH(GRJb9<>)R3}PhixUhGwl6+xC zpWN}VKuXX8BIF29LWNc52`Ac)QV0W(Ly4P>3D`db0VIh-^#vffEkWT-sFr3ckaGoFnmtB zHeyBO0!D^NH>7*&aB54&Pty^}jC-bx3DV1^hg6DQ=x@a>66$S2o3yHfBe;W?j#gY9 zEnLErHfr1-CC70`k#d!O5BGU8@fj(Munc0(@n`_;4_ZsCO2{45xYmi(V~<*mo;xWR z2R?xT(wL03Q^wly8n+GkDeIxpj-x*x1};f&v9f&hGXu7H%N|cVILPEoUSyC#c zW5g^xX~Pd~UasAPCnS7Ii9o6_fjdY=!CV-JX6?Qd%!Afm z5aV)xo7kllN9&7F@S~?Bj2O2fNo%wp0{AguG&4q}45GylkBxCQX7tU~QcvmiP^YC% z7*k$S?$UpAV};ZXaqE;cPP>H?k=m4&3@bNM21H>+H^59&F%rk-6V#h^_3NUnO~Pj) z`lQWAtAk&(7iq0<&a^|Rr8r95f}!+_`}D*EJzwen+F zTr<@$(MMlKlbrTixp z;*`jq7`>yV!N^7pXs`^FT>Jl_hKhM;&9!o;ofRi(xzaKv9IEjoAxnKo$k5JXR5|`d zdUv5$(lKpDR=cEEX25G)Ptx+Gc4qBT@&&yVwk6IIFdFZ4rcF(o!H3a`01>vQv`fNo z`e7WG)IgoUm?-&)T*%jW#F*4V*bp<68U|24XPJRl!iI8#5`?=dY0@#} zD0!OJD4(LgTZ@&~V104fO(;^U+VM)=Mq4$Eeu_a&lzrq+N=913)aZE+3MHi=h zQniXcX(Lqw9%bl*R7^ckg;~V8jut!ZNygn6wv2r!&HXO=F7!2Ndr%WmH&Tv}j|lBLte6x;J5gS zaN+C-J3HW<45>p3Cm+V`E$aDHw4~)tx}+^ckA{2yw4cfI)Qz-9DIaPuay%+P`;(Dp zwj|F|(pu^@lnkiQ-)B{3dRUZf+$*9qVC38ntRcA;y>Z7T6?PYCo^pk>&b=4X4dZ%o zP0!Oa@#@fCtjL8v8R=o)lzh~&oB=6@HZ=VP(gxqJ#ru?8MvOw5qiki&mR=QMtYHpy zpw+lkb>LmQD0ETk^8gJ zg5DN)VCg&3@1;FVd{QrwZdviP0??y3%Gr`9=qJ%CZ2%9RT*Igfsg;no)pHVUaLOp^ zDB3Et6KUM@!1eK0mePl*;hJ!QtuiBIxAshFG|-$5pQvGO#%g7{7$>4$zPwG~Gq6~rT= zv_Cl;dXWm&orYF%Pm-}R%2V3rl`lN&?wIb~!dNGu79EVgx3MO6CQ;2H;T3hr22|H2-{SL}h8MeI} zE20l<#ODcE0VB55jB%fjyFaw6i4)q={G9eIX_+UaxF0}WM^A(H3%QYYFfC~6KWZNG z4gGIY2cz_aA!#~p4or#~UA$O8j$PbJra<|Y7TIO?vFeL)DOgx4fj|I>krB3BD zv>5ml;Y0b&=oLAJmJXv-)CSzCq0PcQ5yF!DfLs;vOc_djL70$+wJ_t{)EFP&N zY}g}XrnCvk-5iTM3Dg8}%|?vIW4{*6h#D_0If!|}g0Q0+XLW>?VSIAfpdmv@gI;R{VCx<{0252qH z3hD~lXXFvuX7R`halx-R9Em?_TgC|}Yvc9_Ah`qn%_K*O3ZCA>i zAWk`QZt*jwWv~bxu&-0mTNPmGKrf^gWZPm?88c1AJh+l1^hoaKY5ppl%FM%A(;B?e zTjKs0b4i$U!<-Bk?1HAi@NGP6!u)uqHy<B4T?}|}FYFrNUW@nW!P_xIuAdVA20oWD9&?`@m}MQ#&Sv4Zab0!}?w0k)aInir>>t1uI06VU(2z{;4} zLklL1J=L^&oI3#*>T~Aj(5i^y+%PGO?=(U$#1b`19dJN>lL@%;%yy zK`yL_vYc>g1KNwnPRQMirw}?icqa>O8smriI=HVF&rxre17aEI*Mr&80!suHHUPX_ zSoZFq)rrxv(_*4(imjH%h;zA$sCn3w0ld(64v)9LlJ z&&YQeP-Yy4vL?Hpo@x7rkQ-yKpC^3}3A^yMfNpI)&ARYO7Dg?{n9QalR%!qVo}i{p z&KcEWtaR`srLl^2Fas(NFpuJM##L-MS>F=t3W5$;kFp$X-B>?0K_X-lX_KC1Gt8Qv zBym9tj-CQ-O3H_8fEufCl7=Xa$nVVJVhl>h`@}*Mz$Adv=R8Nx2&#m>iC;p5Qk=Pf z9Nz^fFz!);p1E&E>yciI09aC&(JG){!+SAsO z@w^xB&?cl!Oij$#4>bw*hCG-9Pm0hQVWg2dmC<(cIlq$X>4v+lajK#Yp#8-dIc?au zy-o|6l9~1}r3Ym=t#;aA3HVK~kruTK=q^gt{HwF)QbFKctf4x(QPhq`F%wY%bS@vfY% z*NV@mi%{R>h&VsCA5{xiSM$gke7axj_iIzqLVWGTIS|vE-gW@gi=U7(ch+d_=C@zr; zjk`^s$^VFZ4JX1U!^;9yvBtt|>5{fm-K2gWovFISBg&`7sI(dx+WFdf)IeLTH`0b` z`RdQo56W+bp12q17U}|g6dtRkYn`Po!UXL{ZEW;&eTDcQa?lUrF2NtewV}q^HpwM@ zXxwCIZ~RrL5`Wbep$cz6`!(81NELt5zYxn~f5hg8e?(QpLxzo_4Y^IP2(wX}&#sM8 z3)H8yT)l~wuO}jp@$HEI;TgqQ6`KaP~*SEn5 z>N->q>5{lL^@r3^iMiIN4ZHNGqkRL*JSDD~-pr6sor?-?WxCSefx=QeW#KrK_+Y6sbORXTtUNH@_?jRAzW)M(#CiN%UrnZCH`L zA^o0|C5}eMO)=HkYQ0gj8#{Di-qf7+8QjbxA7JXGsT@lNwD z^W6#bjtm&DbrHtloWHy zcZnZ4ORV1-R>xlV4X!CH|GX@{>{5Bd>c8FJg`)aae)yzd_MF+NDAK* zxe=YEKBrfq%FAoAu5?fuDc=}>SH_D!>vsgNbjLW@y4v!jd4}nIWq`Cx+Zi_azjL>* z3)EEAd|TTP_tH9oZ$&ri2W7L#Z2ipsuj3KtyN+kG}=r zJ@tgzO3xD0mBHramR{DuR;NWVMGV`;BGnMR9(={W+Yw*R08k>(w zDnkt~7*Cr{o1K<>EoElSRBHTBx!>@w^uAcAA3-Ijve?J5-Z3fmcy|>t;(6^MA(SiXv|m z59#ByKx|;FMO2H#BFWJe(d?Kvc2QlbO+eklUBbtx#@t2fBfWv!;ueXIN;i;CzYz0Z zs(!D&qn*(oHC!~!v6yU|Y||}Yo9xOe;e2dac$oi9&#$i1+GDj#>TbCn^mYz7!r#Zn z3WMb4M#*yA8n$IRezo6Yf53Lza@JI(EXO@7t97^9FP0V^7TFO#hWq?xMvT#aqO}Mf z^?|LNBc2ogkt(G@@+tXk=~Y=p4cAYl#^M$AuKI%3Q)sU2H&3v3wkO-4wd5P;$WLi= zBWH0NN38Bj?WCIFHFDkWu8?PUU})q6b+b52>21Da?c(^yvDLZBx!Ez;zRo(`yhE8Q zXNl)SELK_ zYp5jgKlLxQOdn>`C!TG*vuD@&7)VyE4w&qyf&+ZZa@!|Qg z1;Q-DaMNGbJjXlEWeLL)+ak{TBbx-)-R%1A) zB}Uo>4!aN6wyqvgabHE-%CQB?dAVJ`eRsm$o<)7jJT;2Hg}T}> z&Neo&f9k;oy&Eh~X`J|-ZL;YbDW=YioCuBzO!Q9(cmmVIo1%lXzQVnzf8J8jl!3;% zN*}{J@=IbXeUvs&9S1I|j#b2#sxNADkiU9PoF)pwLCGMWP^X8EL_RSLOdZg8RI`d4 zlhYG>ujbji|GQCp?X4SE?|f1IpywU+JJW!~qp4>bbW3fS__fVtTq~{B{Lvnf>!DY} zM0mzK;D3zU`p)LlxCeQ9sj#JBCMz3&i(fOAUkV zSgXBFQa9fy7sxvs%#5e4|GYci^+W7YQ*Pq3 z4MJ%}srwx(l&0#Z!6N@3!Rp9LEkQbK$TRgaH#0Xg84V-FC$*yJw#Zk}Ik9HiIbn-9 zNXo)p&eO!nuwm2niCRBxrDnvv90uV}eIsgdt&&;`YfuMyg|ID}<4X=ct^AQ2=+d$0 zh8A0u!*>rIYjvQ*k*QbCl^+T(HT6!)%qq++%1uZgVQZ)kcdx5{rDnUgNAz=fqj|lp zr{lP7o8<%Lrub8AOgJmFGT1EgZfv%YB|oefaO3g?u~Ns~v&ch^s(sXU>c!YE+Dvhv zw9oLC__1t62K5;6i2g~Wi#yl%snVkPk$x`?7}~N)^uoEk-|ah||L4&4AN^C!|D?U% zs8#br%~t0=k$A7xr*=-!_#%JBZvRf{ru~=X{SAIgHY6N1-4TX{>pXYsj@3O8h((>s zFXm~sz1Dk8K6#S;^XR(M2seKbYur#F$!hBRYLc|&|d^hFv(yP#UglE?{fkH9Hw z?{+^AnlW%vlb>n^{hj{fsZIM1KT^I!c__PC^Z9N1x0&Dcy|nvz7*d*$k)+k)qY z;r-O&hR@`l&iX!~nekdE$$f9-?TQ7pJAyOh?bf=){R#hbd}I7r=p1>|-^8Ef-w?hY zOA{Y6d}SVBdB^;iVW8eHydcsilpSd&z99Y@ecAhb`0=DxJuE}}-&>JdaDDr4L%w_D zw=d4#@m+L2-ehi@7drgi=F{9^wiO=J?I$kYxSC$RPg|5cC^wY1uHoycD=fdL29I75 zD(PJ@*7KXz*QTa)PM1<8TeA4S&^zwZ+LNwv{dBWa!PdHG>a-!sPk$I933Tsvg<=QnaSQ^I77- zUcnJP9{8lmH<6m#L#}qdF|^oR-7YxKG$?0H+gIBkZ{#=q>W!ApE^S{iyf(%6QEZqw zr@^3{k22fYt?EJVU#|aZkJPpC8)M7GBGY8MKjAU^6Q&PhlOwBr`QC=H|74%9``zoF z`rIrqW?_jV3{di41}PVc?6H?p(!pQkRrVz=CT{ITPMwl-;EIVa4BykGJ3rNGID z3T8x}&bG9UHouhJC-pWe!`Q-;ODeAQyA`Z?MLOi%m9WLJ-T8D%I5Ep8``#$;UH*x8 zY4nJCR9_;WuzsIalX+_)Cy`J~Y{Hjla=j(r;-~Y*>v3p%9qK|xi5?}4mt5-?evuT~pdm@L+M-{BNIQZ66fgdctr2deW zmh=BuIt#EYviJQ@z1?(ogJ5B|*r*t5cdf0fu8G~E zL%*um#izJ*v8`NHlpGX2wQNfBsC$N+1$^$7XN7xH4vfor;<=?oaP!%%t$h>;t=z}w zC%^rjo|nHMKdvfP_B(D>M@N%S9@X+vgw?IgsmNIR`?IB)M6H|Tb|z?K@K_gDHoqpT zDzr*j%U4gP$Eu>d`g;~Re^8#qr*pwI6Y3vVo~iyLjny70A5f);Up}=l@n2o{M*q5= z#r>|uZppaRtueOIgE1?rzj3PcXH2H+sH@uE_|DM zvhpFh9!>fFvr60i+mL`hvtowoK##Fz<@rzRW?anuF}6xVw+P%nXx6C7ZPi{rGLva` z{+v(VpNXTNVeem%X*Tt|KZl3wQteS#yNCqdVnX@1b@3;G861V4h#$ zU*FR>M4xK9&-1CWw5%1;io++6NyOvD!$x>L8Q5#8L5PNddP?|K+odtI>1U?b1fA7d$ zqseIbu*LU?GXdK|<1_=)CY`75JboSfAu=Pvi2L7eU*7y=*ce!4T9dEJUi|J;d8wYP z-DP+wyXHUL_o=GC#?`e_o?w1bdAGrb{bt@;8_11x?x5^Ih08w6qNLZzSEfOxE9?mR zow*&ik`9*7kbHzfB)#rH+2*nfx}+xOTMuZ~*Ei4ik+%G2)Ggh;{m;ekE@z%8C1fq5 z55-&#S`=0mI?^qKZKze%cp1i+@*61Hs;bp()p#l&tA;9l#0P95^Eby%N4n{OeH%YU zd{VXnG)nB!J|YpjjcLx3*a$R$dFq%(DG8j75bctd)m^FKL=S^zv|18R2VDqS>lRjZ z=e6pY?~5xRN2kXB^t3GWY~kC{YmYo;Wv$6FlGl8a zm7#cW?F?pj;cw}o=8c$w%;uV+wfx_xzjzUu#_YycQwjVD6aYRT5^kZSoXT(fuRalL z=RGCvchl9Ofx(B|oXpE|&!qN#H}M0Lx;*1!vBT~nGOF8oU+~)!yfb912cc=E*g>vh zifm?Mh-sVkkYhWIu)oPqlwMpXNfB)l9V4TO52%!TO$V_%*hJQYeaIQvZTwYy5|&EL z1pRRnu^R6t@)Ac_ChOPoYjpqm4+`H9sB`M92udMu7#O2t3tjT_mGvZHF?R!fZ zaYD1l)z9ZsP=1i7e=8rkt5lsNz0C*NW|_kDF7`A#2|9}@{5o2-4=_U4Nj?a!s_9omyP?jBQ8-_2Fy>s^QTjAHleZA(L7@@z| zkM2394wMQD}8nX0f%{}O^tcFh%zn3K`GBvk!M^z!}T#w2 z*cQt4+V0+Zp9Pv75?|?0e6cOEaZB0L{Eoj0@-qt4%G)&@wzNi%rE7J2J$m|$4;bQ~ z<8!8@{c5bk2nMisevQMQ+PXP=Wq_^2fu1 zK6Td|4W!&@nqN*}bZBaLQqW;ftAV_qHU^GZhK*S$gbe@d;%4P`72+kx9U&VUDPE;X88GO)E@Jr z!~9CEDa9v?;|oWpuX(=pz4W)THbK9Z5$p89zar8?o(3EYTC3TO=zl#3}-xutx$#OA8MF$PyR+PNU|N3j!w~22&-|o#>UsvW>PMp=;4;m5o zEUH<6&UdZ*8~J(mg7J34jhYSB#~UUa-`SS%tRz<5M?FC^TQf-gpL{kr)OK~OwEnip z%u9`7wkiA{JR5xVHY(<-0*H~gr&JGbNbULMHRYw>u+L$l$f0h2UaO-P1+jeVk~w*Y ze#Cxi_R8tw#$1oONwi7k;qxvmBI;c9yU=|eO4Ut~jhG{+AiRR%># zqT^kNck_1M{nYusH-dLd^~JZpUCe6w{dKA_H92pT{uxO*&GyR*wT15s4GZY#_E2oG zPu3r;n^tWucU0F}pI|#lk=)HW#%+Vs9Cc5HyQl^0Wi2-@G;}fMnu=_NY{+0@(9<$lEv)dj5W=Q8Z0#dN1EDw zH|TDAuL;Uf^{X*tAIQ3s**on?`ix)YHBn5EYJvZxNH)A>_@nSlzaHv;Sec=&Zbzke zF;m>Orj@l8doTH{ZggAeeZ`|t+aP-;N=BPa!S$#%yZ)iR)L7<7!%vH!$!nF%)G^vc za)me?pX?|BZB|J&Ug&K+;@dX%gm0sIs@v%x%K2?$kL=^$`ei3)Jl94WWD`{Zw)%jq73cR9TFq6?l_gc6e3F3L+Zi9-`PSfd`%1x@Y>g zcE(Jq+^qE88C|};{Ti6nsrZ}yqWY8f>yW0=uCd0b*#WqVM%>ZrRC}TPYFR|tzh!&t z%#LEQyLyOjg{zb24Ud<)f2A4xSx1buO5d$^boHo){kDtDC=^DGSN@~Johs!4@(Ysg z*kdvf6;@6E{lYNDdq8ZqpH#ihIoMz2@=AX;t1{%k}ZsvL$PXG_w~+Kbj_X4srKM$);P1+a>H0t z*I4IfU4iaG&NG|(PZ^<$m3NmEh$oR-rFY1H+F?bLtp>k`(Vskf%j>nNzEw`s^tC^( zW(@dw>F1ws<1)=fw`^zR3qa7wCumfJKI&~~q~}C=8{X`oO-E})CC$qg)idVDv<__- ziF9*ZdO6E=M^w}0!Qu_*u!b9K)wow!D9gd|0~` zHNow3LUf^v%$V`J;cMf_`VRUr*01bRh*Vcm zRWc+$Bflm6Pj*-Om>NpVgq=V!?d~{Y>t~O$&){6?5BC4W{vx%x))t|=;WN%zrgQN; z;oaZmu?Tlm)-9;~yM)erp0hviS&6;2qwyFsSTs}H)4j;c-)DmNDzB@qvD#{x74u@U z?fw>j!`lX(p}kdVTWw#$p2Ukp)5J02nGoTACw(hwK?RUP<#$VnPF=DuX8PDWvC+&5 z`nV_-BP|cn53R3uwldfGsmnTN)_Iv^h;5%~d!utjM&b3s3&joPckA03b#w-~S(&H% z;u`CA&*QO&o6{=wY()XlAFHBYS~ARu#)+nS({Br7@5w6Ba-tt~P~28x7kf*aNxVh9 zDQDarJWQH#!|8pDhvO~6tcy7YPh|Gn$KZ^3v^+&^lJC~!I-S<`lDy%OqlNio!^)cH z70DHMYVX$FFgV#f`Pt-Z`4?q?wu?(Ury^agX0XCTo=on>>zRqP$iBne!MfR^vDMjE zIo@zAc*fePog@c&3yElf=mMoCn}PE1P_~M{$*cn>ruD3e2(qWy?c4}TEz6W2kbPA; zbeA=)Bs;NMN4iC7>{!>Va%;`2+LjGHP06<1Tq|n4v_bJ%lcGDKOVKV;zf(FtL zp590fVY}g0aDQpZJR*Cd!x&3E!%s1LAi6!7>5aP)?%a54IcON}B{r}<_*FzlZUf53 zU$Lvm;cPr{7JP#r@r%(A;yNCL;>p9zBXAWy#$}Teum|W7Uc*w9C)jb55a)DsmUKpAnAtc%`XU@%z*4z?DVpnp3b1$REdGbx zK+VQ`bNi^jvEL34BA+beUZHK67~P@d?0fPo7f3%7uVxA;XYL>VFqs0QA|`JzM#P$s3xAIe(CN>+)#V22$_a;E*FqLVdD zn&~J353X`Yj%={GoxG_%f~vtU+sA?~-a&q$I2YH@vnYxTVV-c!s7HJet&%!h&dEaf zHS{=pjLgk$*S)G$YwjCM#j(T-Res%Y)g!Er)rI>Py(e#r%+eXPN1T4z+h8e{Y;p+h zP3@ougD>|3d_R_svFJEghG}%qECcae$9yzG}lBYK4OCpC|| zBu?jPg_zyy=u6_XR=w2du86dHk#`I|T>9&eJB8HmQJjNp^ELX6TyNQBae{K#~!RJxBpO&f^^^e*WOW;50rKT7|RB-sB*L+!_?4}3>%p`%1uWVBMl z$T`+_k}mXkDo}h4z>MK&w5=;qFZ-kKAro2Oxvs2Tq0*YVO4?zbj*sdU_9awLL#ix` zb|F5B#_?|4X5yM-H>_p;@Gp%@kocIjuV@iFOm@*$ zMKzKyfq7WO>hNy3j>qlOl=Ji>oNv_cRE60G@GH<0<+X;}@)Eu?Ug>yFtQTcE+$4SZ ztBjg;CR>rdOdRo;y-HSdKl%Pdw5Z5}l!*-r=dwmp*@VetzCzAEg&2yPD6?g-Y!p(m zo3U*1N%I;>1YSU>Y{Q^0`zbv}iWv4GisN#rew>*+#(I+@xvkV~rhwM-qw#2B6*!R` zB}R+>vHqExtHW~T0!}< zpNLg_5jTn4Pn0q3(OA%i98PVaX>uI#82m6(*wuJGAC7bOThfV^)8sfVia3U%@hA9c zP@tWP-@p$5!7&p%itU4}6!`Xnry(ey^U3^w*cQ|q&j;7(RAQ&BKR)geQrT(fVTMzyb%r>mu<1daP%_l z3mjzxwRwS-o(4?VJILa&{B0m_#(+9_4QNXXoU$)`lR)JPyt^Gps9g9w2i@=1*aU1L z^mZX=v~C41rw8y_*TC;nsPPiWKno~m1_Png8?@ISL7zW>dgoct%KQSP+iu9@J%Dy9 zpl-$kTKWv=|R7^09qF+UuuCqvI9Za7rw;>NUhPp{M7@IRR;7B4a}TSgIotkxWIQR zfYVYyAB6gWcxc}ZK3d=f1S+cz_@ZK<pw7>-v6IL6x7%S&ddYO zzY%yNfuIeBqXjZb4J`>2lTa}tFt}Ryxj&3S4X>P*DiR zMc_{bH2{I&cY}{mk4D4KUEzDR|6{@gB3t-IFX+89w97#&61Wm9T;~Fy!d&3UYPc2x z5vBMaeeSLjUOnV>lJNpA1)(lk4c}Y&zqur6aWT+qfn^oQWPvZ1Ku-nAO{n!2swo8SS77A@-AsXfu7v%! zP$eWVheExgpg1pF#s8zjNzmwLpXl)V;vy3bhtOU4}qG3jYW*MmSceq7dq{1^pC( zkX68#33KiLRAq%R*1-Q0xItll2=iZ{^#nBnp_X5mhXVU8aG`>#pum#~KtzxB4F+tpr*- z57q`FyuE#gb!;v434y+OXVCNg4C~8OxNimZkq+1?SP6?@&F+ca1a37CxLphU-3eCL zPS{N7gWwZU0UG1IpcfCJf4;E3WWo`GX2;)HD)eg(?7*LZ&T%j(iSL2gdz1HsUGGC! zS3B_M_-(*eV?eY$gq^w?z7s)ieH@kxPRXxfHCvAP;hp&)SS?$FXGV8m^X9-Bss>%` z7I5B4pb37T9}4>0tMOla3b?QQ!pCBBP#UliH?ix;7hS~q;v=vW6a&wpwb%|cjDH9_ zg#>;Ze;Uuk7V-PhbWm+K1Lv@U|BT5iSrb1OzXNVqFL5s{8a>8_z*~1$z8Ac!>;;dKJRU>quyASw|B@R-=&%xII!x9? z@-Eh%+lMa&Z>kv7p8rflkxRI>+$ubeAHh^IqwxV`G@@K{ld<%QQ{ZUB#z+v^Y3XRvxdke>QN8=Dw+iT ze;>gI@Cx4nJbJo;+IuIsTMDtIcyqiM_L>KXM`Q)*#O<@KV&kwndm3|$m`{D?lChpd zclrieLY1IT$W;RM!1i!@EnCESu=ki4vNt)G43+Me=7Qe&FN&kGnQoj0t-&;SG`fYY zLy2^$-H-9+qR4b0^+K^1cog22IEQS+MPe1DHhC$aP{6vz(s9v59OZTCC8@%jGhu0W)DgusHh{%S=9to6X(@>h33*CmV(BuzO=1v)_Ca zb-+#JzvKzhlah%FnKH+D#}9|no{t^lrbG7WIVDQg#KmW>_a#!Yvh}W9*}90!&GN+Yf*F2XG#Q=Y!d%Ra*T6_ zeep*op8qIS(G>PVwv&5p9l($0Oy;57L2&(ApnT@|yKb@~(D@8wTZ`EghIO=IQF%p#*W}}<_(sfd)Y9PSO|Rou zif-vnNPCK$WKzjyu9d@^iQy%V94o`Wqn3fUQxZjp-xK}plkhvDsq}jGH1n@qW2un& zSS;*N&!)_pPd$`<;=G*my^eHP7yn;yzuL4fLEnG97NAFwrjS zzt%3MK)RW|13ijAE0u{0$jkBovH^MXW9XgiY3mzqt>c|!vAwHuK6e1i^tf+-^KFbY zDR`RZmltYBcFv2MX06FxnAP{b&xw<_8h`ev?Qbg#OlUnZetP)yFp0-kd}Vz?*{sHy zRaC2`@>quJf8b-2S*ZZ^47=@7TYuE<}L{`OP$DfnJn zXSSpL0yT*Ht+3mFu^~P^>H42)d`~b^1$uXjztuK4dMUQIu;IsF&n}+LxHUViXX$RH z)-@@1cbm~I=*ZbF=_|5;{ED79bHkmy|Zf74jOKnm70B?zHZUIfq@o*?~e!F4{ zS{;j{`Mk!Ch@w;Qj2l1L3Y+d86@{Seu(&qI$m@&jv-2(Te zu5&!T>(+?6f(T5nh9uLe`q_p`#6c9|m@Gx*E#FD@7DZzOm+U~+K5VX|kzK-zQLfU5 zHew1_p25qma#pv#${dfn2>+%Tf$e2YD;MRxOs5~NePsWURL<(V>H39sj%*oK8*cF! ztiDcHHYC;-S9{kcm<>#U^q$sP)7ojB+gDK@5kUO3bkL_+rkTgsTeC^{U{RiIKak&} z$Um?H7-J7~)Y31&p-#hZBvtHN)hN0G{pH+?y;b@TQ{ZCJymF_5n#KMdUMadz(Y)YS zhRbuGmrmcORRuC3s!4t=q8>!f@GEm!Ec=5B>JzIQ>-_aY>>TqzVsvtGxu~X8@8rn@ zPLDEGtTzI(GnZRT*2G&-&LoW|L|b79sMfb zXDie!cDmz#KJZcOf+oT0S7o_**7VQM{(YMFDYw+h?U!!#UK{>Cw#x6MbA$LQ-`4b^ zGP|zGG~Hf@?URjFUDvH}3Ri?kui)-Xp3PvnZn)W)3e*eRknWAaCJD}rf#&2m1%u8hFScF zM)hs_&bfR2sqDW$AAMW=l6Om~nL&>B{ADJaO=1>H zw=>(Ya>XGsw&90mr#QybIWj(25%gE|7T0+F*1Xa$DQ_Fzt^eSj-Ody*eFJ1bOvvNl zkv@Lf+x%4fP168(EzakkDfx3L$4$8R3ik-9={ zkY-W|#4@%4TM2|nBDlo|FhSG+W*(}PwGrHFX(d5b?lcu*?hIB|iD zz`Tiv{4lI5>|M9v%lIg3y5$g;pqS@%D5#zPQ}=0_1w^dPsoq{RIaiwdJg2l^cvTO* z&9O!DSo0p_dTri)y_`LkI{7GY(MfK<{hH;TX_0Zi$p<4}<_~hKhdCW%MCG*fU^cw3&4OXpi-RSnsd4~FL zDuH=p8K?hUn^DuOx~@W9rLL)|t1I z1pA5Wz?Z?B&>k|L3Z=f0f#hDI8V|(RV%zyCd~5UsnYk#a>+8=CXGbvCx$F2I=}zq) zm&qz(O#lL zTqpagNKkE4eNetv7-d@|9A~JCaJ`SQDX0(}ytUiap)2Tf>ign{}63e8qst4*p zYKMF))gK+Q_c8U?&ul!}_{4C~+}d`5R-oh91M-z9UXmo$Ns}Zh$xP8L@;woc$3x`$ z8wx`SC<&#YugC>FMsGkos5L}=Ps2N+54_pk2Jf+az8Km*5AlqS5N&J87eTzP2^vNa z_(A#sa|u(4XR97)C#b5#zStsqgl)Vn5F>-D<_o)) zn}U9WKieR_2QC74*kB?A?*;B{tDrh%9**NWd=~DE&&R=k6tW9h@V5C0iw3W%XBZFp z(rL(x_yN)MQuGmW9+A8kT7ah#2ISAb;%f1E(Cb^^{MHUX2&3swoFOK_Z0U*a;HR-J zFwO^f8=FcL@TVXLT!KC3l&C$td*8=1xRtyU^^&`Zy?_|aJl=#S@(Cz~59ODWEfG}K zLcDJ}WLC0~FL>#d!|WWwF5pK}T7DV=KY08O7mp>NgIEFFEvNa9@TUF|n~fg;2fA>W z%W)7}dq*t8o^uZ9wHJSoxPgA*E4jmv7tmrSa0-v(f1?@vLa60wz)j$oHXR?%{eg-Q z1DeW#qdPtwU(NSJ8=>m86E__0#(k)PThEUn#({I#H;%-Qfrni$l!%A(Dts3>!8x#P z=qWw|J%)<0F5n(`7;Oh<<7%ukeg%P>DOrO(N4L3Bs7;N=+OQ$ScckT0@p{Nox5Xzw zL~Jn-k$rJ9ejaLeCi1uOVQ{Z8d?gjiPvJg8jLQ|h<;&0(EC_#qYROoYBCA?52}mHq4JoA(mhWi7or|2ek<>Ui-}d}5?uTK5S#gi<#TKC6?{44k7eT@ ziPtC#t)sSK|Df$$J+=$ZD}==%rS?+YxY>?VBu;I1JVobZ2OMX)VPt!b z#R|wam;n!Dx)75gisp_Eq8O5371UTNipCt<2p>^0Hig}VSgD@(q(z|MtYO-VrbA8C zRPry;0Mvpzf!-5)uvbw3y&3Bx0ryIKAO58HJC|$wLc+eCyG*>{2>b`=*TnZ%{BNn}Sh5>{vr zh-khc4&rr=I&2oTh-2x&NJRRP7uaO*%|48~!rXi!<*Mg?%aVo(RcorG=Uz2 zD1H%MOQw)Z*cnh`S4Qk77sB&qj>ts+L%bozGhXZ_?l)y54|8(%A~@I2fXrnKnvEH4 zF8oW8i`1XkXWxz`L5%Pj>Bc>Ud+jm5Q*=vofo_4)$T0pqGa7Bj0cmG zxfuK_^?`kawZoh9E)b*G0(Vmn&PkHOi@6l)IG)LEA};aYXfd&a8NfSx0ib=seaRfz@KbZpl21EcE$}aka&tlVPKVBgUAy1&?>?w2)?@8GCEvOGa z9_xi~fEem?`(*~}$F$@DytDDAz#Opi$sU{*s)|ZRXX)H(t(t z!LRZMP+PQ+=t(}p1K27?K~xcQxlFDlca{mm(cn z4Eg}~h!~;|ew7`^Hiu`T7tsfSBRTdFn~NRdBJm8q4bhxWLme?0?+fqO4b(0&5w)k~ z=nT0Qo(df7ZW7?xGKH_fdy`*@lc@-!G9c{ zG(EY&{9ABd9l|eztWHP#FwUZRSR1?)JW6k&)$Dsz4}R?5xJB$*1l$Rc!Y^a{a?de8 z(MW5`R%{IV&60dCVmo=4zs*&#-jI_|hJ5*0 z@Mvd1gyH}mhrLH};NCtL86c}sfVUw}WB1Sqej0d^rt^1EQ*1mw4fgFD!Bw`7YsH6v zducRw7>^_r_-m91YvSMdWnk-lp?3KxN&yz5HQow*R3|`|u_?r#dqPg}1-NR)frI*M zXlokxh66ua;x;)P&xbgr2R8~ip(x}ByOM*D|9XjChl=a|aP~`xBlv6>4J9#_sK+}H zIq(EHixc=2*d->z6Js%20{M^v*iF`OwVV&?hc2VjD3Figk3x&Z;2Il;&4x_W3h;G3 z1NoIF*mUT@SZp8o^p1voMpKB7`$8_U8R+o@K;BhQFZlr3yVsBhJI(jPwgGX_8hgX9 z0e94+*k0Hpgut$$Ki&yC>5QAU6l>Vz@>LOe*}Eh3*c$q z0@~|~?Z*DWR$(dNFq{mdunjy}hrwqQ%1Erno zkU>ktE&)ey9`+_Hz`r#g_yz_33~PY1X$3pA3;a5MH17ke9tD3~q4hA>*(JjsR)4?t4Pp-jFdCGQYo| z=Q(iyJc3N=LC6Bf0u!*0U&2quzF;jt8$l0eGZ1o}9xy8+u<_6XE3BZ?;oOVS3HVco z=I|S!^%2mQWSC*&uvySrIE?fdc&>cIPQmOOQAI-w4MVq`!O&L2O%n;2gaop zT!DQsvj%{hGJ-dj2G}isf%k=nd?DQ1G3X+<4~wPdiY@^OcNSj^dJP5mZ4g-c!I&LU z^d@FB`<)GBuQ9dEO)dm>!NZ9UxDjtkbR-8->i z6kS6t(Gc_=_Gx9{FMS_o+e}!`Sa5TmiYu{6a7T3KJVJVA9c`ww zKqaM;{*Ug*RI|PL57-C%E4&}yCYqBfYAUsl@WyBJ?f86j2d(2`P+uT8YhmphhzF5v zxf!;Zyji`(^Si6RlB7am#X{|Sml*dBuDr$} zZAWb39z)h*pSfIrsBxSj({hK7=I;_d;(L;hvW*H#StGkB{zERsMsXyaY=2|>$F|%0 z#rA~ph77ZTR8y&vd{GxFSlmluVz`EDw)UFk0d~L1?gLfZP?y@gKT)Oi6{@l+g&RsP z*FCmRCOT?+`-KL_`+f9?avQ8I6;DSO?EQ@!Yx-C2ujy+nv&C>H$w+w%)kjsB)>F4# zyM=4cZnEvOwKSYD-mUjC)u7c>J8qWchsmRg_*&`9YQhQ?%;KiHeD~uX2Ip;>GcsrXx`k?NXe8@Z#!S<3#}#U#d=T}T z9wkW)u(VpzEv4(Ns17WiZo8R$VZ)`)56H|XwSQ2eZeB!LdsVlYokzy|2T3Wfntgdo zzW4q*J-c~%m`zDu&yHNH5a^{nLhqfr~dMx2w9D@z}`trtz6w9fM zJGB`vYgV#db*IDcwh8X~u=~?a8zW-m=K9mQ#h*1FPGznwJ!(oP;+#7N4vA33^od>) z*hv$@B-TwS^37eEixoeq>uuXe8nw?oLwtMsF7WQ=d`bKt?PHu;T~{`u>{0z9({jfv ziNCg^(v`R>&m<2{6Cpm#959TpZC2i`I<;o1z7^Mj`bZ7M7b{5r3C%`#+uieJJflr0 z{qKeUx!PlUE-ilbf_JwRRA0c1wH7MqN$Mrqhw;%00$vWrjsp}CZ^=Do@EX$g2_^m*Y zg_{;XqkT#H)~&WjlCCcpvbZAc{%ilYk29*vrZT;>69NuJ^ob6S3=e+oxmh&_OEtVN zMR|VN?Q-La<$8pD)np_euJJ$3$nXcvGvh}#|2t+`NTeqxKkHasu|7wc zCQfhsnO_@6HT86jc-3TbRHr}}7p+)D+Zzv5Z76XozF*R;`d`yPEKohzbCCZr|6H%5 z+U|s>C9ZZ``J3|m>J<%rA=mX@TIL+*K1%md8YpS1KI`)*dR^1PpdrM~Uq|kvQ|i-x zkNX#`k&FoM+1k6!^CrFhhdHMxZiut67~At2x56<$O?mAq=Q1apP-tdsO3YEeB4sZ+ zr@mL!*UEqD^!hvIBi7Tv%?C&qX?eG{o=aT$8`oms&l&{yUi%@7q46Wz5@Pc!cVDXr8L7 zWflAd!|IaA+@^W&$`hEiPMd>QMBNHmIYAof0nBQwMpqoVAucf{*X6SD zdHRbxxmPbgs{Wy{b#s~%B934}I{WE7S3u2MopK$%-*~5FL~c$_eeqXIy5hHAYIxVs zIPZRnqx>vOpy`1TGXdDLR>l^-+ZSq{_|K4x2 zcb3O~j~DJqF7KpU>Ch@ie*4^oMX&Yg1nG9oR~zuvL1iN_MX+p+}HBLwv#Soa?yOQIdKSYD!L?}F0UgGvT}&+&r}Z# zDsK`V8SQq|(j~jc^Pvwvyk3=;Z@Mer>DIx!qgOAFe>_HcZuXeubW1eS@}g{SzA67` zB~+ctXSo}^r+fBtijy6JH%1?{hVgOCH-$D{tZ&focaUUHb(vFyORoB^cpN{|G1b<> z*2A9ZaHY%WUF=G(1$hu+oIjL{+wPtO5HUrDmzi|yeOvD$mS`>xx0EzbKRltFK$AN<>NtP z4%r%v)s0I12J=#OulR`iI2i6lDwdEf*~hjCHb1+Xsb`AW59|>(2I93BB+n$tk~fk} zBE?Z)P@APFOq&$Crm1^WnrpoMd~VyfD_>sz-2S)5ViP~q4sdC7{pLE`J<_uS=p9uN zapt!bYyPB_46Dy!mdK~Nv~l0;lBqf(2_o+E@3>jaRois)al;$*{MR?-XiK&`kPY*QxL{>(hjbl4o}=#5uM^HlHEGn9`-m8b(f+y277g302{Xc|8W z{esLuJl=qRAa;V#=Rm&JKF)TUo330CkQ0;K#KXUW7*&$?q3sj$dC!bq)#*eRmrS1= z?`3X*x{s<4Dv@fA{4)8@(WUWnWnty(dUrZbI?B1LN0?iUx`MjTQubKeANyG*meaGD z%oF+norszeev;+#5_vz#8N$H!vA3~qwXLGfXgX0%Z2$raDtvfQ9>RQ~3Sb4(h`-hJ z4A>ttqseE;<@c|yOe=l7^g+`%V{?a^mdT^NmIci4U+>k#wM45|O_A>s^+kiNKkHp; zzSdmO`!V(60?k#|F0KJui=;iamtJJ6vKc`^>IM@9mG%E}GlA-Fq-Kk=A){v|yI{Ex zFH3P8r@OMlf!Xay8t~EhEiw_Won4aQHLtzPAv?fhJ`LAIL6 z0nMc{+d}(5$9;Mf6U};a8-YZ;M)-M?6tg_{@n2i`g0K@04NRT(J2=@{^xW&V4M)pJ$pNJ>~H!pkr`Q;3S`KZuhh& zul|(zf$L1m(V!Ja)GN9-Bdo-j@1Qgw#&PS^boc6alEuWu(h;T+85LPK^gN5 z{)==K_motLSBY1sze?kT&8Z$Z2uMqz#sZ5dBaRF`;h!E?iU_#ISz zwR|e{Ogr$#<=w-K2gQVSv23LKbAQjEm;PJ5-n;m!-${&k12fHf%di>L-2Q9)WWESw z(-V1)x~UG=Tvt35-^7n{X^v4K(0|W%-Y%yHv(-?enM|0dQqe;3WU)xpmVA#*L~Ysb z%oxWy#!f$CmtxVl0odD1*l6mbGR-y9XOHg!k1U0bPOm)vbM{wL+SMOpOZJ*VMAc3g zeE#@5`@4Agx!hOgi?`w20G?6mqzlOx$eC$j zpJ0o(`GVflE2cL(&l7~298Yx?trR(lw3HLs5o$K>u|{?dJ(zjK4dKqSTUaj`n|ej0 zTPNR%{=wc~)qA;nHEZ*3e(jj%_q|=w7X1@qvQFvKBjB!Ik>^>bSBe{=0T8cl!xlPP z*xy=6b7#{M^9I{jVE1lHjw@!UN2ot5no0H&hq*(JSvI}(DDWQ)(;va}6#s>16B;rf zRQ39iFNofR86pE_t}QY#!EArDk2}DAVJ>ld2tUOh*9hNp{*~SxwVU{#wbA+aziv#O z`R!Xlmxd--Gi|QdKL0|$O`aW{Sb3CaH-3qKhw8X*tkq!$2E$?6YaRvkQ7T>pJxWz+ zR9^BwqE*;2mUJ|+cd}PHy0Z1$WgwuhV1f7)tOp*6w`6xBSj)7)Zz!jGE)5ig9QDpt9<$vq z9sI*1z4+_cT$c)wWjXF8f1=(EKMHcX21yHfs=PrKDQQPe zU;wSg{T?881T&`XTes{>5<+3(}-{?+vaE z3UJS)t{YYr@6B!UGd+KM$)uV=jeAVlRyQ__{HhFdyXkw@f1MxWK1g$3lEdF(-rBm` z##)wITAA;f9On5}ocYOjrdCRQ<)h^*WK$(SC|`0M)TG?vPIB{@`Sei7QpX;83i}L& zLl$roeu>(JpCK+$+ljMSEO#7oGlSJ_y`lqh{kpoWB(+9u>8pI#Uz>|YmSxl)ZD;}( zXH)DMe3Y!8^E9tUKjib#qr0w7Hk|y$hXErq3^Ki4E!oD6#`~re+a%VV7$*8Ixh?4{ z)`?KYU9$}@vM>!I0OO4O?vr2K?HcM0AwZi(@YqGuB+wQ@_Q(hF+7PvxQ7Q+cB2pGrNlt$p zyV<%a7+Zd#a7a;p;b%o!;qZd@^VNdsr9R(v(`J{VT(Q5#d>&IRs&8uevr~Qrj@m!dd;)AY-!n%vY4_aCASKX=T9o^UwYm5 zgWkqcVBhH+;c`YgqMAj`ioEJKp2%kSBOCm=>y`TJ_n+ z4(O2=qzvhi6d`p(6=P9;ByN_zHP?&3>R*^esO;Pm=h8FPmQoex#@N#MhOya>ky3^h zADH9+(AU@7x%@zBzv45+t;?L=WkIju5bw*Ilu_1&wn%4FSM7*m=NiY`*6%E*qzlr1 zM0Fn+1N5QVyXs@rr`q)pcIE5(W}`XI9?Tcc2$OJrV1&3#Jd6{F=aHG-YsBMJ;34ow zrrO<@AtgBXMV^Wp>soJFEd;bZp`zexfquSsJTI5mFaN$`o%d#NiP{?x#M;te`CsK9 z?CR`fe`xD$yKKo+ZpiDUS<)axV22{JyITKJpRa$W#~5!IZzBKS#O!O15dJnR5Nn)| zDE<<}IlGAG%tc}dnbLfro;k+2tbJ?Nk&oEEaF#p2w7;%25vv;eft{zp^?^ga9=>0^ zvVT-ybZDh^39Y6U!ltIngO%2nfbz&PRf({CB)=(l1)i%RhFFMbWi4|RGTj}Gwq`G* zJx-78GOwZD;@^lGHxkw&a(YQvYu-hE;UVf+?!mr;H*v1DqrSjgsl0FN;`-V(&^BK- zjlZ;Jp}N6){;&K4d}+QJ{xbo8=(4`TTrK8FzsWlki{-ZRgQc~yOevMdO1s3?h#!BB zxVPOrY-HdJKz(zC@wZtM5z|!U5e^8iBWu4Kr!xm3vv2_?xyB+t-A(jQk<$IoD$8PAJQ-d0we#UvZ^E^*94n)NSSiX|i>T?JN61Yc1B-O%u_l z!}uTe3``K-G#ZG#jibh9%g1IvZ=QC@b|R*Iw9|f3U*K!%De$cFI6bxe?`xN&Ew&Bz zW%i|(g-V_{M)=OizzKuq=br`u&S%W8g=ftV#d(GY*}reh%kp{S`_O4ESNY8Gqw{&|VQ~>o z5-blU`u*MszRyEH>-&Vpkf&djuF57Q33ZHvc*{L=DfVm3!Fi<$VS!Lx=p;_YIi{<~ zoK!>pAs^@Yj^GqjYn(#ML)@BuFC@J65A1nqBFq)OL#+Ln8IN;EikORYD`ny=^NhAx zPmq>d{E<;ooWweAg0}0i$px#YmOFAiwmV8(iEIM=^{Qwz&Yj4k48@M47PzyeunZKrkF%{8k*jNs?8+2jmid`5 z4rk3|aXR*h{)*j#7o>a2Xt|9P5Qih`ZR&$Huewf4)@$pp>u+M0$vem+d}6gA9Ty|lwi~(pcTx5B zptux!PM#4yF{>k!pNkoGgtlod491xp%0VJMtz`<{@~UzvHyhDl9CZy`IkR;AVZQo4uoDtM5=AX#U zv;imAf!;NQa?pMvvaKnow~=EyfyEz@qq`=I5pEbe^v!yai;jGI3K){3(55$N0w{+W=t|V88waN$b|hN zEEchw2>Gg+=00N+c=fY=YUNmy=X8P6i?cun{cxwIJM{k%qjan?AFtZpi} zaEs7D3?iP8Z9X!_AanSZum;(u-q?Yrm>Y~TV>iw>yTl)Gt}X|>_$sn>pWy^zGR}R+ z0KVSHA0{EkQ)u20nq$*h6QLN{t+mJoy>1RbE>MMr-HMENXK1${g-^{{*eCHKo*QA_ zFdktaTNC883XsLDC42*Jy)Qh4RS?XFh6^XV6U1A{j{YuuDjbCDNXRz6f<0GFg#`0U zqZ}N8UTn}9p9}vXt9SuiI37C*y5WTATG-OPfM^u5pBcz39z>SyhWQQlslASUTFa5) z{SsN+nc&E|=0)RmoE}cV8UGK({m5v)1?<0$y@9_Oy&)5I@y;=@=ev;&z5}h*7Ed(C z{<1Bwd#_;TdyqqaY_>&Rf$t$VGS(|^Vy|DaI2`YI+my_|v7?dQf(&r|7Uak}n>UU9 zI3YS18TKXMnZJ6hS!6lCRRpo>dyoWPBQO=sT^c9Q=IdHmx-0JRG02@TD3$WH=JC|?v_ z0mo(F>}wt*;D3-gp6PB6&ASM6Tn1gZL%0f@eFQ7H2-(IGp;Y)6v}lg!2O}3>h`hfF zTV5Y@XWyH}$b^3ZijNQ?fcu}Yd*A}{_I#8tlF}F7Z-Pf=Av67zFb0zPx>;&`h5g}Aak6(6sCge&?i%df zx7fdX6gYt=36EkOxZn-Y>T{g7-GV#kAfL_Z11*qYeg(SRZR7eU^^>5T)Sffv`}LI1-j-H(=no z?6bgJ2q&ChM=tyrcDbE^wXTh4UdBF(cCg+v1RwTceuz{4Wf*Tdtl4YAPr&R?=6kUB zGIVA-Y|CzBq*s7bKZb7V0oZBLKLHeF!0uVV{10{@q#=9!6853&1*fktkKs&vZM=U5 zfVFg z90sra3n|zI4U9cT`2SPv#-0USO@anq2RomKYt`|FYuE$v5Kw31XB*7-^-4^Z1N*I^ zwK~GL*kJC4F6ji!^u`7y2Pj-zefP7Ym-D(Xfm%zzqFxFLIJR0#Q))c4@2(IAm4PdcY-J=jRIu2;r zAIuLgiT%XRL9Q!+sk7L%-4oPdXUO(=s|sFY_p{S@2B&2)_YRPd8od?C-^_ zY~T}|=EaP$)3UO@L=5ytHOMV%UZmsd8O)_2umb%B+svN3tle-De9y`od4RGib`Yh& zYO^jwb=<)k9;`7EgaixF0o%ZJ>{>VkoWZIdhr#zE=-C<2q=Ofd;Rgz+EAklQ)B0C| z7C8+qY65fJ;E{%Vam9c$;=$!fz~V#jb0o0G4!rdtX(_lX8}Nrf!9ws7Yf|_@d3H7< z3_^HN43N4)S9L$-oRdR#^deE_jw*XIbImF2<@4 zxKqK8W%wiuW2Jx(*rzxP^JT}c*0__^Qfh#j>~N=JlxwhynV1K4kQ9}r5Fo#`CF zDXkfM$zKMwxihW}#$!kI61y10j*vpXp>``w3(8ppvh2S}M zq<#wg#exd#m&TeD$>1gfkQM<`?7o{1>_35J=HG;gw5hKUyb@ACl+{^kR^+10IcF0A7j_jG1gAsIKrWUXj11i}eQLI2x z12C}LXcb`2iTCQ@Q4zS0!m|~a(|t&f7hlP+0)+4}Xu`hL9Gjib$ZhNtM{UGP9PGmC z0;C0)3Hyzuz}tC*JKz;Sa*FWzEpQ+^l!rUA0U_&}!~hcZo@FQTSj^}V zMvDT53V^?wpidES$4V_0;MxOjVeiYkpp1sUWx(1L*V!$w020g(SxUDNGqYxZwUhNNUcM%h(Y zflO7!TS@^3`#lmaYD4zx%K@$mL8A;%ScWV-1cp<=1MF;?R>^^G+?xb?5`PA4-#zfX z9nVHUg2=Dj5ov)&33uzH?xMcIYoLb;fPZ#)F2q}?nW;xv<%pbv^26|tDN_lstBHVw zy}|E*FSy!Gf~`sf>|SUH#CJgf*6pbZ+$(q&XU}fb*Dxo_Q7qo10#_bjhQ0gv{ww&V zCa4K%WamkC`A)?wIrFM`Itp{O0^1hwHR}(RfX1vHMGnmacd&an?La+z773WS(=r1y zpr+7pM-^PFfp2#BqkgCXzVqNJtMRZh4?ADq$7hs&au(|*6@zEUm&9>x%!A#94a|?7 zx9fsi`4)0xait8hcQGnpU^H?%{oq*OqzKTGg12xlJ!j%S0`ojyDOc=f8177(4ZdUt z$wrVD53~>UHG4Ye<2iQUa{KQ34F$bu;!I_jMc4uVwMfTZcg(7w!7ciql zK+jIQ<-j5?U_>uI3*v9qZgK-2_DW_aM0V$-y>jDD_F1MbX6I4%|74eDC!~PZhkXo- zF?(Xh0vOn_m0c`pk!h3I$J~xD_Pl04bH0~zW4$SAck(j3k5hM3i?EUtt2jmB84K{q zPV(%v$j&Dvy z(3lmV0ejuES{k{SwuLpQSTBtbv!ay+Tt`Z!Vm_=+My}%B#0BMy>r7f>>T6<`qgZio z0{ESEwOBijRk6w|XB3C4A|!x)J`G4E^)LNf+M+_dnZ2`F-HJ12=V|^$Zerh2TJ0o^ z$+__DXI1KI~_Q})XC zgR8Tk39iDQy9_*D!V*DbViFL{adneOhWSu?gqZo{k z3M-fj?2-DEEp~^^2fX>vQ00}dky{dQCo9`AO34oE?4RciI30yF1&#b<}a> zoB-xhfqU4!+6la-VQk7QXTvIb{Gu+Vr^&HcU5-3J48;Lz`U<2UJIWFo_ChYl-Q)~b z8Dx)UdLZmZABpiv8PbPc dV9qCQ1$KWbEj+36O#^wTc67d#F2z`DX&#;~yzp2{@ zi-MbaH61&S%g2Gh^sW;feo_eYb&*Xx#B4|TC zlrWwhu(0<#H8w2`dzd=_0nb&b7>}O5w7+!%E<304~ z3V|K=V`e2uYB#O`w8|0Kah}x?IXeAb@+R$71n5KE$WF`bk6R4+D8Mtkk2WN%$=Erb z8iyT#S>-PYPf37-9gbD-k`8RrhQ#7i&VsOW?qwK{U9!plarmM(AYT?%zQqlgsNbS+ zm0k`xnyW$fm*?}88$wF?i~!X9ggiv-@(n>iMOk6(K+=fvL@uSoQl71Vj#5tk;aZ6{ z-(86xdIDZR&HHFcDMz%69G&_u9#>d#u?Ub78&=Ge97IWS<1U^}Qt_L918rrvS|K@! z8kuVwaz+{M3gVlqRB{WoJ8>Qh%$8tmT66lw)C~dPg7Rd;J)8^m7Qd)XC0vWe)8U$q z#noEW5WP?9f+6>1vN z)Q)fV<|Zbx@ho+IA;zYyrZufzX;J7k1Tk(&rId+)lD+C_NjVCwCMASgkzN%2kT|@V zJ{om9^*Qwi*Kj_(O9k{{T}&=3hYl&IasX!|<6hoLzkoR4{2ZVe`G|Z%`b1R1 z!FiRySEhUx!&Z@>NJn}GT%+gx|C8t4Pi3Jxh9B9M^*1jGIxK$se?VjBim|!y1Zb%qV%RhDxcSOmJ?T1!au&I*Cuhs#ngZ z7*~irH{Mx+rxF>B|NgNR*n7b8JjIn~6tq!zt< z>IpyKpq35u5WQvUG0uQ}(Zl!9&QO=qGmF5p)JoKAoDZo_P0YAWDXws)VLKhBHRr?1 z!o)avmFss>krKej9XTbumZXG*@F_h*7slk;j=aJy^3)*wC*rCXQbb(RPEh+2m-GV2 zj|muqb0BxcVid|HIgXJmYMZbxP7jQ06+cEP$2Yl~s|i2g;=SZu(k>crqxK|ElZ#6* zbFNfaMYaqWE5Z}xA8K#b9j3+P%8xpWUIJ&zRhI+Qq&=W~(Bja0AYTvyuB?d}2VjrK z9i%LE0;SQc#8Mfa5urP%QE7v@2BGH|_6(`LXuYY;=@HVyVx+wSbf=aiHYkIXSb7JH zSCU)NJOyy`8A3=(Q=^8lKySeYXlSLwvnj>fqcIEGbJ_@6;qX5`#}zd>iqb$U&-q5; zx33bfDj=Xfi35%j@SA)u<8!V7eZb>We0wYTk8=zFitu`dD@R&IS|Zv}>S}t5#5v=^ zmc_o+)EQk${NQ3Cl4lO0QZ4B*Yz~jnvDy9d9N^!oDi;=>klQO-jrF!MhG+Kpy6$tF(oMosHp+z$%eIjH0~nJV)2`{ zk-CD?K?^|7jFgwaSA>C4Qbq?Di!H`aKjy+68mu-=-9T(mX2RYD^$GPU>n+nJ(n8T= zp^YfPC*)?vZs_524MI+)cgX6_)E?xRu*@;uK)*W?5RvwTh`6MV<&%7hnuAt={$Ls2 zTnsHu50_FwjX)j&3Lr(Xpl_I87&*)b)PB5&T9bN(`jtAL84T(-N)9yv*9O$_cHn~A zE9?`{k`Ys^BhE-1{RAr@r?gPkh%L$+M`Z+s&nmda2mseS(SVv7IP7zTR|Sm5Fek{k z9ql~V7uX(xv6-`>A4~jjUBVbEtGsiKUS4UR>ETM4VGKs5H$$yL&z2lc&z>0LPriw^ znNm()iasuDTyy61&FDAF;4(r=Z9yM2?03_vAT7BjkH&SbG;5-jGl!A>@Bzf@>=BXc*^|FM2ohWf`$# zrisxG#@J~)DsUg?MSVhiao)U2ZX|sfL84Be{-Z9S&M(1lMuJIK>Q!nSzK^oPO7@g^ z=8fnraP3b_ky|JQd@E-X*1psr)aQ(uQtvS4t-!96YluBcJbgWSn#|I$+Bt0_SK`D$ zxLQ0TQp7B+Bt2kSc5)zB_SBNp#$5M@Js`$-!a9s`Q?3&kS&YN8j7l+1M}LI;#mK7@ zpODA6V&lAMR~U^VOl7!-(!sn4{Z|8b(_Yi7BHuFdNxd4D1I9yK7>(;!N?F*)rLU{N zB6E#Ry-8T9e~3AH0+bOebVVX0f)ru2kXkPaypWHmGGj#rz%RLglFJA&K z_o7M|OMs17%!bi;$~s4)?@z8KMac2=r$}4cV$PPUC;AcGO~M?26ZcV5&>N#Jr2V2d z$+a6R`g3K&$N+sk+6rQUnt^lTdM~UaX#c63={eI!k-gQN*PHA*7q9Of0y!;d!;I!YG(@hD)CxklP^?tx*Hj5Z{^(&C-; z(z!aME}#T*UCH<*qhsMUHo2E@vttAEp2QG!Eu%-Yv*Zj$mXh&V*w3UkBGsrTC{z4L zUZRYKXUkPy*p_gGjf<7B0LBa`3)Jhh`w1A87L`6MC8(s5Ps6&l6wem`2Ii#5SBY4= zq+s0=iCIwo!kUB;H2UM@BKm5?FQFg@aK^+o<9=b@rM05OuBfGV~*D_+nn8xDsk|3nNLi4fNQUQ6W!|N61&y!nBvfF{Oy!MA+Npc+|t3 zIcGyDp=~4fD7o}Vsh8-7Q+v>J;T;AbrOy%x2~j}}`gp_&bH7}_Q-70&;iwTQ#Pu{e zg|ndlO^R?H;W#>@-}G7d3@J(*%}5J5mhl~~{0T9yQnEP)aY^mWInaA&hSd*VqNQiF zi5?^U3i{>5GiO2nnX*I6%W-MBsA*_LI9v88VGMv;f!4@|=ct*e_bK6A4@3YnjOmaz z;V26|8LmobUGSswFXjp85fR@Ug<6T0DIAmI=)@%F#aIHd$b42fg2OlpM+B2B4*h=1xH>Rqm*DB<*u`HxhiFTghnm2h)~ zz_Wm8^l;4HMAYGrXD4n#6RcE z6#-!n^CooxIh}Cx&6FnMixdvWPRM~ApV0DN%3avECZ-4}^>TQ|wA37#@<^LN?1ptX zq2s8u8N?&8LD?fE=&hFmR`MIQ7$GO6xV|B$kncG@N8?|l3!(r2fAngY<)fED-=7@I z6*c9Cw4t3KhDlBC7@@op60XmPNA3+G2NO@69sMxkgexvak!YKlOQrST6Qm<|8j!-I z6FHh(AwoJCE9Kj$3B&#^y&BS%Y0Fq-IFrjbWEhi_S=wi61ZU-2nX_b! z!HH|kn{!t52B;s&W8_4xXz2m*Nos8JC1*+9z|{jkrS*u$d&1f{EV1EiKW9PQ@*g98 zVV|1vNsLii!z&~Qq=j!HJj4Y(Ug{1?Sa>x>388%;+azxrk<5S*4n@TPwZg~gwZU7^Mvo^E~#3_AP%9E!ODq1hb8OWWq*OWlck#Pg! zo=?!qQAQ{e>`=s?9FyxTVvw;iYG85*xtMowMx+6=Cgf7mhqI@BBu`Pt5#q2;59c<* z_lF^;p6Bey8N8d?k&?tw!fR&g5N0vL-Z*tAwKg+ljBb*u%r23>gq2hv#7st+9pqZ-Wby-P$@mnna0Nq4 z$QTRtC$$1)j#T0`&XKDG@+j8~e3nr$0(%>;WOs2aex zy$?>gi}$d1nTWkK71;U5-7Mrl?j$2mMq=-h3o~Y%+l$YAz(qCW{xk4y(jy78jmDnj zY8cs#IoN^Ebo{>%5T6I;YT=FwJR@S?7v+Pzn2UXjZk&IL2gbtX-nWBlaKKiUMs?8d!1cF*2Lw91K{0K`0Zc#^Lp@g{bvOT@U0!myHEO6A+n zU?0$3z@G~Gs=(uacp?v!X#kn0pM4LQ=AOYqP*BCrQV;h2+yG{&d%3Svz682)z&+>tuk8$4OU+gq4#t7FjLNOrXPXRc7guTGz^!mWt zWke#*VmxxZ8~0!3nHAvqIh<#3;?5=*ubS{IcCYTho8QMSR6llFbHA90-J{2`C!5mS z6xHNXfy;XsZM*p@?xj~%1-r2yV8#zY6ZSl#M#zOE=A-Y|X7o)ou&ct0Szf@N`KK7K zEBb{s$G$QJ`|B5(A3{zHJbMDQ{~}O%Z!omOkMQ1jcIz$7QNig8%FIRcCE&LyW;+mj zjUQnTa5L-@FUDT#R8XZJxVHp2x`w@Q=YXH<;0GCJ)xN^n6eo7^M}eZd&3{1+EBc4+ z#TZYqvwDOu!(1cOHTMf^%;`7@(g|mHCWA&h(dC%b!}%ZcADktb0zCX=eg_&^u?M3M z`i#A2&c?3Hv*vq3FS7(^>FA$a#~HkC;KEbD)!XPryb9F(+Pn?iFTh!co;Z;;AJs%3 zLI#3(`hqb)%rYuayYVT`l4+>G91=bRU)@Jf&5L3W)W_y2m2KGZJqmaHXl%rO&efpL zOyGMPM*0cog~s7**>UV8eh=Np?ij1Y-%x$J4sdfBV;q*cYn|mSdPi}fFwsayH{_)_ zYm|yUZr!lMeX7|-Ed@V*g& z`gdOo7me{^BVa29Z+^#2mrm&KN_+Jc;$kgENz#(UY@svyaAt^$advf#kf^0t_J-b) zeCAD|rMTVr9o2^CX&;!Uv3?#amZCe3U+!V-mtNE73ZwL%NC zE@7=Dr0YjT6+F>Y>aP}93WCk83pDhc((}b)qd@Af$4h&R<$|uQ6VK~~@=s=j{=CKO zOSN9o(k&j;4ZSb+(mzpZ>Q?zJbagA&-ZHK7a(x5(x>?2Fg%Rp?IYG6;4IL}QNxRhX zQn@}zY$;4fzp^y+J$+WovMkpQNY}KFjBCeXo9>|e@3`3wNhWQW(U?;PpQ|$ z!|0v0S6?ry8qdY$>SyEyVwvhhm9TH+0ig=13o50L7CtdPjx-m}OMZZdt9K!@0N4>QLKGpJBfin51knm#72m1N0OzGuTY}z`P-& z)}lC9+a`F$pY**_iuN{Yde63Ezo~v4)vEgjds^!GbEIyPsI)-6{QmxF&TfH!bj5iv zFk6}|b~ktHKZnXuF?fyey>T92r$lMe_k z?Q`oh{y{=R)ES+EV-$CAuBCghb=05b6I}ze!`gV!g>y_^$E84$^|JOr zn`(@eem5rTyQG~kzAKHd> zdP$xg+$4<@&M8aut-?6DN3gn5KQIwJ=g%pNwC3Wcp)ZuLjY#o?xFVEo85J05-ydu* z4-lN{^N#WgOJsXbl0DydSzjBGusAuX+Z9i!fjFDzxD8*IcYi9c|_=R!E zmY_GXw9@;8-m|?ITxDOO-PiL`13k@LrcJWUG^$z$qAJgHWn^fGc}Q+AUbdLp_klF) z$AR1EHyjc=S)#OQ!gibsX{h{eJS+AO9JdY&o|Po2El$S0C+rQ@bhZt=Va+re2CG=M z`Cf1=QP;Cb~XwPj%(^I!Sg{FW)g|hX1j6Ry!9cvLtK!tqbMV zf#J5VJlD{7d$qpJKCOJ7a#|a#H*x)~eJt#k=4t<0)&?q20eOtjQ<_EN);E5YA8UQZ?=UNPtAbBoC4OS&>;IFN88fAP^Dm>F zJVCIiou!V(eDxXo7}WFZW--?i;z;DV!=|kw3w}hYN;c`vANS!CXW*(7tiob@w zlWJ?N#lP*v!4Z~w!dsqyWF4o&YPjm6&&WdOPIa+(+-Xw_rBg-+&mQ>;%X{VoWuehI zkY&si&g(UWG`LOc<-F^`o*WDX6|QOkE#Zu5>Uy)%V-hOS{z@(p~dd zV4_e%ngR_nRPSjfqC!H295DNa>S=>fAH70qCw#8$(4A78JWgtlZkLU4DpXaUF$YNd z#mUk~=#JSG{BqT7Ej}w2nSJ$Wocw&C9!8DX9P}#`rLE>v>9VjLof*c60WHTIE_77i z7C)D2>3zk;(lPTzX@yx|-GKAgw~R!b$Zds+2sKdYC?J1;dI?8R!}uiL*j;>Veq~fa z1^lh3)IHruF_wu_g0Ax8QMsdq2&*mpPfV3yQvvmToJSpu zGa;i*ml>3m@6epk>V+_5l(krGmCI4HC3Dik8%>cyt$}P-5Xw1 z9dx~Hjj9L7V5P>xPg){;AT|?jp_amS_k0`1f1+^gc`_gaME%dYE$fjpEpN1 zjLwZYsL!wlXXYoOZunP#XBZ^nIk|@AXUhc3_lgsh*w+~wv~2ZlwU7F1sDT=#s-aEl zG_AJ&tg#bbRZa1#7%jDw?npaOqqbDqBK49wO2422umDJH@N-t8qs2Yt#N1>X&BKu5oefv5fiDEmPJ{^j;WTHadKYE#- ziV7IXTo0P-g#qYq-pag(&aZvN?dm7N+eT08u(%CXEE)eMR&mbIUUW|@csmy4AFI9X@JUg{+1P?J@2`lxan|&E`3JEmB={$(A6Vj3_SFBPK~~ii$2s@z`=8%> z|MvWc1-X68lD*3V4l_&1b*_j>iTf*hnd_i+h_t|XV(izGaO(GKoYO;G3stB>sAp6m zy2Mi0PLDCzEHE;0UY>QB_v&ke9Id;&$N0ju$x)&iSm^sB)Z8|-y4)tO?bSMs9Digb zomBqIJdtqgXz4#@f9nENMSE)Xy0*kANi$aQA!|l#|o4GY-VDa73nPpo;!=0nj2iMtJV{2k{Yi@9Y=gZ(fusbhHBej=8 zH-iz<2-^}@L+2dJ2=h-hN!y1GBs<~Fe5g+|yhgeHm(&m4fbSSRSw*`?ww>9BRP+}${(xqX?zI>_Hd$x-GQ&8I51gL+5% z`^KN4{SmFyN7>I6%!qE@v~B;My<<{x%P-#ZJXn^gT=@R*z`c#nOv&vTky!0O-I)5# zYSpYYwNBM^^neO1D(dqzs<62yD|oT=DK)BpQ*UsqcFjAd|889J9CNQNx>ZzM)U&9G|6R!%F+JAmT;pmNm1rNW z&(muL=aj$cIT|%7Z<{}N{O7(o%A<(~BbsE4Zd=-BRm<5a%PfPWLxCGbw;rTtrx#5LwHIYq zroDcG9Ge}p+uB&J?Q870>*-vv*?-65mokiRA}%WfY@MZVZ9}cUmAALQQZU-Q8S#_1 z<8`}c?|7<_zxrlZYKl9ymel#&OTRBY9(A$F-THTiN+(ld+TLriw$+__t}1D9-GV)f z+TZ^&=i~eyMK5`83zuS_Pkb039}yEj+4`S;!~cHCes8S%WzXN<$>t>MoAw{=U&*Z^ zE=3P7U+y|qyh+upD?{&II_$pC+0%Gi!i1Qk4d$lg`!g@M*w_5z&P!F!{C0b(w!Uhx zX{}}l8sxOx(eRk8|P4NMS^9cTxA!`hlfo zef_U0@z$;4*vMa^>za2hz4d{P&IO~4b`ev{d)(L%C~m*4*03srVyD#~T>V#V*VzMq z&bfB?CQ!0GDoC0g0T{D9vPm;fDK*FGZtp8TG(K%W}-q-dvF&*84fyK>%pr^%Lv6Y8`{ z9@4l$KCy8qnhyQmqZFY5gZ{&{fZPEvk` z^s$m_`_Os1>df>j(am7hUo`7g>@FIU|0TNSCR)A@%(AA&G>dxAE_qHyM!P3Vqa-m< z@8V5wLVKm&Z?%r6^={lM<*D`R>FV2_oNRpRwLBSXBW2@$EcwHeV8+|B;`*e|i@6mRJW z!S#jSH}s1!J8$>hR+(?#|0aK+Cry1jm?^BY9kTC_aye?)bS2vUm(ozYD~%RTp?cB` z%QoXQ)=(k&J^hUEmVDZH#av`85$)PKse{nU9B!Ny(H+7VV|=c(3wL(9MNtq)ubEe>UbCW_lFdu{ub zKdf~ueUx`CuQ}E#Rw)TSYISj(m?LReYdki;5U1naPmTYCpY=oHKgJA1sT!gud{-^X z(mT{u+$Vh@9QT|LeIXx>{5rW>m8x-RvZh}(ON{PDN-(1ArQEwY=L(a`?)ka|#s#MY zTB?u4=C*l`Pm!Yk%6d_;Iil@uTQ_S>#fPX%r1%;td+b5P?1DPU_)|X%-+Cr0Xf+q= z!Dc24)r?h&TYDsQLLaQEzP?5y`IPIsgtt-_#aQi`#uL=0J1iX0M|uA(IGeNlsa}*= zKE?lzZ-{S)ce6TQXyf=JVxnu9Gt2g~y{9wax*Ac}Ia%2zh0y)u1md~fgbk`ivj$z- zQ>>TLjmt)ReVp-;{+c+%m}R-Fx0U+Kt4$%8ZqAVIIcLYtNgNq7$NoK{XlGFe;h3?) ztC#$d_h;_1g3WGk#XA2f?=SvhR6p!)xf1bK#FvqUj>gUw&H)i?BZo%(ZF@_}5$YPN z%p|Oq#;8B5ll{Gdx&A}iOImlMwf>h8tNkSoGFMm@n6c>D6fdR5 z+F2h-MaCJkOdqbc^V})wkpE)trJ_{#EYDxQcY{-c6ZI3yR7bmrQ_*Lmo{30|7#DHG zHQRO5E?RDi5A{acVb!Hh3UvBu`d+Rh;rf z`<4XvtDj0kt=pZM&Vi9J5eZSBqMG3{=Uw|{rIYjuItVq^ih{ntPM_>A_f-r27ko>7 zQyYcqG1JAa@=|#z`o~_Df3<9r+sQUdu5?KIS6gjvlx{k|i)iU6P@KvNRHEr=N+EZ} z$L_u*zLKBaKa~Gm;Y0t=8ES8I6`gH6WFU zZm3qU1FEsE47?s}6&kHJLY=j_=C@*`G)|hTw3GKKv*ZVIBPBsTgHDRq%udRF$0JvL zN2YaxavePm8=7lEA#eSP%Vinv&F;kV^om8O`dT;ih4HU&Txn=cbf}Ikt~}Qr*F~q{ z=x-ls?WKaddaAwBNP;YyH+TMKPsxG0U7|yrW;x40XNQP5nfzrw-8OYcHU4*b`K% z>V|q&H-wR>L6;?}fTJg>NEHf=w0AM%CHp`R(Le2CrUk;E78HerFEXgt(3_9h!a02h2_#R%Ng59`$qI087)6A9yA9V zLv)MwV+b*$z)Jrg{sn=t!5yLhRJT^ccmWaq`(kI=rerE@EXyqYEzel4D6c5_ay5Cr z^q=@QvM%2t1~ANMVf>0JZ13qdeWJcouWmR{HEfvSLVl&xyo6p^6H(F8E+#4m90w!f zT+{4ZlxcYPb>l_t<=|a!QMpvUwS1T7sc(E>YiPRG!?+@Pm4J1-eY4|BM}_^Sy*m01 z%(djogTy&zEhAGqseY>d5o#BT!73+!df(al=f-i=$~-16mdB&Q?Ra^G+)pf#h6xLd zbjhtx42(w1W});|#IoqO9mlL)Ejz>}s4_Uh|FpEA#9OqkIL#yZCVAfrEj1@eeH^W$ zq^Q`)f~fL{MCVV=C)O2Wz)04v1vUh9{}g|B|5^W<;A!=t(GRPkO>(j&M^UW0Wu-D0 z>-ZN?v+SHP+!z;HYs?5awf&Y0(0m!@HF<(-Lz0xx$(rt%<7y^+% zt^w$o{9)8;YaBekzlCQtBXrBVzPvi>{q_xZQJ2~`dth%p6dF1IxgnI$eFH|i_r-_9-8ol=oJMwk}*+~3k4^i2(%RQClo zg%+UCnPPt;-IQlJHduF}5^08gM$~gvze_vf_{)mE)ylp=qr%ABSvU0ild~sfJ;|M0 ztcBvE7pFXvb}n^vm5b?JGpZ-MoHNW@LBDrM#m>?%3oaG@TlRb4o;pL^CGEGJk9Zn= zKO)cBz_v>HOP*`?RLA+7`mXps_x}@03{KVi>Q&{9!eFOOx~hEZ+$S9jF{zm*;X4}jb<97^|ry;zCzCn{+HDC z`f~FX;~QbP<+!{fVzf9wK4Cp?dIEXA(dKpglZ;=gY>BB6vBf@CTBtuQIeY8$)$zA> zJXnw?mv$`82px>tlUlRJrfQEm1{=B}${aZ=j(we@dW%=c~<$FT)Egv~{ zxfjT~g_DD~9G1skYp;BwIGYZv%4xXQRM?3Uk>A}xpI{+3#ZtzWd94Q89| zq!>f3@Omd14ILTPzpBzD=1b==dy=f{tKIYOXg6lu{WSY}@yUv`V-~p*mENJxO4kq?$vG^?;457K5sWyihTv2 zI1C-gf`~zVjLMyBgcpqvvbwBGb_2QXLgR0tKI;25MQzg*R4{8QRiM)4HRQ;G;sV=e z&T?A^+hw^2YTy>@6V-16lLMcE=Xd*af>T2&+5lslQAeyNt&%s%vy~mn5qUFg-vHSu z-4`=ZOL`FM@%_)tfqihJ%CKP!LC5NC$Vi_-t~U)a*Se^Qc?cQhn#je!fqeS&s3aHx zJJJMs=0Am?(E*i^-#7o#4ZWN2rR281?wVzvZ%vXP8Ar79>WaVt-*xYN&uVX{z{er4 z_78dqKtcHE|0rvsLC!ak#)J^)@s zo_a@Jr+M@UhvOKr!e#LKr z0^zi!oBgGTQI0yUEJszqTrTEoX9I_Wr~F5Pm(?xkd0t)oK<=tcvz9Ae6p!=}S;jw& z<@z;M(wb}2wUx+s|0~QCpOccLYm!&`AG)*MHYyB3A8G{DOJWywucC%VNM9>I3GsUO zphtYszO(w)Dr($%%QFG3bV1RuqMZ939-nz!t1w>8clL^LCum6{;>!~T#SC#|8&Cap z-OJ18m0$5q2o-BCag_ClJuc!iXqt3nIm`6x>e0|E0o|ts4K>Z|F5ObzlIL2^DLZ9Z zt|Hm>+xi22hdx`)G^d763kRiI+9YSqKqut`TTnY)66@KoUrwCf|8a+$y1|GC6g}tY)$C%EWi^xP#>6!D9DLN^QSi>xlB(!2UoPH>>z#5g zJ-Pb3uC?OX&}+WUMUy={^1m({9O$CFVjUbMMeYD+wzMpkUsD?dKQ8;p-`wjKP8v-R zJ=B!Z_L-KQ_6@t@>_O_0U~3$=yrYr$h>+ssA!C*Z@Aw*T2jTY6X;sAt8q zW%2SiMf2tT;u2|J#W?+2skqkLJqEU4me9@D`_Y%@i|_hQq#oUR_O++m?ai7r>6~0| zWxb4qHW8b|uDQjr<2C_bW8%C?q>A z)*7uvPK~M|{_K~$H-cT=Qv%!6|3cHn+pdkSn$X@8J^xHYB_g>fs%d zrCmRDvz_~#5t+QZ`m(gAvjpE8@s9Au(3i6S=nPD({hklHAEj zlj>g_yt?*_?zK7n?hU!|+P~}fwcb^&;A+*)9p30w+G%bRZ|#Fg8O1r5)|?!B=0M(` z!p`VEY5oR18x}OW5mO`ZG%G)I#ofIR_Z9!_y%^mgc|@awsbWfut-8N?S?`A(b0SRW5#u`5 zANfPZc`>MNC<|VHZNr7H<2LLH{#^gv9^D7N(XaP_qg_@;Z@cv6{;R*tI{QU-4f*BB zGp(xi{JzJ|c8T)Yd%MnzI`#I&_iuevxI=7SzpUGnw!0hOl68M<){D2-pIdn?BF~}7 zHE!11()hpXzO2R$BiQoJxk;jRR-5v zI8g2*H@jv2b!Ez_^G6R}A9Cl5;QmIa+%oi^7|<;jIVJsNo_=fd^dzJhO@|Et%z z;h5%iYp!-R)P5~!ba&GY^?{k&*7;rRzqQxI*K8sfpV)ti>u}z8G~@c9h!ef6ukWfA z6W9=PKW%;G^sXgK;x~5j4{Dh=aO?0{-PUx?dnP`*;_}D8Oy4r`ctq*ZC?%<3+ts~) z={3Bi&%AO)IPkwSNoRh~ey#YXvuV?IJv()7QfHLp%Rh0q#q}8%uiS3-^i`KxKc&UI z`eSPsMkMOnidtm8dHLvr(&9blw~1$J)JQtg@-_QF%SW!iE+0DB?#3ZULF<3Vwr)L3 zyQxJzZFoInZ`SIU*AL9wT;t)usxMvXdAxmI>)4dzS??W8+VaVt{=!4n&Z$QmbZBpO z^>^5xB;Nn_^yWizFD!iYSJ98c@aliJis-Svahu4FrLm6-?|gFIxSM-tqA8@NHNVmP z)oR)CPt>Do+b1{f9lAOA{&1~>rB^K@sak`-TrHw~smJb5yb^h_o5x;b{ID^t7K-bF z^Ros$d64YoDrdui-Dv zzOUWElJlhG%IK3L@0=}kg?2{Bse|hVo0v5lMND^3dpz~toQM1JKQ7oLjE$U8qff0N zwcd*SMwsEr&uX0a#$Bzreg3MLagO1QkE8|?O6#t3*M212YY|$L+^R>9##?>ED(XKf zzuW)Lz@z8?9(L_bi?eo>9u-}O)$QM)Ve(hDoWi;{79QPs^UboaOn1hOR9n?|>eQ$` z##N#Acv^OK?Sny29Thi?UXh)nL)GeM>`Gm1EAigU|MiL0{dw*g?`6G>V_sru%9DhV z_Ph4B!3CZprS%F|6}=l8ANVY0o&0@Nr|QRrv9K54THDp^)#uBGQ+?0pd9JiNzv$-O zljfldw>OBvs)25Iy5Fk*Nxe5?`&mx94`oGMs(tl`5`X#GWOtH~kzduF`cHf-Fx^m^_!*lndF0Xu?5u6{@ zxp~LdKh{=Ljzp&!JwkOWdOw<&C6+F&Xm9^H*&Vw!`nzP8^}1Xt{884suyc7H^AE{<+{m9(@=@79S*p^awyVm4#Aaqc-`i$`;Jm=g>VcA8zBub7 zTOjI8Of4l<>#Ph5eHz*-{fO1@9KXySB%uYwaw3 zW_)L{=|2da5B5IV zdav~psl*6lIA7vlsAmAB>$A~Q~Y)PZMB_PPyZow zBPhAYm7T`geu%9ia;{u2Fv4<3Y_B)A{^*y>FPNEXfnbX|ZL}1tS%bzy@eNB$e~Ryj zRL`9gm81QqO-vY99x8spxS^hFIQykJZFa?WcTYc%ePZ*Ci$^Q2p1ijtKQdW+_Qy_L zS`Vw~4o&k+2#(5muVC5JAvy1BTIAu3Ppi#OyXEL^3^sbI>n%OKmE+K1X(*b_KK&64gFmD&CXH8g*zQKw{L z;a}dno=@5@9MiDJ&+%V8i2JkZzki>rb9&CHZ!V85{iea_7azVlvSWJU39LS^JuS(a z_P}>-Rqhh|$T}s@Ol$mnazEYftyPgze7m5*!_AL|hoT}bRDHHyRO~y-Kl+;B9sfaJ zLD{05P2N_*N=G2+V*IB{qCF658#)oH;jxwcPd`w8Gi8YNPv`elEyca_-g1BB`?T%q zm#y78M$EZc_V?4jvrcV4KmYjU2ixV5&zv2XJp9cTs`&N2*;!{Zdt|=wU{U65X=Yum z>*}8N+JlVIc_|M!W|w3|Jz0}I#h;S6p~W9fyw%*6+C|3G58UxjS3Z@>+js^>U9L5< z=Ir=_h-03er7hjrrDKXVgkl0Sqsn96s{XkWFT7}No%Qvdc7 zJ*#(rd}{pZzBiV6{*R`s0I#Zk!{?lPZr^oxZ?M5eH!2|^DTuU!f}oUwij)$9K}iUI zMG%k@De3O+W*e+nZ+F}6JolXc_wGEhM;!N_^NX*)UwrTLs2hX&Og=pLi@3>^73U6K zTlaWL;daxvY*FHh?yClV-})2Pv;3S(xwj7Hw=xC@Kl|-Z9?~(S-G;bHuIMKX_cuNk zYrb#!UUWnxeOvjke9E!+9SSuGNQ@bN>tOy_PrDn6>dqH_MF-1wns*g0GQHr-(_Q`9F=1)ltL?|#e~dZhmseQD{km+=>4?Lh-<@jC3u&6HZLz=k(5wqFH(gtE@0|BtOeub!+mRO5s-an{gg^WW zJV_N}@|5>xdZl!a=Wd z?Ddr?rg-1t@Zz^0kB;rI-o5?m!aq(Q%6PJ?GMnER{!>QZ-e>#1lT*(eeX!`r{)>5q zE*}@ANSWMpbhGZ6%Y*YAsZZve&%cvac}n9;>C|L%qF=%iLm)TWJTd>!qYn8>(=UE( z`tHmwvHe5qJRx?bE~~i3>-?%W?Bjzn5__j6Mq2|;TO6jZUDHe1(uuG4dAc>`ainmelR#Gar2Xh+3jX}Vu_(A|XZn-9x8 z5ySiTK6T%|_N-}TGG7-mKIB}qJMNv(yMbLitxE^zDGS~+_EBU-M21F0-U`{S>#D7k zmRB_`$|!lWa-YCNIQ$33H}hMp+aB41?OR=y-?c1N*RuDCo_&(WIrUfGy)f>{%a>D1 zZ&#i(w$eRq*S5!$p5G-F+CO?VIWOn+i|T)^UpJIV6C(5(%Ua)0d`}%}ykEMc@M+B$ z>wx+%nTM)|kjT{Z#Gd{-F~r!kWPII$2GK#4LljF5B@u5#4hrm|i+4>hwW@DhKeLvV zwwbG?_rkVn9;o(k9r@`A%X)m66BC+N|Ko+d7bEV>e&l$ms?-=S`Aup0UYB;=UNt+Y z-Qhe?d#5D3tX=7Qg*T1Yq&C4^rl)DYg!@4=xSq~TYgEmivJXm6Rw-O>YM+F)inx3u$h3p}qK&HzV2K->ktld$@7M**pd>DIY<*Vk-M}F(lRyVClwLTs^#B9|`Lqqt`*xzIM(6{tm#o><0=1*#)jO}VmO)DG*W{SGj@1x)^g4+gO z(8Vji_Fbj@qzx9P{xeH=%Sl3kNKhUO-mCsr^%tX2riKURxHCQs+skw-9#%N3U}@g? z7xQ0?eHK(TfuA3`q^Y?{Rq{J=OQT1JEYp>FUsg{mDKGf6;+1Kk`y|(i&O+@A)kiFg z92~My%}7Rv&6H)@Z;GtHV(oA5a3Su1(xZEeZu8>FL@6*BAtI(M+;{iRBcz)k)THTp^MXcC!G&- zC0R>Rt9L;kw7+ zy6>Ii&0!XJK4%{Di|CYXd*6pl7r(i2qvA#f#VEJhGaB}qimO|dRTpn=(Y{`EUSJ*nrS>^t{sk-ZnN(@1@V;-3XSn-s zx8N!A?O>;JyA-qeGm16}y~4tLMEHpLUY~GOjAgD1A1ay?p4Dm0`U04&{hPlQqWol{vZXK;ptLcQP zjjqL&`XW@HiXU-(6`{UcuFf7&8m}J~?;r7t-%Vv#A=`1%dbO%1|90{CiX7`yu1foh z_OIZc;bGzGurazgW}j=c^Nw|*t;E*TkxO?Ue$m{~b=JS9{Xm(ie2X}6R)b=f`MD2=`RiOJapBwll_M# zzlz?f9i@oz-gnr|RV6K-4t?Ia+-$XSZp|da^622aT)de9@thC*Feg5I~n@b+-C|zpN3w`)DVRKS%<&0^OmD)4xn%0k- zV>eXIFR05uShU0#=bSEF(%cVj7ZsnVOc)vZtM*I2yXQ@7oKY+bDqB%A#BOnqP{e7* z23!n_4*xT_+MreMV`g}3Y$q*_+8d_X=04V+xgMO^^^zSKzC7(_`rO1Ofy=m3=1upL zO7+vM+hgx5UscowJH|<08&cv9HcM}DA@fSy!Qc(r+hQ~Gtg^J1-SU!3-!lHs!ivo_ zgM&`QZAyLhj)(MihF*p`i$#^bSPI48x$wA8_M<$+4U6CY)woy9V?d*4~?ac#>!>d~vU)bkzYAPwW z-EhIsGN5gs%0Q^b!d&Mn`w!L{%XOQ^<)E`2Be+l0vHA*KiTa%KHD5w^2L^iAy4!i~ zyBgd>JfC_0B}<)+?sKAc;c=nUdV8eRll z3f~|7ZJaaii^xR7Ng>!WsNszHSIb1xyOgJw3DeXD|8W6L{qN{o>iTOkl^xhl-UW7( zIn|#dzs-N$r;N>o058v7)<=oeEk`?vq2@Pkplh@oLq!q$gJ2Y;$uX3sG; zkQ8)tq&Xiu7P*%&_q2-w{tArrFV$X9X0kzIw(y-N$#u~dZe8Q37piE#aRdK?PMaK8 zWvPEwY7}jmJ;FuzF;|#pqR;HxFFvQ!I0am?x>9l9Wwj61yq~ISQ=U${@!v zYI1IZ5XSng(3R=`)n+gumSt7tm4^BO_OagIr2dM%s$ktYDqWT9cS=7`wL`k;T4%S~ z7de%#<<9l4_JV=6@?=-kQ`A#ceUx()Q`vHHu3+{YbIib29O8ZxjsV*q*S9Z9{Yue@!RNKSSljo#9i^&M^S8e3W_?ygG z$5!L{svWh0xybpj2u!lBsGkcZm2+>g?1y6@K2wajv>{(1dMtIzY0+pHN)?@+qed7Jqnq#>-6)AEb>fBAd-_xu_~Fxwyo_$~|Q zy|aYB1*3pjyg2&)c%6r7{qO@$%;aE~Vm%nz_NE)MA(Bt*B3>a>>~DpILYA*c{DT?Km2(@p3v4lS zfDp$1W_}|~!@bfnG0XS6xQ!4@uY1~h#&N5IvJxL8*N5+9R@5#p{?zYMI4!``ASYeW#fp#QWZ!!mqwj zzBj$3Ed0yhc8R-_w}ek%qH4>E`V{x9`rD+iPqJ^ZU9i`?bJ$4TkdR){@v*ZaqWs3N zTU^)eN1de}rSPwNo&ANSi|v$q9s7gkx?!PTUpl8ZMNubp76;S)qY>g!VZS@Yndbb* zUFqw|jZzL)l`5n8d0bz%89SXl!A3J`>389lMpL*)KT_L-Yd#0C0Rj^}f zJ}Y>)aARdx^Jx17+g8gL)*-GB7*-b;`ZVTr{9DnJ13u&iyLQ{^97DZVsc=iY?F~~4 z^RLd&nP-|P|0x0g^Rs9=@l@s2H&d)3WU);?vulR!2kR|IgOI7Xqspe!OK!ygMQ6pw zbONslohUs_H`DCy=dMhz(Ra+(%zM(~;NA{RPP>}vjL%Sp*9^?RmiMZ3Sv_z4-h8zF z^M;uYx}oJaCGuE8K~m4S&B3jeF`io6FZNTeZSJ2PZc}32&iV@bugpW;rocx*g8x|E z8RZ1-72SG@Vp#DD&jb4pmQj|2_GffA@^_V1GfsU<`2|0l_gAJW3DuhYLfGXFcg}Kb z@O&jM77ILM+&az|wm&nwRr}Nx%8TW$CnZmRDygcwY<^ldxq3rwf+JJeHMA^#TWPWt z+D>mjAn8lr!h+@xN+0(v;;L1(j;i0P*401qZZ`~wJKS_v_E$}3!~|;(y8Br)mRYv( z)^_!eDpM<(8E3dybw=>pkr|Qigud^eqdB3t$n+8a^|Z6^Y)~2d8_UcN_cpFd^FsfV z;jCWJt<+9c-{nU$k={M_JC<@&7uy(@Tlig>qd%`);J)Op3oL47?K!yZTtl;xw{8x& zy5{bc7oL)`>I_r3W1+M!P?zD~v1@1ltcOA8JuT|=RYNMfR4%HTRr7xRa9e`d+t4EV z+vHVA10&-M>zJ3W{npv0-u27sM%N`ZxUKhuG|jugW5Zj87W;7;n_?>Smr&*S*7U0O zR!vPqgS(oy_;(EoAT;<;?NRMT%_>*X>n>%hmB}qrdpcUi>(u3I?w!42xY_zed{wsj zfcYo8iyt1lw8gjW-8t6Sc1q4vP}Wd7t+GjNMBQ^!ACFhHF*G^8E+Hm*Tfjd4H_tfB zapP|_=|)pSfPI9wxniB34IUa=6x803uIwxhb17|RbFI0p?SlIo=~qQhTE=)s|AT%F z*{eX`a9cu^oCXqoibZ#A`aO9 z$p84R{@#WB>6RfHM|fJou9Oz3UE;ZW2?~>Q=i*6U2yJGHZce|cHTY7%d z$yIlEiX}ODL-xNL)vm2pU9|7cu3KYruT<{$Hu&w0-__jHd|z^FRbq|vk@5EK+%(HQ zeMJ1uw3`W^gl|?AdDa+}ukRPvlvdjkb(*+a$!x+K!OvYSYL}MIem&hd-8;&!F2EfB zIOK*(6QJGYOiSV6+&fD6Z;d}Vp)7m{dC^`+d83kf_To~jXZn?HH~ zz?>Xs+KA+9l@Gs1E{WsPvlF%3T#A1^-|@O$eAqqk39p0h1~$O?>Y*Uf|!+t}4Jl81Lle`Kl3 zbKf0$f7RnrB@XM8pkF&|?)!1Sz$U5oyepsXzIg0Jevd#;>yAD5cPfwC!y{qpa-KsMfU6-ws+(U+~oBz{P zPwVOS^ed}R{Cnq2X{Gx|P4npVA{d!nZc5@-AWPeFk`Qg$P)jev{eZR)O+o5f@iOo~lW)H3(_rEmf z^_q~Zmf0PKX8f%`VxL|<`}KwLg6hW(7h4x{K0%k%C!!ZOr1tU4QTeT_Kal!`El5sC zoEGr26lMOaVzKd-+3McItoI)kyf^e_kdGN|Ur^bzx{on6@L~UJ7nz^lSy=baDMeuKM-%S8Kd9*kj_@bDA3c0>y(GkbiTyG< zI_p)tX4yylhEy)Q?z(XL!FX?a%J`1H_TR^i_T73t?L}O{lFD4~KJ5o#ljHA4o(;Pq zzA(R0y#LkN+6$hagVGYdjz17AC~BKU7|^ZS!brw>0$9O_gHZyIeQJKWujI?a{qQi)&B6{qxM9H=X=I?-@4! z!?OdvOl)4w+@5p)MbWyN3dS1vSyWQWuFR_mZI#cfZalnyt1#ClT}W)wrbX+~(YGD1 z3%kCkFWhMUk@p5Y2#X18>fchU_8qabsk>Emx&CwSy8-Wn9*MjY_LFqW{6Y1|>Rjsx zrZ`}(VS@j+y2W&+Ji__X9%Ef(uVt$_eNc1%9@@R^G{;XSmE)ANB7b(h*nm*&+&?PJvv_!SkSE8a8D z6D$T>Ot+|(evf?{ESc4#>u*sJwj;D^H$y*GyOtl$RXK*+R#_f6M~a*HYD0V7V%-9T z+S}6>;{3yQT5>9)6-kjHx|Q|wDw2fSL}%A2eV50zdw6r>&nrBKdO7;N)peY`|2JtH ztkDnOxtm{b(>zZcW>_0~F`_W(ujDmByBw=u#ok@_Xnezl@DFo3x9OdFhkc{$dTy%% zMQsx{E1*qyr;sIqe`!bhX1Y(-XV-MA{n{~2GcM%MnD@eFYJPKWuN_?VgYgrOK|L?% zx1cP8P1RcnaW}CZu`Y2e^u(ys^hf+g=_>d?yoYTXM+ck9J6{^+_l2%rksYvD>Q}Y1 zxRfr`l|wD1+_j*>$g=Q{gW{C=me88l zRr~5p?iH%o&~>4&1OCu07FL>O7=ultY-;Ii|C%6=eQ$AH61A{Qc!RVMb)X zl;v?_{f~=1-CJ#AO`p~KnSDYN{ekEs@i#-dF-wh;%R_3^&ReR@fwO`V42P64%q-7H z$3@F2Yp91)s0~4ZC;bZet?rGMEb~-HzNk>q?JVtFRT?)%xb42-n&oi`SEN1s0rd^l zB7T$fgD1%O(6vRp%xzV!P##k}V%CUi>s79j^-2rq?#WQP9l2EM&sMR2(YSUp z;nEP_uf8=>I6Iqa6kVsPTRZ5i^=xUPw1}#ml}I1b`QE?TLS~EjkkIRAc&9oNqNi)1%J=>$XaFG3uZ7JRG zo%Q`gW1i3GxlLR)J6QTsye@Vlr0o7wb7CjetvE78wwJl=3-`|OJykt7Jk~5^zZW+Mv;tu_xEC;gD|abc2-6$`olAv}m=63A?Nt3X z)j{8z?j^!XsvUNZo1^NYF6QXok$0{q!yWH#?JZz3)N|B3m^rRvj=A1T>{t!2J;&eR zc*O$dH*d6ejO1g^iPNOkTn;nF^Mj`o@og8!Dd#IT5ZdHEX@ke@aZ5YcFS#w0n_d;8 zJhMF?iC=J?6#q&gLV&k}?=L#Va$J>7l@m4#t;JwkAsWTKrfPU+smj`Ls>@X`O!xgG z?PdG26;e~NxA437fw+z{@SXU!+}Glt-eAFBGO}m5y>!oVxL_39DlRKK@}rm=REgpN z$;X@QSgILPNcic8sP@M)sx&f$kl61_m!%1f74QZ!{iv?nLaNp`hG?~sZrJGwo!ZMd zxg_3CLDdMw&0-+Cgj>r^Ws{^D-(25JpN8r_tYsxyE%Jz2;xSRlJYinYEnXnS$hCpH z(Av#G<}R~@PW&$u2T`q<)gocL(%s{~8G|%g+#w#8zG4-e!2ZIHW^(8h{C%l`>CC>S z3T~xTYsxI6QoajK4YhE{1Rr7Mgd+m|G zcb@;Hifr|S{(edtM$*}Z`A3>eciZ)ZhC7YwxkXVuw0?v=E=a?rafJT-A<637giU?0 zv3B!gS{oWfPv%esz*6Zr{RmX!EuE?swx)_yDO9xvh_+g~n-xu!>u%7Ugq~EV?=B%{ z^F;ZUG)@n#asg+mjJ`uv^)eb6s#+&fD|AthZYtcO8hi}Z^0QG5Jk-j5M7Pj@Y!XP= zuc)<%`h!63bdBekiBkQ)zZ(G%gL*fADMu}H&?b!Li2BT^z>nIIsKyFBD5La4+TEy9DK;V+qry2VQln-ns;{DA zDk@~6QZ?#=0xJRaQBk816(Uj3RIXx*O1`MF>ZSgJsEQ#f#iD{NDjK4mF6w8avN5XQ zqMk9R3G^S-@kdos)Kx_7S=2I>Ya`=x^n==fm=orRdaI~zi@Lf%8$q>Jx#}ybLAr>> zaxGfaD+a=WT=7~(J!1^0c8Xe~a*ah9K|-#y4x}4YKStG9j2H5Sk)n0E71XH3=rKps zUPXOXC(Q&nU8tstaiRJy>T0^_U#QxS8o8)1Y-;2!YEH}5QBk25(gzG#&=^P*sCc-$Ws#3(^Pq1bskXw1-N^sM#%7z(!3{{0_7cAP@14PXSQ?6hM_$;39xB zsMC)6({e>-xxO)KCPM~5Tg(Y`1*!<@&&pUFpd_RhBSWQI&#rpBMLK;D;|Sy;3;$mm3Dok`=ABzx=?o%_yOQH zD(_+x&}h6X*JH*vK;p(|P_G&DN1bH3jyfuN<9k$Y$MZnoK%H6WD-f#CClGo-J@gFv zL33dRzuK=b6jF;k!)pmsZE4E!wAES9T>qe?DnIioTzBpH;)NKx5cZWrSNnjh>E zMynt#m6703!5cVR=nXZS<*MnJi~I+l$T|cpW=J#8Hc%lJ^>aZJxi&p?ub%z|uAwbx zI4q1nwicSKqaHCL=s9=^E<(mJKh&2FAPGTBcCs|+uZG^m{4i4>zC)%}s5eP(162VU z?V#GOK$gciUXri!QYF?}@*5%4&f~`CV5zI07FaJCyp_LUme`DGoVH z?Nrcc+EOfdjJVj1X!Hk-IgKi>&XB66w-4x6+$a{6XXi*gm>Tk{M(HF~ zyBa|izOto%m|--}IO#{a8$O6=GK_qA7Wo<#vzsZUpA~d7d$ZJu`B^$Zbt77nFVCR6 z-XoYx#PN$%J@=V3S4yW!u&c57th0+M=C-HM;3)K;bk%CF)HnG#F@?IB_ zld{-tY!4<^6ve-(F6u6-{@A8R66xl89y5~JE`3Npc~s4J4fVZ%JUA;^#79(r?J)IQL6J>=+6xP%`l~0%3-_WJ zB8e!}of*iCXTGLLBb)5&Rr1D75${WHQ7rM4c;A`cD5k2ngP4=jL#nn~K;N9ETDoVX zFQ}cx%uj@geuCbcN8HpgZ!-B5H{2v#^np}4E}yE@o}u60A%Ec^83f|x9cd%gmy0B7 zKBu0j5-f9$ZdYbfE7|n>E$T6aZVUcRv6fx>km9VXbm#Mt)P!^fIFmlAGHfU6c{vleWF0 zkp&X!N(zk|krq#LYC&9pEfRm-o|=Tlov=na-)LEt*PBwBf?mrxp= znOZ2MaRSRmPjrf;&&p|pK#r2F^G&iE{zMfY%?MSl@u>op^k|I0u16*LMAC2Ie4%bM zL%a*3CsB{Qn)=D2o>5P`nr2;0JhGE!`q3Mu^h6zv2XxbuE(6~L(L@y4na9+covI9? z(mc?!Vu&Z8|4SMPP?A`p$qS-_n)->NN(r#}K9Z9J`WtB6g)~E8G|8TqrK*4x)I0Fw zHN@pm>K#@+pJYWv8ktLdWKw)5N(uCL5RFWZa>27o8h0dBD32w{dP&*_{9%l(o< z?dOrq0G}t0;!YX2Hjp@jS)z6}ke$g|(CG2TL!uz?JsIMmhGq~-R0lRjBDG^D>lH$C zFK?`Yo=n(ik<=LOMxXEw%lSS^>{eNScypJTir0Z#fzjC=DA8 zuh2mJZAx78C;dXS8Ag1oBpyhV69BslcylkP4@9T!X`X6&-%0dOr8h+C$xLq{=7PKc z%L{o=B+aRS{_Q1RLleWOeFc4HBKd}n0i&dZW?o3QtIO$Ipv*>+{Y|8n5CcME3WzEa z*$p|4f-dNY?};>fc*St)(LmIK-$w;~U{DD(mw4hMkhY*d)%1QjaROT9qdA2Vm7*z2 zf@h9xlo_DqA#Vw!F~f!cSJp?K1vsTZ+(MKIsY7%xkQ5?1w9z;BQ7NShdAKo6wGO!E4 zW-!q+K+3=f(K0YEK|^50AhrS424YxXa01T^zaa(z3Iy6hj)TY#s8u{k7LW=+CpjlV z>?R|^z`n=`P(UC8Cy{3$PDJ(vON$3Yk)w6Ajw}qwrgCP1xCe7UCWQGTBa=~# z5X(RsfHEpaScq4F!GMSyXbv(C5S~LXh+17VBk%;V5-0*pGt3&u&5%K$%Hw$;49IOF zas*NW{(w)Q4X}a`pJVih`0xiYDdK407XZZpDA9-AA7NX8)Pjslj{0O|3%r3jBIiOp2|Nne zSs-iyUj!&8@D89XW`y>DRso4apNMyn4MM_!6#&`*g$Z&Dc?P-&EFC-mBp6tH&>`SC zpk?I07#n&9>KgDJFjGhmC?fZToDJ3%5)9M~WL$V(#@)dvkb?kG4}8a*Fh`6Mlm(T* zSB&#N92#Vp;4J8bTtm*(!E?+CG?lr6h#fKo=?5MSY&Ecb(2k6Z1SCUn1zJFl(G$=F z;D^hUz*88JhJG*($Tv`5kTu9zhm2YbiotFG;|5tAdO*GjzRE~a$bG;?WPiYkgUkT2 z1Js7LLpmUVuoyrhgG592fdK^FKud_*(Kc)gyggb2x({?5--F7a1rSZ}f6xs$E^>wk z>I3Nz+6qJ$IfnL1}0xs7}Aqr=SFEA<$=F zS1>+ksXQ-8H+Y1ZW32)7Le>V`C+G8!Jx~wU52#Ie5_TVJG&-U<0RkZ8CCkj1gFmka4UU$g6W0A9ybN z3j7Akh#nzbx<(smr!^8tH&AV{iUpsJxnm^$jT|%5XFzBLoq$~lxq{t@C9KM zIRRx9KY@*O$Gi9g3y)P73&qPo#6%mF6q6wi2Li2?dIL{^;~GWrEYK&z8(RT_Juo4G z?g$-(7n6TrjW9k?4ZO8bgj`ND!Adb`fv7i(qPb*>sMF~ug?^8q)_~hqPdyh?2K9on zgvaz>E$I@TjU_4}#=}?w8^-`_acBT24X=SX8_3eKWeB9VB59mh=K%&M*2EDjAeX44 z(Lf_Zs7+A9RBKK)eVfUdSZ)Cr3oEi$LZAx+Ye9g6U0Y8Y}})F!2Yg z;&L3*iKhQUinYWQ#3!;>mNAm+sn;r^75plYgt6uZe<*ufU@?J<@Mu5@1$rf< zNY+&B1o#s*FcU<7@MVZ~;j0nX)HPBSnHDGx3{luitXjh|B4!2dDB{;Dk`Y)B=%AA5 zggL^yVTU7v-Ul)$WCkc%b@X%%^#bHQj2kP<@R(SqM7!VzY&&c(aF0V9c>pVh2uqHV zeDs8oD2{jm@`3rlF2EO{M?_*kU<0BjWEh&{Pon^C8>AMqggufYP#=l|b*pooC3jAuIsv)9)93pPuh!fbI2&PY9SHVwU2Kv#sv7aK_57-ePb%M`` z0D*PP)5rtq2bjd5Ea(6nP^@+%28R975tqR`&=YbGZX;GfGytiA_JgK~v>>Ojl~~<{ zSBDJ_p%#G14wPqD3Gfv@R$ea$2VrGpKLWgH;5EZe!O|Y1ViW(XSl)0KMK$ zej|z2B!C7SO3%YKA~w;{4B!E=jtrznNChyXfjtR3kDl?Lyt0ir1s(zD>ex3iQeQx4 z!^!|WA6B>Jm2^4UMq~+_1axd<_`x!`A_M8Cne)!deby z2(A4uHmIjofgwoM;;ALPAyWbW2Za%Bx+x9;N^%s{9wf#F%1yFvBHiRo37Q+EU}LUTZK3r*)c~gB9Fk>p#O+OpbN;>FaqSOTAHap z%^$lxXaQagk{d#w0=pX244|H2cg!@hqDJk;dIWHuk!$E_Y{=QrE+i6~2lP8&hr>c5 z+5-kSybg4sp;0OzcZd_v1Ed6ax7hQ9JqI4Jj^=@w6}t#pY5}v5Jt^=3fxT&>K5A(u zh^P_UBM)t8)Gx#_1{xjsh}9WLG{%8m5T9ZP256~)G(+$ivWUn4`7c_6zkwzjNT+}v zj9J0r!KQ%{;3H^=zF|eY6sur|PD9VjNbZnn@EZG8u#$-Uz$xTzuri^IqmgqIv~Hqr zVK>2Dcqz>KKmAAlScL%}u&0R3AL#UG9hMYp1uB{gtQ0gKk$DiwRRs0pPpx5X6Kfcl z8!U~RMqE$-h9`qnK%a=3Ko7(R$W9TJ!A3%Jq0v|m0PUc4pcAqodHr5k85FbJZBWXTZ zeZgq!=sU=ej6Ms5br~fYb`;u%UJ-wS`*>GR*0z+qXeGUaj6p_TgwH@k?`YIBPzSiD z*zF6U7Gr4iuurn*0c}8eP#1{jX8PRTI7--GNS1=by5 z+yS;Pl={XS^7#f+qpgD+If!~SGz**&KxPPzA_jqG!e0PeJc4F`h}}ls29a7FJqJ6k zqwhkfH}Diu5x9@l2FM+v80-#$rbZeSq!qFaKV@(9T9AhzdJ0xm_SCQd@B)xEj1?X# zh@=i&1}|azYl$RA3G*7H(Ml{X<_7t>0mV-3}_(b#qe+sVw4+EcL zquG}>auMrm$nxb?MS7He52YVyJv7GCsP%|gVV4le!rCFi$Ji8&w18zooCGfm>BYZg z8-|@I&=q@~IA;M$UlaurhMwYSMEmeEh>YPSliEgYfKF zL4c&l5j12076maSb~KQQLu*257P9R&Q@`@cF1|qoi+B_fBmAE~eFn=VuQI@LAfnX} zUC^KGm7&A1w{Ch@j=PbiAaanYirx{Y2aqlyFN0sMB{_!mmL(f27PX`W^7;^BDx4$& zh2a}9%Ub#y_8XQICm)~{*d>6p%W<8I)egE~e6Y2M8*%msQVX31zo7FN4}4<-%_e~6 zfd~t-D3Fw59MEg*HHJ`*2p@@DPL8HwAt5X9(vTNK71+r^YzBQq+yTxZ-c%6J?9?hW z7Ev%(59F0S><}1fPVo1zOt9y$fyge9g+sq!Pml#5-o(xU>9dzlc<@4}>4Azd{!=cUW7*+3-;C`rr>_QI0;K+n6t1$)_J=hM>Ph z^RA;GNGU$YiZ-%H3$<;dA3en<3Dh?-{*XrLz^((VB5a|KMgu#DxngY;o(}#F_5yJ@ z@+f3YkO<^_-~!HXfkQx5mUm8M4=SIz@sKQGJqz=M1((;OuwQ_TKa9o!>mlbY_#3>! zz7cX6#17DXWZqaIfloHmx6m}%#$Znb76x7mJb;{GE*L%X3cQ7VAGC_uz^Wpjg;xZ1 zV9P*%Wbk+kRvjy&uvM^>h~r@?u%=c|bV96y=nFXYSlI-h5DmhPK^C!M2l>YSj*LDH zT7Z(!f&gk8c~lU+hjAi0f(3^EfQ?0jqM|)na11LGu-}k!L@n59z)3QBuL_ic^uyNr z6CaV?Vy1|UVcW234~c^Y!iw1FJ78#IcGxpj(o$@PP6fk*v|Mbrm!g z=$aqR60(ZO9P%dXFKFve-%+W^#`z)_!mRK-4L*GFm$Q&YD_i0$&gn<GSO)-AaJ~zaN0i1katM^dt}$dE<3a2VnZekxLIOK4pN{~C5D_2(M6Zw!NCJE@ zMvOQaJdx*!zOd5)%K%-Ga}DSr#v@A{)_fqd^0`;c61!;78GYk8VdXGB2T=e~7yW}q z1)5>r&?T&*V&@jJh|xo{@jZM6o`vepqjid3>m=+J?uQV zAWJxQ)L{uB$Iv}^2GADK7jy~n0^%mT2S0_8fP?rBz7>2&Tmm12KiFA^KY{lC_XPG) z!8@D=ft11)VXqWpg{*;h@@^|~?f+oRkoR`}%=E^WPdiJg00AAqAi? zs0SLsK0=xy1M<2y^cXE+1zq;&u=Jo4W2a z5zCexx`3Pn_VzzY!MdPN`Mv@CE_T9U59Qqith8a32RZ`F3d{3fZ`g-|cSU3iTaUa8 z`2-|KK39X4R75WDq58((AOVQLVPPRj;0{)KvFe2tAxIN66PXKa1w1}v1fRomp?^F9 z3dpCcu+tBI!26(Otob1mz`Bd%g&;v3!Xb#r3 zubcosS!pJ0=}`!9CD$vWAmBQ`>h@KjiD zggro{hrZ#9p*OH!xZ45A!EORpZLyvNje^9$0%3=mC*DCKd9u#P`yBMCoaJ-$4pvZb z9{{l&EGIH(a2uM6okEVzb;2^@mKS1u1)Xs8r~beL*j(gGXdAo+j}aX}Pvkfn`)OD+ zgRE9lJCI<1YC)v4lv)}OWW18vX`u77&@}jo8X5sZF{+EsLt`a}p>w3NbcWHnQ60U7 zody@h$;j`)`Fa{b8l8&`q}iJ3#IhVS7tj-RbP^Q%Yi5d)0%*1|)Hm)%AiKex1>{9q zY9HsF85*IA@(>s8GU7a644pYP(gkunj z=s6=%1*Z^jX4*!iLd~XcBT}v&ws7I_pDJhx{rt$kxdoDVe3J(dp zr>FU==+p$_9ppbE<)cQLA67OqNK2HI(IgRCy_)hG8&Qv?bN9GAAkptwXDuKZ7m2Po z&-;qTS3#LY6n!cZ{}6}E>-@Oyi8XKsNl5}pM*Bv6izM11|0*MX!?xhY-Akfo4dpvt z%J7imDu|Ep>&bL3y}WUD$Vg$WAaM-crbIqFl=R^t-AyQx#xX|bXI9A>xKg?^YGWo4 zqEmBex0pgG<@0@=d_8^d`FE_84x{o@A?olkEyDf+4(`Up@J?&agpt~GDF-w_cRK=`4vw>(Z zlsf}bi=ituwU0Gr>G|o4*E*vJjDq1h1@)o0a_nj7j=_2;U=$`^`r9M2X@I|%Xcg<$or@GkQX^#1Kl z5bg@U6J~iLNycGj46ETj=2mhSxgWSiTnlaoJD;s#GD(&*2`9c>q;j=X0j;@MEzK2M zi)+OpQWiIu|5UY@aPD8JdDT}6mfb@2bFR9^JM!!qcBOrnolLUn5`OSa zB?QP7zMa0cY^ikCS4egICMuh01a*kvzJ3?E50!Y(ZM0XI2AbBI*IIhmb6wy1Vz^0s zraDJ^OuJGWuO6c6zz4JMO7#LO4D#*rJoBl=hrZSPF=-{;-k!kbtN+p7)vPrn>poQ| zm^H4ORAc&Howi}6rOx()=b8AO;x}~@-DTYe`u*DPRhfJ@=5O(T-t8Wh@Y3Bx8tiK- z4p6OP+cF#2KHPa-oqmGWXLwUPjLmiZV_wqmtbTXx&U(9jf_EGHj5li4{hSXjvxmR_`IHc}t$7scp04Zp6P>;ZmsBXf)!Wx&?dDywj5o((ySlEf0H@R0I<~MVWC`-G19Q%H;u?a6^!Pz}2AX`X0i0 z#|c}ht=@UkUM_scKk)0OEL3J1nkfUE!%Sm^c|ny?7QaNoVJi0CEmP;+e8tw@Y8Y>u zq5L;|cZ@nbG;n%Aq;{{TUqfX5Rm;cD_kE?lkNm8LKDurpTaI-u_mBc@p6uLlm)e9ix0TTyeUrmgi&;dgF7s|?N#>}xm` za7El;>R4M~s|)j_i?PX3$JGty_Y3CV`0~cO{F{{>#V*0B#J`&LY&tjep>D6YfBl1M zRe3w}`_dfs8BJW+Wxrece{@yeou#VRv+aFSHg%}YI2`ezdWHGl$9^Za9P9LKt*L{4 zWV9ypbjM3MKL@|8--nyLP+bX|Qk*FSu0BpZ3t&{sW2)7R4ZRY~pxdzWOU%laI@ zgz@^R7VYDuC;A>e@o>B4fv$bxpUo`oikig*-*aBAaK7&T`lISn>u2gYQBhHUMdj(Y zvE^(V>&cg|^RzZs+I!vKZ>5WSr2D7g+M^{00LrFmO(HI-jE%>06IzqI&-rjfCX(D0T0VQs?8{}p{Bj?Y;+ zsH|&r631>XY<8u|9__xw$E!I*lP}u6)8TsSiue{{(98A@mOeXOJ>J*R@G$<1j4O$M zhVAzxR3;f;z19}ITho-^)hT@Vw60?kKXI}TC!PCl&o2iD7hdD%HP7jGvi&dF){r#w z)8`v+*&lbStI`;who@w@;L}KY!e!wm_dBn~|o^Oo(0(65`|vey!Y7KDP9; zhA&m8+s_<(?d=beURj#o@|^6oH~HYeCp-De*=Krw)6t#&N9ZHh?BcHXO75;HZ_ob} zwLT@Wi4^-|WOL!mGHrEv$@;RXH6KeoT0I%wX+YDAGmgRchMoKD(EWXzZVz>?P8;02 zrb}YhgRrXtW89ZJ>-MAErPg2lA2&57|C5p#K2146@lEZaCr6*Cs)nUh48At-*3`MWPK>bPe6^V8YN%ZEo^W&ns?~T^w<=*O`R-OKnG+ zW_8NzC^Q`udRz5aSX%i}t|m9Fn3a+Puf~5CH#7QZ{L1hu$F}^=&zo|puHOx<>Da~V0#>$})@f<$ITX6i;|1H)@+pK7+SF+F-itgP8=o*GEhu`p zucUHM=_13~x90Xe*!~a2<){0vgr7ceBJjevs{_iqYQJmJyqofkJx%_I3{Yg+de(hk zu&ZD~=}7A)wq*dH{9Z~;;9JZXuOaDLuTlMMEtk8FT=N|c-~ZR~YnM;l%`Mfdzeo>% zb7Qx~EhFP!>%yGP>edw+bI0esXEba+Qp(qqI_`1Fx?_PSLxa+0w;s{4c}}a4&8AyV@~?;&Z{E22 z=$oR}b+f5VLv&J`tRI@6%9t13#Bg5t*1EIiLG`MNu{G;0Wu8B!pZGj|N~|p_vCaPG z9ik2i^Gm;coP2lI!_Qy5S8pJP17GM+FDDOVUEG!l5zeHLS4zDMqPY>i6m= zX(lOJig6y%dCbww@s;C=eVXHlMsq_w)z!sfI~9g=VFCg<`ol&vVZ; zO^D%kDmSTqQNF=m@;!B%9Gs(veVM(pJ;AZtQRkZPeN&vzp5#xeR%-g_JlY4kVcJm| zqk5+@k^NHa;=3unVlQ&b6T5_+xyka;j3~2l8hX^Aw8}`xJu|YDG^@WX@9^;Gcafh5g$2VyPlR@gCJUK1Uf| zrZj`{hA7{9Axm(2^Sm~1E2=_l6K497DTZ82S#1%snsSG}+-@#Qu~iYpcjHI$9>oI1 zOD>U{#xA35sX$BCaq)~%uH6t zo#JLHOp0uNEZ>~Jt{9=X%EfT~*on+9(m9IVhfw|KQ9_td=T!>bgkOY6-vZw#u}oYq zeNSk>-?1#k{j(HiMIhgv_v0@px+!*WDlUV4msvpBQ@!sU-yWf#Q09H+ed&#%{tdn( zzF);QlzpbLhuC!P2KTullV8YBq#r>slX`ze*#n&bqIWy`J{N4>Z@da`w)bxZb)S4>$xVZqn2cOPI@csGayg&byVhy*3oz4u9!o)ydTVa7W(p%y2_pb8hdt$x6 z2s6bc%s#Fu?^Dhr`PogijyEe?E7lV_Z*#(3A0mG3o97$vYvn5z?g^)bK+5+%^JR;- z#1Ya!%CQ>QvD^c$z2XixoN5tw8$XzuvVPI4p&qwQutwfjN)TIh)K;ekgv<^736Suf@cQ-1ifC|{%`D~xv9nbFWeCo5iyBkpuK@n7>k?y*1`%eA$`MLh< zE!LA^=FFLsd!PO7?^|cG<3cH0Sr>VYlxM%njQN7%=!(M&Xt>&oU5=gh{~^tZT9t669LUc&@~LHkkN zT^+0ExSu2~36r)1)$k4UL8_8W0

*ZU+Qy@AEmx2~^vDvwmWee6n3nyF@doP||X{ zF;6u`8>uhUZPU#*IE(JGSPMt%)#fiGkz%#+0;~obxN)E|-3LbDDZo>0M%$P|^C9+f zhYnVsQErR6(zontm8+`Km@Kv>5jB{WNmJy0NbVt)!W+LwS8p#8?R?KPdba*4ujru%WPCRbO>RGz3$Dzwj;p0~I>M137CwqWfN9O`UmTACEM zB-K;`v6HtmEYpl{eABR16{!11SR|QYwaZ!bOz=AHqBrl!4XWLd_vFXMpKS`O8deYi z)+KH?JhR+?ILxqUW>yOIh9lan<`R`(lfEfJyUnOT_0mgLwayE@>b+07x>{JXMU~cB zC25fv-3tnuy3>JrE!h4OwGld865YAICXfAA|8@JY_*N;{A zHf><6Ej7+v{bmPW4D91}S2nv@k(ZIee`Hf96!h2ZQ6_rc3gJRu`CW3JX7*h?tV?g& z2?{L_Ysc0cufMMu%lpWKZQVRx1xyb+5R~k;NVdAsJL}O$$G0^fU9;1hUs`Mq2xxz@ z{n*eqZWGKzHd9quv$Fa^)sxy;^=ehQp+%f4|7rcmb-drW5M97o*UeI6{ik0+AN#x$ zlcwhR>Ktqa27hXA6L}!ygiD~jjnS_$tEx+7ZpHbU>2>w0A*KpcpuA?k!9x+aE;!Er zxzk2UsC|-Y@o`=JtK{(fYF(7gyrAh(HzIF@`M7&3l8r+egz{NsUrO1^!rD5O7rTm* zSiEs~;n@=KD)^9JoRb3`RsZ-`eB!S7xu4GF_ER@lo(eb+`6a4v>-}Dr%)9Z6nvPX| zES*zwrTjqE>&9gLOSDZ5&J8($t=Vp$qfcCGq#b3e9Dy2>`&b5lrY8`rQ8Ub)Jj^~}M zDmJOiN$;)^6Fb#+@`>o}@sfUDqxqhk@cB*bhj-tfSEYzv4h4a~+g^yuZ8s#Oty@3E zUY%c=IPg(vuRVTH~ z_C4OVy3^X2qwT*39JZOoT`9l&!!~JOf@kW6oUipusjV)z!dG>b_u1X8CA^n|hkj)4 zu>{Yj&QIIF@B1sV@rtaU*POP-xVmocaS7qW-QH0d)xCa55{ADzmO!N6DA#ba9RkCv zyPqF4zklnPPo8~*nT1aiq>pyp`|YG>tjCcz7u`<>#b$)Lkcve0gmt5RQGTktQ_p$H7B5i_AWh~82niAkbbi*tEstz z(#v;T`$avM4=V1zrNc`{x5igV?{1Zy?{M2A@t<-*^3Ho&)VJOX2eEy&Mzby^-RaDC z&(m(bc@UC#tW+t9@d<995}O^@s&ki4qr)CqHPxjj+TZlOc;T+@i(2)-?p-T+TzuD^ zz1nmh9W=%4O;t-$*qu37_dR@@F~^YacD2jgA%O##xOE}d-ETU!H;YpJ{r&30&KJJj zO8ZPUhdBS&Zeol}r<1K||3NODiGGE%5_;U7dHeaNdo{rh>X>hX`j6i@Y;T0G#Z`kJ zyU{}8)>l$d(&O3u^QJppztP%UMQaC7yJV**?;Qc9zH;ju#`yAOg+mKh)g9ONL!G3j zWLrGFyxr^<3zo*etgpnFk0PTUFh>$zoo;h(*~42IeM&qvZO}rGtd0YEw{+bTa7Ot_ zg{n&nXXWoMyk8Nbj$>3l;lU5wk1@ljFpuIc-}>(h9^NwUb<@Rf*B-tL$~;uoMtejN z9<(TSc-PzQ)XrUqvgY6_uAp1N<-F2{waCtTU*I19^_G{p9mFB8?7qf9l|H(LwD+5D ziI0}O>HEni=dR|hm2)eXn5IZw=p)B@lyl3WnxTbMAz9r=byumexoW5LOY=EM-)xzr zu`&PN!)0JkzoqPnpWB{=#{0g1{ItinNwt&cvthkD90_|He#vvCY!<1kIbYDPd{6D} z`eyk_#UsmcAs$W^;;ZHy?K6kF{Y+gc_W;p9w@0e;=T}cQJv@+>T0Pq0RLHQbshQ=0ibdnLR`uIL`zQ_O57({drIMZ)o zms-y!67%W>X^BshE^fc^{nO3rA54L(5aQEO6%!DwvYN-qnmX66EZI^1x{jkpFw2#h zZmnD|P-XhJ!bE@TKK>mtJ@3h{)%MJ4|766uJ-2(MJ}&w|?XaHT>PF}B9qoemx`vC< zh8-1caywLhCgL>rEOLBiQy40i=1Sp zFX_#I zBVXaMsH1z-d;ciEBW`aEQJ-w?^}4Hh`tQrD$@`jCJ8ui!*yeHcoVdGfjdo8=HZ9Al zQVRb|`%zWd6iZ5gWqFOPqf?NxPh?Eg(2z;K(YBMSJ-@^}JbSa>v!HilzHc_B+u4O| ziyRRf6%!k_&w2*ht62zYhZlc-t+`d#**M?ksaw6-Z|f%a!pL6HRo)vsrdoy9O-f9B z=<-PSV$J)PKduO#E{HIBVtxW+pSKYJdPS*7A)0=u#)|=AoUb-B&9%gOh z9UnEPRcGgPr$=UDY1xO~FZ;cJnxOiqDjX!Ma*GNGYo+_;`TKxX_``gKr-;YcBUSFf!>6+uYH)?ig zyNDdSbLJE+RlUeOkpH}(p^-14*zJxAcXN55b6!9|1nm}W8E(Iv+LE1|`ZQ(i*BL1* zG8F13%C3&1yt}nWu@gfZY#&+e7Z#U4{5dawO#YJ!W9eSWI=5V>{#IF@uft+P38xDV z?`-Gj&t?xx(WY$wboay8+#b4z^3JYdAs?gF(Wiooo&1%*v|Gvs+5Bwn@9_Ml=G$}>lVtVMV^iy* zAf?X_&mqn-BU`aKOZ#m>l4TN;d${2V|F>=5z@Ug*txp80ygFE^_`&t&6_fL&1?Blp z^{d1Wgq`J4w-uqvz|%e%K6mW130eKWMM7rL=bvBq=6$L9s()sd;kiBNLD0RRCU4QU zHEpRqQD68wxcFS*>FO!^SEdx{7KhfJ>-<-GAM}3j`daF1xLBhsT>f+0_rck_%N92; zL1xyjo_%~R{nq$wcJ6DwOS}b%A{Q!hijP;;sP1YSU`8)@90-awhrFhGT(wR>r*&6r zQwt|$Ps-0Iep;QZT|ln{+A-SWm-i#rSlg8fHKA4O8^2c7S1oL~+we%!n>Zd@P~oH(g-uGw4STU1i?qvA}%7-JkGu@D^&x~y}3?zqs(K|Vo@HQZ_Z+ECCq zwXVA9oc9T z#L9;9oz<6B8>zmE$I3H?QgVvbVdZA_D7%tzx2WOP2zH!@yqjzRUxj8Hj%ZezKHAKa zs0l{$RQ&ASjN*62hrM1R(hSvO0`4!nQAyn+C z9jod`zLeRTYKe#Xd(EZPHjbB7TCE_ah)Xmkl|j5km&uzfHwZu20Xj#j4ZV#yL@qTZ zsd}1JXoSQWX_SvG+oKzTqq>tiSdz|c*Tr+sSS{I~;DsY>sp&ISZ5~WB{0+I0v(ZS6 zk?ecLB!~0DW7AEwHG05wXAqU8@6^1>IE(yC`dN%I+L@2GIUr3nSO|Sp8TxT1FLI&c zCp$%W%(SN7k*DeD-^SgOO228`y~5p zUBv+=Lbi%e*Dp5xVqeJ8$V2>3{SkIoq8ZZLpOLl~j>4R3_rRFxuEoevVsA%`$8>%@OZeO3-;B%}~W= zN!AOlbggs*e^!%ZY7#UuqnN^WmnTSHksl1Njh~Q)I>B5r6%ZCeE_p`H(K0^Lcv5nK z+|Py+x9O4OVJ6P7oUf5=quhCcOl05a9?)}4&0Ia9m%kx*5r6BmxpKyvct@ohd!bFd zEqYE^DoI{RI2isDCrQ3=t7$)dKgna@sedBIvuh=jC5u2Q@u+D@ODn^6a*!gIw*mF1 zI5beQQF=tUBVOY4#4oB=yUd6b7wO4dx}nC@QFe)3Pk2gBuub~D(w%%~(N8*-UTMtY z6Ai)Ae7Zu|C7fZW8g~Gepn(1=)N)^VCu*pC3!g6hFia$mP+o9SH`KU;4&Y|deS~PC znyhAK7^VuVr19i9ldmyew3RJk)^m&a>4d-WoJmVAk=$fQin%6xX#}-ccq6XkDj8pC z6Ux)|GpwYOC1Y7PzKVS+%SK4N!(Zg1Oy;61{h8cK{Kxc`Iq_+xafU&R4WmI@IEL+` zmyv^LcV@OY*LX(UCT^1S% z$b!t`Mw6~wJ>QEsM7E-~6P-nOQh`45PJrmxK`kOyh^+(%;yhX_Mj$643e5l}?qrym zllj@=WHf@DL#Tn-vlsW5u$Cw%5$Pwq6wD|;bRNol1Sh3Zu~DcJJy8h}CJY0v&!>U_ zr^If6Z0QWx6*sg&=t;~J15pX^Yc3&Lgf8L;U{Gu%Hla=Eg#ZeQz=1hH{3w)(n4f%` z=nm+h65#tRMVE=QfB*>xF3B-~ahU*|kq&_Im;@)A^MF@#E^u^50B<^GZ0t;A339;Y ztRiZN1#n*);6Ij#yMarTAihEAzu~0yI52qM2VU{}#7lU(3$SCJ0u0aq;$Pws;AXZ1 z+oB5~VZ4FkbPVxCoC5rWZbVz?gKL1ckr77$@3R7UPKHBi0|0Ha08lykz~o;7*E<2? zCmm2rID-uH0pqL-j1Ct+O=?YJPi;+h0rR40Ex5{ctQsd z*P(2hxG3Hh#{$MC9hd++0BgA|aRG2aIPbPIFo9yMVFqyZVfJp!Ip7L>uwlUdS_3Sp zU7^-EQ@SmngD9dHY90W{CU3wr{b5mf4M-s^aAVR?Pe=Gm`v34!81IGi_WxF4gS zO8SAs{q+Gf5=P-k0f$ior4hi#$3cCXfc?(~ zkW4u90ORX0(!271=sAqwZG^HgJ`i7OE&tbl7&(dA5^$amW{txrSe)^Iv3M9Ei!%-|G7)Ej z;H(IYTGau*tO-i}!*7aFzL+@>`V@1AG`R1*2jyk{=^Fac&Am9OL?7 zEIj6Q!&#TOW*DdS2TP1`kr*|H+Yh5t2Z^5KSL!Y*UA*bEH0zl1l&nZgUo zjI1Xqwj;VODPh;~8u}*XZmNf~a~Cqo#K1_OO!LArJ{EyKB~@%Tt?ECzfJ&pr&>y&V zVhbT~|529(XQ2UNH3f!Cq9s!(Y~hCS&csf-Ojrt9l+THgz$g0(CGsXD5ndu4FzcQ{ ztN3n|6+ex9EToE6=rcErUe7Z0bU^*wM+=ni%HEn<zg8p3EXXd zG8sY7hIL>!`8P+yh_57Fi0z^UauLU~!-Wbl42=@n3gaX*Bz4Aeey7Bni!-&S=c8Ei z75&t5Xl+OBN%>wnf_+aUP@zHuThASnY^J)2o4HA(5p5#Qpw(jTKy46XNIM-v@Urcf!+K)k(Lk5mnomhc)Bn3itnmFt>g6VjUk*1YGx8-g|Z&f3Q!tVb0dw_+T@ne zEe)#QEpa*r<7{pgv50P#_{#Sv&MF3*39=c|TsjBlufT_xhL{@J>-=QmE~S*sm%oNTt=Er1Wa z0~^9oWT3K{m9h=em$WZ6jyM4cL`Av+%?izPO^L=uuQRp-^kpnsMwQa7B&{T0A-Y)0 zbcGQ&pX!ZV#lyTwAW$U9Q!bK7=~BrxdMnx^_TeuYN9dR9oOK?$i#lh+BhweItFVe# zLweA8v;%XR31nu0ZgU>#Mjb=E5FtP`muN-B&@2-vb(46}2hk(pF!$TIPk%r+T9>H1 zrB@lcvcvcxVjq-Dy3nCa9CMCo#hB<>)MA+LQgm5J;|~i%h>v6wHH|SzZZpTJ)vyA! z=jx0X^_jXLy_25RN0{!j&Ac!17R{qB(k=89#+$iA*HR}bYjQlAg}#Y8(2oAdCyBA- zL+UD%Ai2jRQCra|VJ;^#DGh7%)Ah&orH03*8Ce27>=93~5?IrIx^BKZxJ zefRReSiv;IOutKzl z=y7jq6?KeE1G_y{NaYuChd|q^*))tzWQTF1_!GiR@eHvW`IA*-M`|0joFb_ZDjPjT zN6=`Zn|M^n6`I8|q7gkKr;-k&EdnJ9p^}&K3%TD=lV5B!_nuqA_YwvGMm!&^`$+OO zth*%jo@^%7s0n>W2vEtB#GSBrS)#|thWv>}!b;B&wZeE|HlN2$;3BzU+yRaNm7;z^ z05HBECEU?V&=eX^PKUQHBuyv>T|(Yy7wk6{z?j_**7)I|%+nyIit7NUtryZ@?cEQ$ zSeJ#XLX+SPdPZZx#@|cqB0dpEfi-^*u@5lZ(}*QtLk|bMeE|Hhu+QNfFAne-Ibc0$ zfbAVKv$9|fV-6Ucm4vf)bYL}U!GglP7Z_WQttia9Vh8yJ7)uZQ{*Vid^JTEE4$je# zgPo2!2XKb4Iph{lz)_7k8|uKXz}GZj$6@X!%;JEvEO35P2K-(F&$A-7Cowmp3TlA! zh1$axV~!&VEZ?&KS&1 zHi9|$Dt=(;V%t^yzdAcYsW_V&=PqKV6>O7MLQA+q&2UaRW*TsYH~D}?h^<)6h=_Au zFq=H)xNw8N;X9nc?#G#>7Vrf)6Y39l3eJkc*#bD91v7Zy3>F!@=Z|I$3AOu^%Z+)m zFlU4X_$`=K7&C2KK%MO1oj6ws^Iu{c6=ydh$auj0f%EoohQJ@DEqoPco8VkHoDGCI zkg#2gb8>J-1kR$xnH$)$#u;Ro9YKUz;=aPnSU4*fXGZ+LKZWxUF^dKZ&;H4o!~Cb% za>w2k&fEHvLx?SToKb{x6>;_p&hh)hT*AP2;o=#p#?6xyEP)sE&hx&Mp)Jm?L5x zBt-qgE9gGPQ?PQSGT?gxUgDR~9Go10*0p$+s;-jeK%n%GGwgRtOsNRs$7s9v-%F~UZ&JNXxT zf*NjWA=UsMC5seH3x#cB0&M_mO(8BuGx^=pA9&vmemm&Czu>Qe zZ8@H=GigApY@M__rxN}VK(T}N;5_KpWC%af^i3s_q;4n2t8AmAQ*OsljA-9c8p*9Oz-pSMDR&-;U%`U5IQS`;i?XxlgGi zXN)`8wSqVEg}l$E5CPIo>

{^5hiE9Pk}(sz39b*j@J4xQ{_*?2P4og`G2phA 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 p-#vgR7bx7N6B&M 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 WNRDsXi9q>3(jjtuO3!{)&;J8M*I8x& diff --git a/libs/spandsp/test-data/local/lenna-colour-bilevel.tif b/libs/spandsp/test-data/local/lenna-colour-bilevel.tif deleted file mode 100644 index 9d79aa868e5a66cc5eed3d360ea28066a3493039..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 990730 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

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

ZA7zj(x;Y;uW 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�UK7={OO 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 z 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 z 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

<6qBxohr0<48>;5F?Q70CTq8d<~GR-(rDv0{y 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%0DGlc=}c=#t_Z%t0biA_qBYy1 zxv?XfjAKT|SGLDr-;;cEU+R?|$+z}pT-ug+8PDo{sh4-eU)mlww=I^e2I@w+F5vV) zQw&$I4kKArZ_leIyvJ*g=i+% zRbtMi1Pd4$Y-Seh@4C&?4IYtr1A98HcgMMoXfs!QxA194d3!S4|9h1u2mak&f?oui z=zHQ)Rh|qHKp?7sqrtum7Xcu(4oZtgGa=? zfY;9Ek7SsN;2c(P{z|F?ZnB9M3!xe0B7f}Zu;USn)cX*8iu`~BF+pIO9OcLRl>RuL zo=9`Sg7d*jq{_t_;UotZoCx=L3(H%wsmPyQoKa3z;`M;YB)4>}qh3Mps~LPbtSNleHwY)>;nu#(5c9foUtdVB*#I4L9f@Cu_FQi35J z)n!BwWOJh^Wjs5sBQdNqJ*qQ3ynlV{U_m0H@G%SmJWKQWAIF9ekv;0_ zUY^E@dg>=4j16aB_nv#!QGTaF>VS{4=A}_-aKYTWG&%fsW@>qM?BkV7 zZ-yH_jtf)lud^e+T^aj0+Vy3;>HmFf_^&rF|9oxcw@0_XynHxdXwB6n1lT!5*gM54 ztm73nAVQ8P2V9XMAnX_VO=58{^|GYlFi@jngqpxx?_dy;M^}nneL_f2LXc5P3&Gd9 z6P<3R8rhai$)P9CSZD_K`u%A#7O?qK4gd!-xs=Ok+@se;38QF21B&8?)rpZ(zEn&`i2F;tJla_;IoPzkuAxKf+zzV1UT5K>}*4A?7#wO zQw3g1q!QT491r%u`5KG)*2K`x)L;f3D3Lo-R0IS9LKGykTaxjq7M64tGa}(fL>zr~ z5Me7a7CHx^ zk3oZmjKOWypS`VDQyK(2J4bqXvHyFlMqFkq(}$>G;FMAhaDT9qi|7%dARxi+*3P7R z`_u03OBD^G?V>s$=J@uW6qu!0Q^}V=0JI|7L>5OvP*g=21Vvz5v`b5*3vSLRuh>ry zLF&YF#M4#Of!1r19UY+(VNVz9AOz;PZDC9Yk0{=L66<$!MYP9>_El|&csqlL2Bqo?V8e>6x zYi3kOK?3o_CGkNV>B%5#Oj2LSj`$%dNJ`f<7RBq=hqYw~H0Fd?6(m9FnBAN*x-|o- zay{NL>5+!@v16N(JCijH(dxQ5HRMubK}>gQ2(ieWnJJ_p7;?g=x26piWz?lc*Gkz@ zZ5xvZ_G}nDc3|Q_(fonJiQSndd}4ORwr4^u57-))RJvnN->Cz)np$4BRo$<+IA6Tu zr{1&ACuVL`U3^p~{Zw=8W9x}0J$=v3V{c~7Ol5CZmppDR`8=ZkX?*bOkm<{C>pOG( z+ws0v!(C5J`lp7L8x?166rWnw*MIKsk%%XF(bf30t@?7AG+AG}Ja_-yrJHw~o93iV zxYfNMHQ#Hje%X5Vi@Bb`!$Mcvwa(tVUFIiU9WMv^o(xSq>}_WV{bso7<51V%W(P>U zdD2<)Y1~ZY!TrwGX9L~uCdS|`y&tIj@zU&12-(KlUSFC)mG<${@bbjKU(lMp8Z^B! zb$=Qiz%~zi>yJ|ti)J$}7)uiq@1`aRQDgM+X{_h>Yg2!_HT{(F*2K9u@nOT!4m|?BBf3V}9*Rt78y<)2^^p*7WQru@;arVN zN>j4fQpLOg?(a|re0;n{IbRFkQRHKETu_{`gv@l4hTZ@*f-EZo`^Cx)p>SYe%eM@z zk1*wh;bv=E7txa)+?^TRnJPHdMEmh^;8TMMB%xD9SS%58Xm6*nvk7yw4X|FRwqGlG z{Aq>ns_{>XQdTLD8%QNT>+s40Z$s$pmb%Q4Z(F34sLDFN_>m=v(YCja*(--8bv zJG5vVSrX0Q{&Sq?EKh@nNdd=sN&)wks{|IX!*k8o!u;n9&!HW~8Uit=6?BKzDpvdn zeiHGQvg44--Y(GIj$u1c#Df_DxUN_wO9o^On}|>QZUq>@nV;4WuGBtuj`)#!+mU5s z<>hGWW@n>vbMdCcuu}xuDw!APZZZ_up6~~WbVmYM03xvMbB~My-~wzSB#7K8Gl}`X zmj!wJ{TL2)#d~Al#(qZ<7DGG03Dbz?c{hL;!DGm;TM`p2tp7?84ZZmkf#y|U~T8P zK?#7tJ1)N7R3^k(dL8s}J&FNnkQY%&LRR4CEaYb4-kiUAKe1{4;ID+{DZJ^x0w92W zo=Gv+3E7j$pR{N2gr?k~3xwxRrNyM0NwILWjv~2OxRO#4a1ZkWprkrBxG6QZH^r+t z&I8^yWFh3jV8JmT#W7DCY@|sAz!wZv8ksZ1B0%yM9(iIY9O+MN8D!D3VLl9q&qoH3 zx>KGQb|yw}ht9{UE(Uw!km>Lm5~w5ZY)b#t1UrVyUhOfSwS2iN2vT8bUY*J5x{o1f6MA$>sF zQ82naXKr6EK?CD^^G5dR#y5(dgMl2*9Gz6S?&7ws*Xl~(?<{pzJkpz9H=UU|bLc_& zUiv&wyE_-#J8o5SgYMpiUUHFJZdKJ{M*0idU!#8N_^!KECCmMt z^Bpadm8G|8jy-RZus3==JhwE`yEHllWA)=`)AGdVeIpvS+OOjVL}$NDjpA|r+}QGQ zy#Lc2tX9$unwO@>7W=y2_f~x-uwat$cI)%eiI*dWx08c!C#0cQgS{U{2bKr)pT@dg zo9dA$V~UOE(Z?$jFNb@-ULJWn((!J%_2Y~Y#lo*w&40Z!_0Lakf4OsGTHpP{mK{ut zjzxS-f2&6_u};1Ttt z1okHTW5hsDgtiaeA<-cg<70sZ00GB9#)g)LG2LRZ2opeN#AW~-Kq8vn8b7*0+nW=j z&kCZ$(v_j^&;>Rn1;D9eoQM@LM@7{08}TD{7PDipfSuH9#eea)S|Q0@Z~2TXE2cyT z#MVB--cjq|h>00C1)Tf%_?`%LEs6C*=hK*=ViaLaRr9)O>QI#qWc>jIqR*8l@-7(` z(8L(ZQZW-|^XK6IZOIKG3WuR|l{rgd0xB|}El5bTeK=WdqdAcR3pOW@ZcG>?yJcPU zWQLzPGomiqZ?BI-s^gmAHQ&+SB0W-QdH(|};1n;nhU8j65QVI4SpSFx)Chmn1zhv9 zv13bTKWCH2P}*hHY8eXv0=(wL5+i^${79Tg{pbi;AVBW<^IaVKS>nuZ(H(#<+zG6> z3q`Z=rVdajyzFef6%IZMMX0y8zoS#2y;FqJU7FvQc6(PcSb&Z|Z2p$I064Iy%o5oA zS$qjlU`)WBygw+cI5hBQV>rYm-8JSzRiPf|1Dt5AfCc=Qk!zNtv;utdRi)SR9LmzQD%?SDkIH_F@)nv8{$U z%90iL+)3(_To;H~SU=Z8o|ZTdZx^J>EY9Wt0gKWAaW8&E0ti$@+=S(&c6m=#&e=`Bswri-Z6MO9~ncWu_0rCkL~ z5ym%bFYjJIu{GDUDYcuHQFipXI88}mf$8k&8`aXij)srDZBIh ztZdU#NB#YQ?%7uJTx|(={%AV+(_jnca38UbZn=1?rsRI>32f&+nA#a1JZYEpj|PXI_0&B#nwAGUK8}wp5_UFF z|Kr>Yi12)D`0G#w%CfhkEuZ@u-_K1g_IJ=ABKUw=@#k4-l(EKd*T#RE>subGUpCh) zjdgsvGVsFO{{HgN^P#p+mrSqCjqgVrm&V#Y%yfU6?!gZAZ}%?$-!Gs1^Yf>-dW?fdM|etn!vf67#&Is)5NTl)YWWfa1?Wb&FwivuH3S?KM$K$XnB0;;lN~r<65Xj& zwIv5ww3Y!JjUce{Zl_0tUK-95EE4n*Xv=(7{W%b=8A4h4$jtr^7O;Zs9Yg3}*xG6A z?Nglav>_eS5#^{b6^ryj1;lG7+MqX0oc0j}h#=yESSkX500FY7SSSq&LMaVKa@BOR zWUBf7aK1t5Sy3IwqKvnUF_VF9IqTo*t=1_cE0G2$y>$Hz{sWE009*m5@*zmET*yFDF-p?Ic5m>;m zV7HqvV_|%J)K{d0TXLP8cK5oIq5FRT?*o z@XiC13%C<_Q==ge9@%PlT-;CkJJW-@z+cPK`;?$H(YWFrF26L0prS5_@IB~DM4>bK zx8o7Q+=J2>-UrPobP^}LUCPvcgxVj~cpukzRcM3iqJpHz5D2Iuo;kup*b+yHJs!d4 zP#itdxH?_@g~X`(bkXDIjNcF&iR)=;TF9w*$)z~Ktv)%Bc>3zxgdbAF2`uhdpU}B3 zu_aU6kQ#}Rb#-cJ+lKhA1ne}z8xx|q97qix$p}ZAX39$iHJ~OERo;<-?TZGd0NgHU zo^_;zb*4r0BQK_f)@O#pGVRYxgrv&2qA4%FYfI|jx|s2-sD3FswlzCiPkLdYUvFMS zL$X#%iYv}rUwP2#o+F$l{KQuN;FS^fTEBbD>XR)_+?!wXevi*;nT2O>NXlRtzm}J7$8W*G`bK|4#^N$T@UJbN- zn(cpK?j+%W;^EauCmwl=gY_?mJC;VfUJkWC?{9fGVfy{%%>VW5-cMJj?~V^1EzAsc zrfpyqqp*!~u#T{^L6t^bknQfAWpRBhpyTTAN>Dg%jiNLTbmr^>mzcVsQ%VjHK08^0 zGy@!b!vcClIMh)WaPnu*mjQxHuFE$?MIfL7Z_@Ay%u6@LVFC>tz}aDNK#C1WL%@?D zQDD*@=)~+8EP(vV?hc~_Ebv>iN{t5v5C9yoM+VwCP$RHpP@qkOF$G-2G$-troaqV( zC9>L$vl^+dNZ3WpO)3*%QU9)_GB+(tR zU;&O3clPSQ0!o8RTQRIgZY-t-@)e)~AYed`eJw!1nSe6{K!DV|F~*}I+P#MMiprUW zpzJ|G#wFOFuCPa6fD0A>mC=rNlm>z`?1Wa5$uJ5t{3r0BU~25)w3T_YyMn-iLN|NN zC1fBtsP<)WT%@qx#{5g=y58Luw|3e@3_rzn8ej}<7h zV6cE;fk-Qe7QqBu;%j=^-;>|CJXBE`;anc$(Ujs3RkU;I;7wN=6AW;jh*lHAa5&HlBJJrg|Fh&2 zASe!^6j5PSLCEAuZNMqDM@1+}2`a?PCnIpB3+YOZtci;_p$$HjqNz)d!XE;00HfNo zx(F(W4qZrllKOOX;DH3qiR_TZY(C^t5{;m$jL7nJ@l|=z%zROn_2$N7E8Uo^Y0ro? z6(pkzLuG*37-MXrFx#@@EP@{uLvmsc;2IgwpruCCriPQg%!#c!B?Lt1NDfAFfmp6I zIfTe#)4BvxRvdw9RXN0>iI_8EY9u10GD+)Il^m?k)%EDqrSaiXeByCkYTNc*^PQc~ znyQ~w9DdV!@@2!>$1T+l>M9=gG|o3)gc|yGXy|r*RZBhRex4itJURA$a_G(2w&>1#{S>u%sFSIraGHyKhPwkJSQ!hj{Dna$k}Yt2OHkFt`Ls%jzHojB{)JCZn+SH0yxSuxMPDG` zV6&EEAlp8db6a9r^56hDmkbKDl|T@N$e;;l>+TePbnT>Df;0qn;6ZUFguo7GOeB#X zA&N_NQN}nb2(s~Ay;5Y^uye5w%9|H^B1?3-*IETTD%Ey&VRqIQ^_e4lLkk?Z(D5zR zVhyiqO;VvdV{m}<3<{gYSwf_feZvBPU@)8DVgYq%3dpf!^OtV|1ZWL<#FRkthiM8B zFhQn35M7TP!Gz)_qjDt1s1!`8J`EZN+81dGYxU|syRZ7QKmjYX1FNYE*x+ z@^8g2#xKL>Ef_tPu`u_@cXB^h@F^7r6qd?C?CoseEQSRF2v&(vG~2%X{Rj|b4FdP@ zll~nR$ju_)K!zOtt^ybA9l-*CfYQLrS{dNzu6Fjsr#i%5sj*Y$`UUQc&`L~=<oqN&`l?mfTGTx>QKa z$S9+0L@@%3l}WS&#gAeN4{B&ajP;I%`2Y$8@029ReXmg;3l5MHBTKa!0vV2~ea^*& zSB3=&&+3>U$_H@eq@{+r7~xkLf+xM-vB&^K2h}k_w2a6QyO_lU3GUgPuDIs+kVXWQ_DFYkR8{@<3 zv69G83u@20=yR!>V{z&Wy5L3(3R8);2@>Cu7*UoKR+kpplM{zeQFW%~LW-(7DNvuO zB@?Y7H=!~!ye>VcduNU*8=jK3QWtY9A-GgZ4gqyKQjE!?|r4Od8e4wfvU8aiOj1!;lFdxa*Za%pFO8)w1KufcZsN?fr)G z>&1tzRvdj$eR`p#{6$ak^X~fR?H3<5*4}21FF$ps?)=Nnu0=!BVt3{1?z)$qrHgH~ z5`Lz)OG_SUm6>IHQYL1eePxJsZS$apU0H{qg`KbTzNfVeqk`uhx+;I1oYOYMib5z9POD>f0;JiYj6HEGq^O>|F*Z0 zxa50{8&7&b=NV z7q7$I_u6b?#Eh@TBcp!7YtT zvzr+eYDIht1LaMG&qvcTqHzQk$kbDIPhmqLM}Oss&@hhbBxq6>5cvugNFgrAEhIXk zXOR{qD;=Wj9mq9OAcd`7+SKQSG1*6jKGp1=jFn@hxLlfM`eA z3vrGFDX7rE0R;lgWA<-oLM%Cjc(@>BC{NwbpI;|pL=V()>|@3( z2}33VZ`42t52d0&T)H@B?AQYkCVD2X-_3LBM;!Wzf(aCnJ8y35+ zWOK0S6j3A4GJ-q0+ryc~dzfQC+DS-6a=<0EK%xC=E+HR-2oR0v5djv|1#rDEU?KPt zHxoh)I76@{<34oAM{zj7nW6woBIX5b$%043$e3MSh{DJ@v*?b`1-Taod6cLboSAE&8^3!KOdA54jW@>927ifbqoLSXb?#w?LpP?;K0p$kPOR+Smb5}tC| z(X~8dYD8apD0~ykQ)@0HFecET;o*lhrG^r7(2^ob17-~!Sz3H98ic7`2%`jis=IP@ zb(!&SP200WMvBr~X&j}7pG*iQlA&Hoh%1YYJ&_Q1X3NgD-8-(HJMci-dhJ;5-5=IH zZ#cEcfS}_1{feW{`V7mx<@3G9=gsF{_v)A1F3^~N-dJ_HWdDs*8=ur1cxmVYGH%s1 z-m5uxwfy9jvYq!z4?L}v9=A8%?`nC_*7dwrx?gqjmErW8p2`;u70>HRA5@mzsyQLe zH@Cgg_dMz~Fu7uuT{@cuM4xM(&!@9lWr*Y zoeSL^PxZAwU%mR&)bw$}@P5?rZd3w1`hT2Z_Rve`XJN1n1S4pZIt0=2tFb}C&fZN8 zfGDqrdw#km@@^K!hCW}vL<9o!@Rx&~)Fl7sy}AGA{-wd=d(z$PG4#guAq5 zQ=ILyVQBli<6MVYA7%yWOWv52#<;4(C~lLId<^M+hE#7DmogT}jUeg*ONv1xr$43x zB2P?sQ$rjQ0<`hM&=HI(Hwj}p+AW;5VHU}7AW~s6LfE14>1{|<;rGs2iwLLPUbu!i z;_@G7XB}Z9vTTCwh1^Wk1@h*_C7o{eDRxFCsll+}9TkBN_QCen$gJaSL~j{$0$Rm< zu1aD82;`}a_M{sHAF4MKr)(AZ#cb+Bj0x6-jjRhb=LZkupdb+b)x>YHWFWwRLf}F+ z`sLvMTq%tFGmBA?cqp~R(7H%~WU@d@JOT4&tYwY`DT@@VqiyU$)>wP5wsKo*<7#co zf!%%eO3ziWN&oj)Kg%~7*#Age)Vb6|2|_7A@Zdm(%pe5|Ae3^+O`rh?kg!Gy6g%r!dq-JcAj1KOnru(xvC<+scF0Fx zknd_wPE($XO}?uwf&wT*U;$Gi_@x_^Hak6>4*GeLhkZcIg0U(U8OKzK3=R%z{C5X? zGAW>a#MEFH!GE3(oOy_B;V~QC?REt?qg|&uzy{hfIQF1T$^<|Ve1HSW7<{@Ul@o3h zbnnp-$e=*qrYzK_Jj92%_}Yjd${h%$@QApC3n60xgD|ohj;Y;CbQ=BktiCN+?f5l@ zxzq%@lBo@4Dnrqy$yz(Z(!HWQYQf?B1AEm8EIQptzGF#)=Y0Hl_8f zPwLE%*5^myEYY9~<1lZ`N@ONYVgso(`oeg#&JUlWj+_)k$DP?)Lv|E~bv00i5<_ca z0wJBY=pZPn0T|pWXnXZ11R4`H%}Ft3iQ+L`DVl+l$iC#Lnv9r|lt_9<=rar%+E!`H z#;VObTX!9tswz7WqhL>&)zKCd!zKgt;!SkYAatGx|jR= z851wJe1A(?zfg5_q5jmBv-_`>ow`#~dcCw%x?Xb2XupU&mU1ogIDB-~L=*_v4J| z^MwAzKr2PT^FHI7neneTXCIon{`LB`<(c6(#&$H%&xYH79B=#i_RN>*-X$i(ljsXf zB%+P69vj*p_q09jy0~DfgEjQywb6yK?oXEomnXa5PaEEhwEuEr;_d9n((Ke<9zT3J zIsRmz@8k63%bD)wsn)+fntU;?m-1tyiPm!WN(xkGy18Ki7Vm%;j188x7}ha~6Ma;b zJGx7npfxztCi=HYDZbrAm+QQ!3uy9SJxwo&1OGJY(v2Fd$e;{e+5)vC1s)MtKo1@u znB5X3j?Npzynv#Bs$q6R9Pcj-DA+w=;kPIHH^%u^YkdfHJsS>n+GU@wJ=1H#c(gWa z(HHoyUK40-2cJ~p$V@9-zEnFoA*Nz;W$%n|_hj25f5p#wRjAFH1bZutmoP2MvROgV zkH;SFH_Yd1quiR~{OA{9jY`i4IFPYmbbXjy8c+owF$M@^t0MU(pkT`3XcN?(E(MZ* zM#G3N(@`>{cnudukE{!x%GY8**OjEY7^&XrZI`^}yP!X>^83>&kM9r{+qqf`Q3Uhb z086Uy|F$lG4kZ(Z#O9CHoIRa;k$3hD3xESb_5ll^fPw`c78cMSrGX`Vh7tfQ2()t~ z-GI`7FHtfuP1o^oT-TJSY=DSB=BvFF(%j+H@h`SRq6MQ#(O4qr$X|2|v zjLCD8=x5p&DC`i$6xgmUa9B&aWs!>=JtC&bsACun5Q_(84)Hpje}Zi29g%S(#?8K- z`$Ga53gAs4h5}xW*iCSSN0Qk=v<(JC^k%T0IOwa`@9n^O{BVHscz`<|a2(iisDmz4 zB574;BYlsDxSR}7!gG-AMsXslCQLrkmpjjfx?v@OJvB)*7!xt1y%?%03sqOeM{rQk zZ_51CeDF?z=Y-b#VyM%ZcuzW_{K%c|cIX*s%kq&Usb+_hRk51+gr|5Z{>oz!-f&1! zn9=W-O0>ZY71-YCV8JP+qF~Zo8t!}8+lg-`<{0}3qGzaV=p9{%QkO>s69r4EswK-l z=yZ^vuKu9$M~_L#%t(a$Vezp05)?}SXKA9UINrZGU1Lhqj-n@Eon(ri7~W#j5^QubWT^Xy{X9!NhzheEt8EGfNH9NwC_s51_NRMvHi7ZcvIFpcG z8|+o84J}WNKb;&VX~WB-2?JAZEb$jO8A)w|z} zj=gQa@U(OrL?Gl?M90rp?Om)tda3gK)9RCNJIkNwTd!7D-affw;o`pEMvS*im+mw) zUoAdX2<)ioMSJ#}A)jc=#SWX}9{{qpjNVfx~s zhx!YDy*~NO(DS&h4mXjd9V!;!8^15wyBza7{$r5S-&{YyfoIcd}-!6#G{#>h0&gu zqXR!)yY|=nk3U|y`g(HW!?nxrX67Ds8~=Lg>VLm8cjIiqew9s%{n|(ehj=%qBu`hC z&dZ%xL7j`;27fpDvE*tC$CFSGx}JpcbxEn>49~O|&mQIllm_%#_>?mj5TLLgPHDU_ z``HjH6OC{*WpSN;kszQJ#SvUIxhVxRX?SKFwCNqOAGccaJ8(v)?`ok)hy(>b+qteH z?GRxxS~J>2zAINqY?=RV$t+WW03gUpKfS^Orbpb?PaBtfiwW*`%hwq$pGhEG?zFYKc}q!p>&y;-3xiBe!& zLI9guf2!|9VMJG^A1VW&0bCeJ^J~+%ANO>~va<>ma^64YxANqcrVuG%E-O~xP|e=V zj2CoZ^ZwSYksCkq#>{njdlo=|(3&&8X#9vlfye(?b5brXl*CrrSkZgJl^WOp9{I8; z9^`M}sV!4ustY8>BACF^X#!4o3>6hO=?jT50XaeTBK3ekWG7tnR$2$xI{B@#S1Vm( zJ$#}altumlM`I$YvJ+}^qpP#R1Qu}SXD&<&h;je|vEYqu)n413%(}WO3EeTEAOiu2 zFpw9F7LooL#6UbbnBdD;P#5M@qOylBNyq>VJ$w`43SgtFwYDLMBhrRt6>V!xd~33; zjn3AV;x*shCC5v$cvav^=c?GP_Qi&pIWkxvB5ZtI857g_r{RM`Df>K=0>%MFPPXDp z-mY7{T(-Q zy0^}6FwCh&R~<|^!p{6 z{}^}hx{5V~Vg~c`gg7n2kBWjB@rB4B<_*9aS1_aFI-g@6TpJlu9Ll!udpO*)0^vYb za%G|hxd99!_^%C70oCC?ND?a3qW(X=-ZD7OG|Tt=ydQQWZcN-?W{ z&L19n8sr4nG@bNp4012^b3QddgwkFY~MWs?y?o|{3LmwkQ6amfkihO=I+=lt0$H?jgaTchvlPsiN|0qp;-y>Zt zPMOJx+(^Irth#QkHha6h_;q{RP-bl3{mWaz1LEwrd#b1FE9Q#R_R3SA=Eu(_-`y@q zpUX(-NQfOtyt$m8v07cTEzQTI;%Spqc+pgXWyC^7`eAqL>%sQ*S_zqF?|PaJ8;e*% zpkdn|=-clfTd6C>`T9_rwl~;@*Yw-|zSmt%3nfX5w~XS? zPWwr7*+y&8v(6^O1y9==@Kt>?*@ZF1>(S1)W4-(RorlANKQAx-I6wPxboj%})X(c1 z?`MX;OpX0@Y2-M z!2+2OY|ps8^^6lno@ByvVA9A*BF^0TA&w#+Ae(@Gfy&P|fe(3(B^_U7Hjgi1*BSTz zi+*^;5fny@81tBVKV!xQl|JVDgCGio6&=?Zev_I1hN#mQ9J4=m%tlF>1Dojo4-249 zf(2GeM{Sgjk&%qK8En)b6?OKC53P*jY>eZrRnr{x*jCXymwPGKc72GwuMm9 z5d@fb1zOg5FcC792IyCNsn>XG00H&KP0NFc^RQ?N<_MT@IJTen;i?0@tvlQWH3F7) zoF;!$@+%|sls%7rXYt*)|I=RhZ`MJSXNE-_hB|Wjw7B@?p3Y%ZLrJDK0|%6S#ZZXq zuAoWrRf;!XGXA$?3A_sjEYLo71Rn|H%Hm!@Nr@qujfUpeNz+#>P{08Yz?+J1As;sJ zMDdQIXhBJdcK{2tzdNFXj893^^ao5zReX%iPMVrMbazV$@GJ}Suesn?e>p(h9fJZ$ zO8y=TMy|SZ`Bxm80r@d;9 zdrN{nYl2;CgB|LFZCafTs{EVb*5HoqCVDdE z`?@3tcqWGil!l*ZPL7+4x;8F6IJFrQ{;IloyRKj?zhE}{+-zR%e8O#X0Z)sQN8-a* z9-V&EC4Jk~JD;Ag7#nn0{PvT!VMBHWgLdzw^FNz<1Xe-!n=rak5$P9ej zUcJ>;y;2aflzwL{HF`WP>q$<`XhGggZqj6S-ey_So2I-Mt*y@*N}(hPFPkejC2Sf} zp27tk93r-0x3L^4!rRW${U+&VQ^T{~L2`=sJGz!j)8?~ozaEvbHTXC@LgXdZa}x!L zdu^3O)gUxxXm!|C@@{-iJ`rkr-Bw0{KNzUTM&h8ScBixYO-KEwfffc$uUl&l`ej=k zb*l}6WV*6=v8H0P84v4976}{8lFinNXFa84uO0S}yd3I$Jwm!c`-h3qPgCP0qU|AL zn;QJGH2vek^r!i$59{+^))wAOw|yWbb7j3IE9aDleu%C9BWJrCmgc9lw2o_Poz&Dm zsj3pLrG8ac?Y5=%V|zsK`Yf!tQcDCM#=RC?kTGfCHjS->yv~bMQVs?baD*uSa;A{@ z1Y7_P00mKX`WqIwf(7koFb8tQxB+%%y`QN93*ahYe8M+lri!Z&_dGC(ge!Cdc+(*u zuvJzPwPuQIvZ6cSxni;+=C~gd4?AXzf9#ZwVQJ^6e9T`@-S?<+sLGKWdPh+g!7`1p zR*N&$Z6p@iQ@h+-tSdH~k4))UklOdQN4{rf4|#|4bsWSKKBPww zvjRjD4Y@awoCE|MFwRlbX2s>5=iJ|^{}gZWny)|sxxJ|2za2?XyfyX_3L84^{D>2n zD*+^|5-9bG!#5Lq61fL8k6(*F@5>8#Qw8KOjUoh1G^0>a)>l?WQ(&g7j+%h423uNP zb8$*L8B}=MzxsTjEIgp)Y6yNrp6mr^4d4qgBZ5szcYq}krsSN7>)s0X7>y#`AjGo4 zOR&mBJCdH0zyVlb4Rx#%dpdV#Ha==KzfXmoM|0xrSs%kDVy(akhqt(8t5ea1;(e>(D^?PJ9VTRF)V@Je zhFvR%Q#VnO3}tDcTChCqa?G^0TfV`#bH5e2(lOou_ihx5QJ<^=`?a2u|_q` zuwz9nhMMsM@usPGd z%opBYmXvHZ)^E#XyLCA$RpncixzFp;HXCL8vO;0Iq4rsG@m5XIYIzzXeNu4tnp-!U zBriJK4%%Drrhe8|`K$#ETk}DSv`=_=*pl;QwByUv-2178&CZso@~mxX;ZOaIKM(i3 z7;Jsg*s{}*`KF_reeX_d=XQP0n;sdV1at=^rZEjV?5%y#RkhJvxYb>EIMTJzCSYkH zU9PKNuCLkaX?{K0zS-IIq_vbd14c$ajSs#b>BH4@XR!CvdGRBTV)E zx;FcHapvRd#82yspB86+T$%af&fDj6oAtSwch0$!TyR{C5MI=0nz-1V($VIYc0pS? z!a^$=nIl?x2*7TpHG-cN+gJ9evS2J26iyVViGO335@aTKs}s58Vzj{}4+0BBp_%w0 zz~Rj7sQ0YL;AKBt;>Z(j730E0Lr?^cH38OemFNo)1b_uZQo$Do3j(#Zm|-y>GUNLC zhi?SYUQIqS0SmqYf%q9YH(wN19X-O1+49H_Hb;+e+;lZDVLGLwc|lhT&In5grqj@) z5*$=mRTTuEEWLI;|G~BFs4Jy$_nVSanhRyp(vGUKuH3YW_)9lpy&bcBj4DEmnom1P zL)}_$2qBG^z1uE0w1(*Shv*Lk==KtU<8N8ztk0Y{Oz)VTvgkXi|J`q-P|7w9g2FC{ zCm_OC$`260*q$jqR#BF4IpsuA9ytmupjwM}cKJn~!mOAKi8CT9KL5zOOjdPLuH@{c@=6700kAMY+%F3(>>@>7p zb+s?LI#hzn+z2*DRZWp>*S2mlEF0~~+|!&gKy znTVONaRV(d_aN=F*j2a06>mB{7&cT%3NxYsLd{^b;W`Val(x=ARSCtJueu8P1+)fd zw6spEsh-dh)WfwkkL#+QV^eIdM-tO5GXwsy&>B$f*%8we04@9r0t+~x01zN1nxRU7 zXk?T?WrP!T zhJzWK0%k;sh=EKs$p66hop4(IJPcR(Li}+25~n+owPsCZLV>S!lCvIyp*pNl*&Vxx zn*!*jIqvp(j%>RvOZ*%wT%ciFrF&Vx;z2izXNKd&CUdDT2d-vGaw&a8jq1RHF zMJIfd1Fhp+^ciUt2H4Z9MA=w9w!&h==&`%=eJ}6(!5)=qi31NVtwwllLdP(id&zti5*|OV^u9*P6;#8cJvD3)h+|5Bl0ZP6}g(1O3l>yLWp! zHald8BOR=OX&4CM1U&ezG$Hf?V8Q#*F*e0-*c}fvZFNZY2b+GJAN_f0=F8IT`VI=l{?0>7!%a&w$Ura5O!t(|vFj#kk+v{P3GTB& zNL!6hDa}0&LNF=m3*>O%K-rhCiRJp;^Wr#&4_PS7Ii;eVwOoVX)O(%@l4nntJ6M2S zC?<6x791yJ*q&Yk9ufNjd>zwVO=4|yujq*DK=KP1TCp#nDG+I;M}81Qdo}1U@~r_+ zfClm6{O?%6^;d)g=%=U=Sk>bFV6S$}O;gqV$dNE@^$2rg{4C*;Typh~3cpa4_@FUA zey}2UvAK0;WO0A~U~8!P&0NR3*@kC>6|;3YvPaiSPq@gAJJj5`P;u{WORkXDmy~F*b9M(m;rASHyb+CDp?*cG^{;eqh2oxxwD9m3w0N;V^iUvUebyRdiW<=QXahUKk{NeC5zQFgeR9E-4wpMf?{}~G?{wxUi z9y}_*Mu7!p8XEe?j_J^`D2uU}yc_?G9n`hX+ge8jdM5{*9C_A0?v>}61ulzZqARsqEY zEWmG{AwB-sAT(pXht`bNz*kF6Zb_s?oK29@(UV{S+*70{=k?TK6EPza z4Xd%R)>ftqU`7NGus((wde_QC-ZJR1FJN~JLlepnj0lQ9V{GtV zU4cmvyqrfS+5iFcO}rau5IAUbDbgu|jRB<>0u<_CmdcR-Stsx{o^W`=p=Dr?z+aA? z0#|yRB_3HC7o9u)rsDR;qQIB&-a|gx#a3!@xTcz^GL5>euf(pJ??KrIcpwzr)jf9G zSe0b~D+4+LJgNmteP%>#lZ9+&YeEzv4K?_f*;9&x5s~)*34V--fpEk~x7On_pYLtW zE&zQR!U#YMi~y_X7jiwVi7^KzL`w=!d?##S0Cj{0mU}xTI9kSeJC^x7G=_Mzhj_J} z@@_fn*Lu;v?_$v489x}|twHYjwt`KDlYO#}O-6tPi-7JxpMel3vJH~`-I4}RtN+P@U|0B}WE`}gbZQB)Cs2g9F7Ojcs||h*)r9M~Tjz#2lm}VhP1V_(h4Zgk#mWCp zYwxq{xS@o&<;1X+l7#ULVLtWReEf~I$LBVRqZS(5XYxvxQZBD#MnCH<*lcQ^sfgSx ziyX_y9(xqN6?tnkRTwDDXwR>hs;VWt41w3P`fQAao|Y%=x3m#?xhAb-r@T;3G#m>}1WG&Kh>j z5LLJ9#ZB**F&4zKSH0~U($=N=idXHGKlc+v(7e~)@v5`nLx1P%v8jd9xYd$`RY}H* ztYA}Gu_~>eZ<4MzG_I4F+}H7DSm^mUG5CIB0Qngzwar#|NV!M}_B&g*TN;p+y&i6R zJ3MmGiv?2K+tD8SjeS}dmdHH~FNQn6EKa;x zZiHKF*dF<>j+&~DI@-R5x@Ro(Lrpa<8Y7qC8N7{E~&mhy-em(v|)4Pl4~20Sbdq@YzN_L*N72jH z^c`u;Ole$0T1NKc!kWUmmg4G}CZTz*sj(p;fGN<%saxm0mt3Vp;rkUyQw+IYBY1>ei|n)O@NnkH7&(@kHzqv&*Vur| zF%ed5)YV+Hv;&PzAG*6_p9#r3kGJawYy)T^WvBu)11^w&odfFf|2@P!rt$-NQX_SkOhga>MR)Yo zFhydU3~LA=h%rzX+W~92<_&L(Xj8J5Es|_a;JVT_pdG{8nhh^83HV=RSm_X!01F8H zbCHYuiK|tPhee8)C0X_b9u7tBj`@D>ah|x!eHyt0JAFk5L-)_ zPq4fM3o!;e(%Uxi!o~6%R|jIQvjmvGef~*qQg2?)z`cO6s0+`9tec1JjZ;P0Qwf*% zDq^u1dN0jit*x7lx;Bvfa3<#BN`4ev{^i`*>G%tSkr$8xlLR@Jet$CY@_x1OQkt@r z{BSYl>SW5ph6fp)aSs=hZ!K2Ut~9o;mSxjukYj()-u9#_b22;aMRnqCL*-_D)nQY` zPE*xFRmOCFy0BK7u#hi+1^X@Kn{{k;=@F{;q_rev?zdGx@92Cx)boB|_&K=)IL>uf z?Y35fF<4r>XsmqGRf#d_o5Ajb?%}4EL~s7H3lJ6$f1i3YvG@ zWiNVr-;A`QQrPLNdOd@BfnOp;~W4E{E%|zeF<)zniqc0g+&CP%da8SR@P5jID z(|;P1Wu0`x6d3-Ev!<4}juskZCb2gywI15(@$Zb>qGB(LS|P*^Pf;m3#U~J4*>Tt% ze^nEZVngv)zyVLF1fmufa*-Sh;P10XkYj;23G-ktzu$#dqeV z1rsf;J+h9TrtZc5{>`42=UsvnQ}dPH@nKnacR^9cnLtbhAOHraAG23g!O@w@N|84F z;SXO;AjA*<)+2}oTh96y5kVmW5Dn<)ZNw42qFPg`71wqJG${T!@1U3r=`kb1-kKc& zFXGQIMFMFQfWfe}fqX5b&sY2a$a$*B!ufGW_maM;M*xx-6|z zy}c^Woh(1&)o{tL_MAI#AUWs9ut=D^;(>608IhoOEq!3Y|N&BY0U#e?N~dzf)l5o)@FRFx&FskrOzE1ZHW9d^AJ{z&4l-f)Ht{o#RDF zu^}A=d*vi|v-=k64=gnVGj$fQEcdvc0JS_v?F>gK%~_tiMpm_H{~2#dkYBF9UtW+4`eJfwTEaZ*!+eT^UC2?c z3U&cb8vJZfNRe$%p z?l#0_s|1-dmLYPUcZ~k-ljyd(+u-&@9_)7RvD& zdXDEcf`YMu!=7H;>o!`-x0~}`cghZ1n(@D5cl>;GV5hT)T$~sEVuSE{c;L-wKQpFh zeJ$@cXMWl~_^`HixIFV=d-cQm;>Wq(e_9&4T}eS&loVxhAo;T4H9ofyOCqHTnW~ zO-%|Eax+A{{}Bsl6BJnR8&@8fkWWlREKuT_dsP4Ex0cFk_D9vMzf-bR(u_EHVz9pa z>2T-E+0BoOi@z)m{xaG2>qzs@0}XFm3%07FcQd2sQW6Hza)(M~GmRa~Esa|(5@Mxk{qKXAD=I;L)}#NPF&>CxYKM8Dn5 z<#EIcmMNnl#Zl;k5u=&>0A*CXt-~YYP@yUCiaR?6`zxj>mcRyrk~qoX$Wczb^TR-8 z4rQUH#*9dT1qwL$_r5?rQRA%v8^xLcT;Pu@z{c!*GHz6uQt{u?US0i^mDNo*kGPPN zdH#NN=T26ha&NfcReR1AET}l^1Di;gkMNqk;YFhT!W};l0U!VoNVg={c;>q2%uO%a z1aWbU1pS)#AOt|ns^n1?nAPIB&=P3g;A>ptuAgG9jx}e3sXEsB_f4tjTA_N{{%R`j zn(9uf$Gpfg(9;e!(sfrk3LIdX6{vCq6Z2CVV1ceWfvsmWm58$;cLOt`^Ty<&X`a(p zWqokZ(&(~JP9{}+m&Or>>Hv)l>mLk)XyE&P|Gy;rjxc>{5 zx=icYBM8RWO{ioz9>ohg!Q3>}!Z^{+bTT*Y|7g4ZYiZbaq<3$yS-yozypbv#p=)O9 zWOgv}C+z-?){#es8p(EM%#`?sDApxmM<>F1Atj7Lj)5Y4%nH_F~*7tJh>Vvl4sr8gBrr*ltu@#cr=Thy8}9s)FfYvIDtsKfPWV?}@G3dwR2n3z&D(?R>H-|H{M}*# z{gZ=Otr*~Lm+c`&ebV0CvCv6&usP%Ic+1niG|YYA?rA#A<&=o6lC-{r2fYaq8`agr zk3v_gvT&G~65?-8B!s`pxV+QRzLplh`1rzFYQ$b{%wEZ342UKRCv<4_YZ0^*J=tjOOiLTA3m2Q?+{8> zk$2FX|GK&AMRU`Zta_oUY_TwQU6T2>rv=}iLs^aRthEk*qKU+F*j9h+@7=A;*lnpL zs`y1|(x;Bvk3+r0;Velz)>@i)g6;JhEA6^Ura12gyY`#wpGb0{kACQ*WoU$(I$u&U zQ&u!DsU9saVixpzZusf&;KA4gab}y6r2V?o7p+zMZS*QF&l?*)5B2SL2&8m&ElMT3 z-7=(PZ_u-i4DWUHtV!z@YspKK>~+?^93+yt`9;qFMAQAAMq&@>4&IJ-V2b^+e_+2) z@~4%#kMj$kmghgO&VO8(`*nGh<-&honcI?P-gRQC{yP^HeHU#*KYgup7P?o=HEx<| zJccFhW=b?Sx??jEygKlB{>|glf$abr0d|9w`hIzsAxuMl`{gdy;+&Z0zyUC!@F!!B ztRNtXy8}GUxm);KN&PLL88Ur>=7!KrWYF0eLFqt&gkv$fWA+6W%1TUq1nl_H5r|R( zInn0p<(gYFRTDv)CHL#^zBN}mVx_5MsPwJY?^Q5X)BQ$C=ZI$F-Rn;}im>t9o!a<$ zZR8*4JN|XD@ndJn>-Nm&vgnzl@a42QNqI^vnNrY3L1 zWgbBqImMuZ*es~28mWjD){4WQ;fSq>TxHCk5*rd_6<))FKoda$p+L$%h%BRHswUs7 z`Wu;FvbGld+>1heOGEuC&-&Mg``3hd)t>b(3~?zsSvCqRAl#RGX_}2*w2AgDef4l1uwTRD z$oJm5+Hy0Zqqw9HVSw`755qbQG5s1c=@~6S4b$~=x*EU%xn@^Q_1G+hXnc>CAy^P@ zq`~!`RTm>8WV_f6(J4SHWedP36!|q=wQ+5L z+6k{G+En$C;W2X85{)sh#w)^z6D!ylrdk+*1uA0i*LuH+Z1hyeUiWM+VBwVfn6bgs_fyY;7p2 zBMdcA91}htBdQWmI~a>g3zC@eA4N5mW-Yp4#JU-9;9~KeAb?*n(i5yq(LbX@c;sM= zfdy*<33L5G`$SJ`F5?-_#^qk-*!J=y!5I#>eZITBG{mpW+a=%AuGHV9(9O2m*SRdj z5`qtMGxp*v6o|Ml32?wVx--;A7UEKQT(Hk#rW;^QTwA5Tqcq5)`nYRRpnV$dl0KGI zCtW2c@EUcl4D({4+!o^0>Tg%+YMJ3+k?dqinhyLt0%*a7e1D6K05crOV(pCYI$Na% z_@|ve(GYXH>B_0G2;cVGp%b@G9@J#b7Nm{mXYLfoF4vSl&Aj=xy=G8Iid=adJoz~6 zW7fUp(!%b%Y)hZj=IvBhER|<$R2RMO?%tB5ElW!A z6WW#)f9`Bzs3WYD6|PmM_m`HVO#aYVxZB?Tx?8#>Eh5`sry}=xL&b}pp~E4f90icOj1ZD03?p?0QDD^=-FYP07nOP6aT3zFieOY5p1?2V3n`h!ft8_OWRAJTu6P$-(?EH~f#gyT3fyd^0`y%kun} znb|)t&c5ocE4vopulb#$vZ{-w9-7ZH1}c|K)gr8Qk-2~cM9tI+EdGNn8;@J!-^O8; zq`(5!#6y=|Me<;{v*ZKQbZZ(3$x=n7eo0%nN_m8V(H9$2{IDoQp8%g8A^yv zb%RMDV!?eg4NMvt<3b__3rH$={pLu(f8O$LmU++_Y{9>tpXAF5L}?hE9U>80Dlb* z3lDyJhCPgVxa0Ez4j=L|fIv~gc_NyO3g3Ru$5eR5m&K77sy0A@Z)XFTh# zo-Pmdm0k>}JLe<4;74Fp$r<0=lRm=KHCF`|&;kJb+yf~7(1-YtHbK!TKqx|MfW81Y z;99`{ey{-FKKg>MSb%GDfx9VK08bt)Q1k_&GnSU7hngzN0)%Er4ZW3*u_-vNqlNPD zoS{ybj-YW~U;Dg)7I1LIME|m}m|t)~v=!3F50K=b2bM;c%*Bi|hC+%xG6kP)vS>pp zPddi@2&+=@7;5k(fPjNBU4#kSWc*82AoauU5pViz2dwp@E%XvhbP@EX+ndAV6#D}4 zV=Ds&_G}8o0TIqU4#sJAMqmMQgJLIl$OOqIN9lVWTj)QqvFUzv=|j`~FXh2M=7&t3 zH|zE@Y4NpBlw;s+YoqI0-$!GFYNj{1Qy3Jk#jf0zg;u| z3U+}Ti`_(~mwCRAmB6%c%srb01?6Mag6iugsT2CA=^0UkHx6Sdlg?Pk*Ko;g%ebNP!I#$Lt_{!KDlD>J_ z-0-ToZi=%Zg!Be4hZ=XA6nE3RPP$;&V^^#A6W*nl&viYHn2Wo*SeQ6+`~3K|pq|(p z)5#B?Npf)HSuRd|Rhzw0oN-VZxh51Q&c)vvd337(VfYi_%w*!jzNC9Y_d}eMA^g3ZI8pJ@-l`Ch0({?53;WQu`%yOaq@I( zG&EE+VLP=|>ypCx?3C?-$ldzNXN|R64OQ=&3JDL}t;oRybtUZ{RujyG$S*Y*o=4@HoLSx;N_9j-AcuT+S8)Uz*-&nsT&H6KSdaw^mB2;1!g=VU<=1cRRHx|Ao zC9SdKup2BG?1zoI)m9IFU_c5qka^HvC-X2Ky`d*h|WKJW1@Q0R8v=9=?{4M$SW>7f+L^+ zby{I4p@0Uu1I6%$N9HtNv4G;wHDA#YD4vKfU}b#dw}T#y2!emd0tII93b03k1)AUf zL8O@e4GXyc0|XF6d1OURcR+W++lgvtWfcT(=$~N_aZFX!T=Y$XOf4V!_@)GVmxg-P zob!}jJymkjz2=-x*-6*RGaeX?6`u6UKj|%E0ZqaDEwT9XzZSYM@&P{g=6tPW?wKIEY zVSxJ(D}XEdq9y4SV+|~<;f}Ig=70qNgd+G1EVyp08ey&p93VHltFIbqtd2`izPqg` z@io)Oxim@igfNZ~Y>m=wL_<+lxD1HIeX;m8eBg+YWC*22^<{sXYJN1+9;-Y3NcX^J zHHH7&5&7qWz|Yws^AQepK1`X^q6{=18SCHH)h2d6!OD>F(;YpP`-bXKhS>Fq^a-s=@22A--QN5ioi!1YSs0nmw0V>Y5_E9tKvq;a_Zg1*o(75 z)U(*D6UmP{@17sMe{neG)^1hiA$c-V+2Z3<2hx0aqc4TD3v<}=evzSyY2N0D2_kI{mmqML2K(uO)d(fJI~SV8_w z(xttI5&;vqo%(#z4(2P<=gUf8mEPScFWzfyLGAEVR*C=7d`bFdZP~l-I%ugoO%;gZ zp4R0rmln(ximzX+E?Sh7F4Pn~X>T|f=s{Vw-!}TPyW!J7-(g$vT6w|yrcw~--N?wh z@%ER)&6^!5)UziImG=J$U`XnpZE;+X>To_LfnlkJA>U%e_jp}M%>K)k~9eX)F^=5AR z$CbHXH|Bp@8UJx%@Q>?bpBE>7TATZ2Lsi@KUrd!z*JAd`|Z%u?4Mj-Yq(Q&S7l(DYGKCi3irmih@zK@HuBd|HH29XFO^ z423YM!?X0ft_p`I42#$!V^4QoSN*cK3enl3Dj5x$sWvddmlV@7eL;J#V_8Y*(Q?( zXrT#5h%r&3m2!loY1xf?|2Wd{ugy0;Lct&Fq!P1X4M5R1q^Elcwg! z8tYCtMKJR0i1OcoJ=9j-0tL*s~$jsX5F|79_YAs{%($!P+X`%Q4>G zF3!^<`BX^J+0)XSXXrB4qC%fUU7m}+I39a@E9Le|wlMJM;!w<$-Q4)sO|qxOcl%RP z4&txQW?UH((qccR+~`SYi_&K@&OR+mSWdk%5fwJ{ z;6z*G&Ebs43#Dl*#W4$cSx-}9aHTjX&m)4SN4U41dhuD_r9H@-CB^G`k6uWt4%!+? zFgt#EsIy$7H-(*0 zB6ymyR)R;=aNN4>j045I`@Gz1B3vx>&`N0p_|<1lz#y4AAzm9<7BD1`J6H1>4nB3b z7(qtG<&7OQ$-z>8Gdvryp}@m=STn zg1?^;F+h|!^@Mwody~C~lhc3QJ^1s=^q)stf9V5yFy2veZ3Kd!C(^knAC`t(n0)4x2K`(2Q0awzqG z-xnx$zhDHjAH{%(i$8er_gEmd8(*f!U%3aSe%*OVPt8+nEaOF8)*+uW>OAv>A*#cIb^~I}_lkM+V ze9{vZi7<1+9W0tl;y zb+Mlv7xr`yQ^m-LfMVGx^ptLezP6xAVW11Ilm)rTe61@93iK5m)7-2DvKj)M$TGva zRKmXbq+{iAdohnDz@g0BD%Hg(+C}e%trdV&;A&LuXAWna^~eJwgJ=`e2Ogf0&MuL@ z&ZXB+O+{Z{h`!bzaeVk{z*N$m&4;1OdBR-UgTu+`TqIs?CU#qWrH~>Z3(v*5>9Po-`cOtU#_iPk|gg+YM(b2 zAJimqJzp*qmTDwRg(>Kc534e<5ygmfB%oN2Sc$+Cq!rJs{P5nWKWJlKiw6Tm`@XMa&9a+&~Tg`{T zn*D}OQY@c$w7(jXZ8gibF&~wbJ!{B)*IWN_u!+C{O8bj}uHEL!r_!t^HA3!-*6JTe z8nL>AP)hz8I|l}ha$Ut%TdjP2)Q&+00t9j}MH#|i z|GVMIr|sytyv%$C$vQU`G#L zD0r9=W57R?>Hu?`2Plb^Ax-k1~91u!O3pa9(gKtNNVXbp%CV}!soiGqRd z4D*WC)3(weGi-iv46X4qsqi+-_ppHGKrYiAGxmaNCv{Xk)o_wfc2HBdQ&Y26Ru*Uq z6lBq_Sipb?<*r!oAjhb(7F8xj-rL-)J|p9BX7=6M-NDyuKOF&F9tb|Hp1}gDJ9x%dc~l&+-plQ!6}ClGaS;os7YZi{Hw$=%A(|aCnDS=*fmrvJW zI&{Ia{+u&A0tQ4?=K?Cu1wtQ6_a&G_+#rj60W%_229ww1xt63Ah#O?jsXIaA*L|@e zlD7ultP(^ZxPD@;cT2Nki}8*4)- z5;KvFH2Eq|Zdn@eoG3K8FhMjzf|W|p1;9bMy{V^+E75g5WmIX8tW6$Ro4`uCZ>+)m zhIlafEZ-m!PHBR&K{|os6nHZ3rb!AlK5z zkwjx?JM01o7G~I#iVwXvk;hg|0d`#>&TWCB$!?vGd84l-PK;6?n|cpxq{jtrRwX_T zl_4$--gY&vX6z0!oh>pw1sej-ir5$X*)@g23JjX{&eFQul_HQG~5%bQTlfQ*=6{;r98i`)8j-Uz>Yyq5t8zo;zW4(U<3? zRlDg|W^*EEQg1&^xiR?Y>_*Jhw>ekV>YLFGEG33F$0d&l*L`M_Zj2>Ao{qe~l#{$# zEQ}WvHD=!Iz3Z}k!)yG0WcL;Sz6WPV@^V%yQ>XJ%7E{iz=R_Ws$2}`g*eFUFO1ia} zeD_sF+;dsUWOm9-S;^?5uqVY)&txU@we|BAiTh=#FY43x8kqEy?6*{iw2`WGhBSwb z)x?P{73T<}x#=4zH=bAIA9i$5`G<=OpX6NIX{=qTF59WiJ*caq$gfmp&E>_6r6u=e zJzlFTT&*eJYAS!#+0QKKps5Yh(f56AD3?h_+mkh5IJ(;;dp{@=jb8Lf_^$Zct+QNc z$$ZtG^Rl~(4e;xpHlSpyzG7V>WbR0_U$)m0X0U~ws~xgk6Igrkl9(eD}5o;KDBH`TdgrO%~^ZBv2ZWnSTLSrcL>J7wQ_!JPq+P?32>UjP-I4}k-+445S|P8h_ThI5e_kyCx3XdO*fTD30( z2h)5SPA7}U*2cFjG%o)Q3(%U8r9yszm}P^9vKZyABo-^`*s)NSl`Lqk&54>9ABV_RvEtr@$)x7HHcrgm8YW1HN z`u;lG{BdQFq1yYg!7nqTzbuUZJUjT~RQJb;_7CH2Zzp@-jrVWuK_Rix4N$Qygbp2 zsSy((5#;2zcyU04ZG|BBtq=!3a!U&u3*NIRo6OYZgj)NF6Fp?(V2jz>t`4c)rb4kg?mMCQLowlx9s^ zp&D(bmSCp~4vCR$`bZi`OcN<(glVD+(;AqZ_i0_4k9Xz5WMpOps!Y#vZv6#b& zDAUCz&(*%n(Ynmmgs^*TAs`4LH!HLyO2-NZP^=|!f^GD&D{-;Pb+IGk0FMm3=}O&+ z(y@a(M0icAhgFi3F`t(NI#c#@ysc8~Epq~h6mTj%?OYLJQ{ib!=wPai28En}pnQM9 zp*F;|^Q!f~{SW zqfN4heKHaDH$sLVU4NPqxg2$4;r7Kv;Z9G&)rs_b(uY@fOX6^to=(1mN^CCS(o*F4 zp{qetkzp^g@51Sa1hkeEF)gG+pf-EOgg(-FI|&Jc4Z|~6$J|w`7n#NYbtk|nuXnx%*mAWoxJ${ z>TK@UPdY0G3Jd69)@sXFD~s35lZe>dDHoQ@GNvmtrz^_WAuY8t=V>Q`=6z59VXJhn zq4s5K&Fij~r?pj#n0BP18R?J1ZK#qDJIgm3t6sEMz33=etjd`#N=IDqWw`TI7gL|6 z7wy1-P%xXHxKfcqo&gvBEmi|VgG`5Z+MBjorQ2c#ZT$E~?Hv!mi}b$0yo;*+h>>4ck?eGRn4 zS*^yAFay*&dQ2<1NfZiRR``{Ra1d-oe}qw$#*7{oU_u_4U#s@6C2LyqOvL%j(Qu7sh|>uYB8@ zvsZ9q`JqSqb^o$QG1a*xy{(eB?cF@0PlMUT*(!sqf?L$d4m^KTY*~p6L2< zy!*pQ2OIzfa_@(_LF$94vAyBJ=R?8(|IJ?w^nIKeV}I~&e*CA!^^bF-tL^ot?6pn5 z|DJsYDg)vyp%2j)ur&Y_6u6-Hkk5CY#FAz}*6$EG^x_5{`;Ha&4 z!^I{VPsy<0^0NUg*G_>2gqAd13#>ZnTz}2ThE_Ct%bQWs_+_Wbt1cr~oF=Zi429VZpRw;le&lCN zW@xpqVWEp56)Dk711|-l#>gHbXBEc@PfaamM5Nh?_H=4=hAME1#B?)tH6}=bT7qh@ zo?4K$3KPUL2N%RuL@343In z%bKbH2L@aWk=W}p9m1rDi+O~N5pn}WXRvS-N@RsY1#})pE!aYE(0++S9l=C9*$(43 z(?oj%#euNHzCa`q*%^^jpJk&T>#7WCHQK^$w;}!ioQwMBy3p+ezrzTR%_!f&>y9!X zgK{g4Vkc9KP!U<()>3-R_=!YHdy_~TL%#8SL-?$^_{B%r=rJ#ib1)*fmp8gIp)WIxm|_Pg_FGqU>~8(APNY<{Zan+A)m`0v8L| zq17kdK>BnSgAzag>J#2g=NxN-wPiutFhbydmN+`3xVhq1QRb}Cf5N2MTbFFMn|8J# z_HI%3T6rPXwddFu1c@=8Wgb@K#o|v^>Y-U4WS4hPf+2CVTdOJ<&0@K5e5)+`UGFF{H8XixPfBvPBsB-s6#@a0 zOOou_oP_nP#C=Kf$F_=B^;MI32|H<5Hu4_!#XcHLPnoUATai_6H%dQtOZQ}z5KTYz zG|~%*YT)*U?Z$HSXmkfVt&O`K&A!hYt(LcDYrN6iv?`NAE+T0GRog~q&sICd+SV@R#yO-w@U%jeUVF+F5)r@9L=T`lh7>e($!qimrnX+w z*Ig#BiUnZmsyk<#)Z=is@rw+M?Z+-T4u?B}2poU_k;1@bkJt$+rFADyD@;q%PGIHCqYu3y&2ry78)a30T|LwU@d566XZ*`fdrQN->yU|t`&5UylT%xD z*1IgswtYckl}a zDiDek&P8JOC4a<1_aY8JrdkSPB0z!X2wZT6phBZKerT-DtsFRDS(_@bz?GX*00i+U z%SbzO6pf0Y5>fluAm7*fhZqyx2i9hBo(}sJssB3s_`SsMbxPRyO`E6pJU1`7O`dTo zbk~1i&5l?p!9(H=5WvbTL+ z_^Ij($1#x@KJT@ec(d#7<;i;|pG!-dA4cpYoLkCFSP;%n<;CMFxAe$&Ot{>4_io4e zkg#^;)Nn%EIoc9BXK(Y9+cJ>Z4C!?70(;8iJF0*x-G5Tk(TaDi{G?Y ze(I4j1zN2xeBIanpzUWAYH4kTCOgjZNLQ&$`M-xoJTEIe4i3YbxkI2E|=KM@f$e9d>_iX)f7i7U=b5jb2M zfrClhO3&K@2Vb#(zJNdgcE>CoI0(%uyvPJJhes4=qlH7u4P7N}c!XSet17vusW@n; z*=nd-s~r=4O7YnQ5txZH1kwKX2ND@gRW+`M9&ax#c|AS*dHKnYOY@(mJKwfs9OPeO z`_ynRDDQGu*0nn=`KfC?-Mjr$FDLr}f?wx{KaO{^WBD}M^>L!}&2STXZs=S4J+gz| zmUqx~M|;Ve!1m+)P$U04wwtRCx}kD)*6(%7VCR0CnEcbi+Mm`}-%XA`n{01*6z-|~ z2Ywo4TZSs%8hkHu`8kwl#f4vf=NEk=IR6<7sP-H>1u%j~vH1URgak8Q2^N4FyotC< z1`B@MK>W{G036Uf@XhSCb?K7;0uJ|oG58oNDfg1nEEp__kgOs5$3dcG{iQK;cP`ypx_;Cq45{d6k^?uDjybaw}Mvx#b2H z%-{B2x<}YOiZj2ZyTOP=5fm^Qf;dE9Fm>I7Z36oOu`jrY;KXGh%y!`ab!-@?2rB>0w9^{{CklFwXNEh@|G!lMGgb`(FKPRJ6T`V9ULJI+U%yNy? zK`8eGxf5M}&QOP<$g;#nJHtvV552}Xx1YpCC_*T4HEi-S>vu8cx>&Wk+od~L)VSF< zd)oE+*r3sm`UIl6;-pVpmR~LV5 zm;i=?@a-0oC>L=A;m+{4<^)+mR3r)Wpt;!BxH%&QkK=Dd{+o{Wp#`{OZmGA`s&g?T zu$gjquJp9-jq{tW%Gs>RU(SnLC{7zs_MNXxU+E%to3l^5i${wyj%pHC>tha!!zU|K z#>z|AbHW!&q9#krN3wjU(|l(O6L{5i!)dk4b@g|Iy!o1*zLgz%P#iU0TREH+u-=`$ z!jkRwHte>PtW{?pHDu#adb2WhrY2*dJZ?Kb0H^6Cqiv?Oc)G6mw7=<*QFW#0-VyM( znH|gdfwz6R*q(e)bna3q)6Ka@%_W!OZXC?JY}Qy^#a40b4YU0Fk;Qid%vlzFgVzGr zS>LUY_I`+Y$8Mc2&m5}E-sq}d>g!yf)7Kf)joyZ1dg+e}{u^=cEvju;9Y}_FGc1MN z^n}%U$7}l}?SV|_klpz~LAg=N-;D?!2jy^4z|3|a=AE+Z4>=uh6I>06kZuH)0gkg{ zUKf1Sr=o6j-Cz8Nl0ae2k({?m?>*pjewiG-9;96lA;VO3I|&7-?TtEcShD(|L^GS}l z00#g9l3h&2UKya^4RnAk9Sdgg1vo7rHUV*r9TB2R;WFT%^AMGK$UE_}taCD`aL`YC zGLDjYMCz}c)LtPQ!CLKw>33h75np`^W0s|+rXiLnU_+mgE~%2()a|j^pAXMqs{VdW z`DumoIM{g6nYo)2$|*}`l@<0^7KpkUH;2a_)|WqQPeCC1*MpV6>@8s~__8{Np#WF_ zL`8GN?VRj#QgVmNp}EmF;|gr>;Qod%c#};5m2)}BufygIPyt@y)6(Lvy9dAQ?tWNb zxmz3@ZOum~rxDx)&ouO(ut2rpClTRk+k>ZaV+5!E9SiXMk3(LC3wXuJkMo~A^Pj#z zg$2L`+^8-bqV1FA%0zjvGg3vl@3LhmVF@dSXI$ryXs4$02A08_EQIoI2W z=3z>4Hg2@mh1V=oUp-puRR|~peQjU?tmdw-)DTScpLaxIdOGO441w<$&nNN5dg+$N zh$=;Lb(SIdz>lLIhkus24x|nV`Y&^B$p#G2ltp%Cpox)U3ilaWys_}a$)BQ+@H*`h zJdc~}lO8ni3+6f*x-Xu3&9qTrKt`2X!@fnTcrX+|-3I9>$Xjs2<%Eekj(to4aAF}M zl&qeyMPV`d4*rpVIDl;ea+v~4o5}K=Uj~~0ZMf`bX5!nn_>Xmwd)c0BU+reQ=j|5i z-H1A}G)S=0#-n$xkp>uR2$;xCk-Z7tK~e^(S#`2R9WR2ZOq1Ir>Zj|ep{40i`) zRpi@{Z!z4gkw=Ylm+VD$&_l2n%gdJPWZi6MQ*3J%4;tIcuszTUhd=zjG#67?1|$L2 z(m-oPv$-;OD zKR0XA*Nc*-^Is2Dl`NFTYK<>EwP zZpK)4>{xW@QBC78hpMPfz9w>GjtdjV(mbV^Nn4c(qqW7GmC5JS(v!i_gXZFy%Dk}r?1+#j( zpa7in@QLdl+th3vOegiE&*w~V4kA?>X~bjhTFrG7gM6M+!DXkaY%yDRRwjqkm)6kI8Q2pt=&o^xI+AmCEmi42?r2@}OP*yVtvJ`&K5CA}vyf`x+! zi>gDO@PJL0Fua|bxEme58yk6?oCieetGF;YVyO%(l7hF@0J#hl!~%Iw;=Uz zP%ln)2HP3*6Fw-)Hs$*0k@}x-azO+U5sC?*3z|y6^2c>P(HR#wLlqWaO$3gSTo$D` z{f8AaCb#EC}&*0qO3Ci{xW5;rXMd{&; zs^al}`Z8?U)8n6ZHh%yk44Qan=JWjU_X{JR=LbK{DRJT9|6xpUH^Ms~6<>^q5FrlJ z#)X0dk2-uJyUey(O4B;K=SW6y!PH~V24KA&9r?Jj^wZAn$E~$DbIRGiGDyYsKx}`l zrv3bnWT?Xv?TbfsU;(tBSncb7{m1_!7Cd>)RM`|ysPUUOS(Qyhe%F(3h|H`834u$6 z1>|1n2@6yUDU1ey09+UiZ~+3qt79lYIWm3;U=MarHfkDPdb*hUssg;aqC@)Q1B9t) zWe5`^dM?5P0Yn%I&|5-{@@B;c_C5?J0cGa z&Hqm+?PZ__@iIvLS)9K1lh;fmO7l5rUqriMC?I>yEcM_iOEh?uVWE|z|1ur@ zmGEpKhSWkApTZ3$f-G~bjHgIC)OjPA2oK}f&EQQO{^W7XDe)tA<99EFl@nK ziD56sk>5x-kV({iJ_v3$!^cpQ0tEmH2#p3VAk3)NR=dJLtJc&1{Rsa*7MlKvoBac` z=v`CDMwZKRg8gU&s#Y~>OrD_+6`nFs9asvH(+JetFq&B#;&;V6m`Okx)Y+K8bPR_B zlzf#oC}KiFiw*(tf4hxIfgb5(!%)#>Y1n3GT<>E=pdHY|lILpE<7i!AW0HvqG`r*P6uX*2{@Lqq%kpz>vA53C*Nrw-#{(eJ zlqhcY3?D~nw68qIo9$;U41nCohT}mP_tvyd>kW6etkAlozqpSTI?Uy;PHlNYS~{sB>Dy96BTm16He2 zCNi_<3cUvlLy&cNlpiW9&POE0WN!LgWj?dKb-K>~t|#QEB!NpL__9h0pcEY{ji0YC zx$mmj?4fPeCjHQxy20mStG`|oJ>OD(O~kG@)lOAc&*g^?R+k>NB>ZVYe#xUFqJFo& z^nfn~cFXcU+2S-XFZnk)|BQenp;n6(;C{Smq95_=5?nkEIP0hWXoVp(y0UeC!3D^=a zBfOcGyqT6kRs=Y}n1Sr=6Dc3R$K|l(P{Q5f(hsEEyGck=Vf0{L zPmbTu&Hxl1=4OA`+?eTYinY)WeDzhPnKqKty9f_shL-`)R}ZN~ILXHn$QDbo*cPEf zPxe#DMi!D>@cQ>1ksEMZ ztfTJyk~9}!xs3}00pX^phpagqg&JS~Avrv7du;IM!@a+q9R4~l|8a`>!*I)Ef9`f= zq%tkID>|qVo}T-(vhnBrl|L;{{yIPT>w@%$#bI3EFAM<%00B2cpwqc1 z4?+sz?T{FYBP4trh^dDX+NqMYBc$vAjukNQ5lW!I-86b4CV-(IR~G(p=ivLj?GN+H zrT)rHJvG!$nt!dK{qh@>gZ+Ly<81#s9Q;;0hRx4^nG5g*cx=Z-ItHE;MEEXpsq+*p z{r|!OkOdeGU=vgM#c=+sXbBwqxN!cf-~czI-54Sy(9hp|N2*le$$0+KMO`z}+^o#U ztus215g#H*4v?e-%K-<;EO=ffbWgZ* zwJ{geSQ;Q12qtsvhIMdm(%RqXFQ6924vf zsx4mS>FRex`2KB`{~vSIf9#9+kskWcm^_kTIUQxO6y?Zv0Y?BQgEpcuGWE673}KLa ziJ1gIpuz%>$Oxc7d=h?+D&!G4S+uy3GYIxkIAn=Z__bjca4@Sz;j_6Rs1k6@D3fQo z8h3$OurbYdFe`L7Ye3?JpQFOZ1vEi_ur2hS@DX!7E#MJAqa~RPZBABqk}gsgeWoK> zlapg(9&K-f)l-YNZLhDZAUv?&$C)4KEDp8f2bc{9W3039^Cp~Iy`9^Aoxn8k{H#Qt zX1yp;bGEE;u?A}ZzJTJW3qVV;waa!i6hm9gV3jOmJ`rMjHSlFXa7)Q#G@nabSr#sq9=R$HsK%YtWWN;hiLk#IWO z%RKGKnJiDcYKum!|HGhgrk8qB7kDLMA(-w^(ErG28Sk%M$S*#jBw_8cQCoOS$=U2` zo9(T+r<8)yI9H0NC^Thx?iCUJKy4w`+AAiBf{C)!g|=eEO}vw`&^de~DSfMC;_$v77TruKNkOQb;9%>7PE9C{KF?0wjtwG{`#qE{ zld{KQq+>G>VR|~yyCrBlQLxVkk!r+-l^C0*JrP-pc`W0mYlok$?M69+v%w{3s4rV-Odcxy$%W0(}ZRN|AJZwS7WM&t~kgTUNbaQ z;xGpbJedf05xEb*k{JDm;0Q={iHbW;aRz0K1raVpnqh^E{Q(Y%sU%lG0CtP$MaPIi zb{_g7$i<-8R1Jn7xXh3&gWnQQf-n~#aL)1t1f*(E;S)%GGyU$Bt+sYkLDu#1@TxJK#jl5 zDA7HK3rz9%^AHP(-%bcWOiSKRiH{)+mhxfIxESPY^E$T$J{To z{~Zfdlri*0Du*(Tc~y!X)JJ#+TO-w_+7UfvR{xfH2l>$72?;n3o`B$YEWi!M0lZ>O zgg-hgj$mK_7TCT}3otMQP0$+V4Fw`4D}+H(X@;CTTp2FVbM8fjvV#8L=>66N-0P=t~X+E}_9!Bb3z4#6*giwvoQ zSQNo;Xt6XSiv+^EfclW($;{#ue=x|W|bMRc@nv`{Z=A`jsXs7_p~j@+%yK5b0B=2)xR&DLg4<_2F=i_tT4$t|1iD8~lrl-+qRpzW}G zubRr|XhmCe@eQqev8#Q7Xgujkoozr}THa%K#=S^>BI3_h#3^%LFIN>1o1N_|UA4W+x zBkWWuyc(6^x%Pg1KowyDEI>BJ(-(-(2NlR)yBQls{_Ew~$ko^wIT`>6X6I0LFx1^z z6zCsqY?y0n)=K!;^m!Yy{q#5irqXa*MYJ9MeUlUbxWPDE5X2A|{>B%lx~s+kOav?G zD7di&iwM2|3!=$*Cp;m_BW#dy2PhHv8RKsm)5j8?NJ#9m%}5$A*;F@Nha?MJ)HG~g zYM6dQo@_|@Ck&r!x|>@K_0#|9>f}#AfqB`N3D)Pqp0@+UMq8RZJA#>(L@TajH*`$0 zxbRQFf$?Q+7OEkP0H05T&w`h@D9RIks`vHXe`ov04akc^J zFSB}~tFMmWpO++Stb&85_0Io47U1MZst^u;%slu-R6sz!KJf)W5DX5ue$x>FFjT^! z-}q^=FPVe`ocuWU(UgY!r@asuXfmY(@2lnl4{hCK2Z#EQKw4}VFEIoU{6pz}(nKF& zygwttn;9L@7w!$3fEwl59plSL2*lJNPxe!$`VFM`0}BSz!w8J;8wEkDx#+b=Z9yQe z^#Wh=%JKvpY~}iZN5EGZJzydTMs<40`WRGHaXiC8sASf=u zKpQ$DXi8OB09h$o4E{3~xV-o#R9`37h|o_k&_QKsg!*%+Nh5S#q?qZEY1L1fQcMA) zh1c2`Co2{d*uGaen&GHd>4LxrgNZ7#)=SrWo}>Q~n|Lf>pv^%BQK6MCAOI&ZUR79t zWC+zgBIuC&-|mX=1btvZ8v&NXUI+OZD7YuHrmc}Fr;TDUP|3KeZP9f9O}ehWvbgli zaOpn}$NaS~=_JSZw88PRICv!1iXC9UayRO-HOSQZ4g^M?tr_-Hh-}7uf|&#m1&X53 z#-PmE3>ir%V*{rQ5fMCIh#+dWH-fr{pg9@Vn(8F!X+Ta@=!lwd2h>^CIq2uP*w(pQ z;qVuGSSWpLCI0r%fA@u0a9p%G?xwr|XI7v$Bh;Ua-*(h*_qXgtJe`+)wxwyjxoMiU z1*~--k!3!1^k9EUgzs>O<3g;n%pbBKT|`@x>o8Bx7B2^y4`GFRN(C~ggB^N&%m_C< z7~48*wL5JfyEVzSvC43;gC%7;J7T3EcRniw!{J(W@=ksJOj+VeRoY=sEgs~LYLhpc z3Pv-bI`N+^jGN1fSSv}LO!XX3^PjKI9I2y?60HZF*#|`WLVox`ri&t{RGuBV&=51< zQg%!bS(ogF4JHj8G&gp{l8q&1x@s5c4>&-H-pgp2yiTI5_@(CXjtJKsR{ub`d_ zy3w0_Hz2+j_v43q;CH_j^*%@#mt4x5!O@?VXYT)FoB;Ftc4ic6qDy(#`!N(Gw1Hi? z7IvU);egU~!la!G#Ajl~CZCT}9ZL*E4}rP$*`f+lcY-y2VT|V+*WffR(H#h&VzI27!md3_3XJ=$YRyh)AyEMUHW?7W|P^^pc zwZky7hLA>+>Nb;r{sKo}0TiSQNp4sZsjvVN)3rvDhIZ$Llh>OG+q>-NPKovHn_K~a6N#OS(>_E9J`xeeOOrhabs+$EeEbuEOsoP>u7`M{ySd)I8g0~p4LQP z<5b7-{=d%!NRq$-4-`I>(>(-!%B=m+z>WD1IeDUL@!xNFgrGY9T(Ca;)&3q z?g$S`YydMcNRl2hk{L3T>OYtgFq9TDlpaAWr@P^_C)t5KKj;9~^8=T%d~oJt8;EI; z%(Bk%fo?!G8Ddwc%A!I*2`&;5V(g?LW^5n5URQ%IXM+}JqY`tnloEN%@R|j_dWjv8 zho(A+V={n3L(NC+l@HSDUOdC65J?mQ-!c4U5D~#j1_xP&xn7!yAxz6;qYXMPpAPnX zGmQc>HRP14B1xea0!@r8R76!bINRjAnx@ z(#ral&ieP2#(&}@e`*T-i5Y~FhromUnI!ebA7DAGK(TSQ9CL0u;aMd@cdkWgb=gRJT%Gea0KBh@UiQ6wW533 zqUEX)RmC7#R+5CVVea}nt5e zmx#LK`sDqNvQ?s`{kS^xxVP7`GXCLiYq-ZQJNmBNFbhTW3bOCsxn z!#Wg;XQ-v)mBqlYt;)o?%z%lUsQLP`J!lz?+{xz!Fw1XB{C?%L^R%!l!~Yd zcq#UU{PTeUq!IxOP;+yF(&S+|;A3AZJsuo*x3u_nVeN5Y^V9O|mz9;Dw)W<@qKcH{ zOv1;p$=yieV>lFMf)ELLwAniCBmsrM>CP0Q^YO?!m+zxtzz z!K?JxxJizT_~q~hCbECsR(u?6#w>8nD>`V+SgOqB6&4B0%4hp%n?ex^Xzu4nzF!~t zWq17N)sbJ;hJRUy(^~RjM({W$co>mBjtsn?k$@l|d*MLk$XI(^>K3zio7J~3rtd>r zET(M9e830?f&m#9k|A)x6AUYuiUP)r0GilRT^$!5*zqAS0%tzfK@b$FYz1Hn zp0-2S^pF?6fczBkGy(t?RRaUQ0w!!&u`Sh}TdBXW)_7_0^>efDUcjz~!ymW;DANCj zZ;k#471paDQ}b*Wr|yUVPF$cOEliRWsK^MBCHYH}gZYUe{V`-P9X&dL9_2?3_vFS0 zNs>cFNq#~&3e$W?GW>xEqp3l}MvnJhQ80>Zwu^$`IL4TO;`_C{K&%MC6u?%1>nW;; zbQoeSsH(d|d?D(N2BU1?Ed&;bgG_)0olg2lugB?$El#4oHtLK~Z3brn%8tp2Kuyh0 zLmiFRAv&ajC|La^3X!Ar2yMg=VTy>;Q;*eo^;-LRhM6&f?eLV0jSFgyvyISY{HnxC z3xWp-b8y;&iN&HNQ|~2sVXS@734nkT44_~Q@X(Eie+2)Onds!2Xuw=t?PLab3-S@k z0vTruGy&j%N4Ee3rD!cHH`8b*TrB_ucoc4QFlewxGPD7_X4nqlg5C&*G)xqbaQhXUpLq~MfQik0{S?ETp4~kJMtTf}azDm)5LADhb=@yviL()W+Yg!q> z`HZOsV**xa9ae^w#`>T-FunBJnj(cR%S?mt(R!9@qT66=M)k07ax{cfxYNg$8SH_c zdE^TW)YX(w{ye(SY zjJi>CX=7aBWL@oU-y7yVUy=sB5L7^O#mO_-!OKNa;0rdYviGW!_Nx+>i;|bpoyH4u z#?zuV^Me*@(@9ZglK)6S0yQTM=LD+B7Hdjwt0Hy^k{AiW^F^uqwC1In>Vx*omCl~C z`kY6iD{;1yd0Z2@Uz@ek+r5_^bkW;fs5a#)+SPp8cl#$E6P_q~NXOx|LC zz*c)LvgY7BUTP%fJBf+f*3;VfkHV%yHd|hmh5o(U_Kclj#SDk9C@DB7j=826Z1q$3 zYSRaE_ueirMq|h|gWj@(yIv!1z4!A~R z?39sKL-Ef1AXDs!u#)U{fjm#Az+5xUSS?E16bf?pS6^9b>VyV_i@LhsERFwoyhQwM zWA@K;lkdj_TYVWvT`9}06$+wAQ5vKq>Zdxpb}`nB4_(1UF+2EiY3Lut^<%Ylq_DC1(m zc0MG2TC>T2!-D(CG1Qa-3*Ik`znvX|78juvvu$aaTF*40)_L_p?+>IE7|-@Nk3j^e zF4f~aDrj*2gCoYU@cV_40cz^`5plt7U(rtGj3oap}$1Wdr zlz7$+RVRJNDm5vhN--25rxeN6Av#*X0)*E^z;_H0QL-^jFqBfean0K#h{69$JL) zW8o?@*Df*DL|BX{wGN5x+48Bj6!I<`6Z9Q3OUa;1jxR zP+8XCVqSnq3VTZ=nj$YR-AE0VX#!i+CJ#G!dEqjEw1{vgAMcT+io8_t3OMIsI+KDR z@J0HNQ@yW!je~Btj|IdT5b-j-ZIQzbP8wMq=?-SV2t4D9z3sYDz~F37K_juh4a36( zS=LlfGZfpx^Mlp{um;j_cXS^!1MHYygax)#6kC1hzzAC%z#8B<+uE$$&6XPBBaZQz zN(tPnh}$ZOoU6&4EC`(~48>#nVqyGpw%=}H$U$YQAnEm1kq_wOiLB(sME9Ap2yt!s zWI0kJQ-;dp7V;yGb3!JPy+p}TmC<1{-S7Ww6njJy>545&I^ca>{`asPLd703_`VwR*Utf3>!3vApoID{GC@v(zU< z;>2)n#!gNUGU%2i^F!4wlVx#lTD*>A%pHzmsRX^L_w$@g? z&{T2OQFI|>5f@zAUPmrU6fS6`SAzB{9`Bf1cSUJEpfy82`eBg!C}Zr?S`O%~sLVO# z_TEbR&V+2FQXKWQz@hdaXgL=#&bTdS+ztd#+$egE2L^6={fqR@qmJCS685Etea!EH zto>r3|5PjjmAuheb;GY)rljw*M!%LMC=ZC|W}h9)JKwXdHPLBLZLngr;z- zoefG46&lNJ%bIe7*P!?5`KDcP@x^4~hXC6@Q_8@DEf_Ie_D&=hL%r6kwEP=m#^ zr!dk4Cj<}RN)>M71A`umTpa!%bPiW^7;d-H5MLnQm0%fGK3$bNKopEtM~_w| zvg+HXDSZHf+nLe#t7tJE#UcnPPhaK$1oC&2Kt6Vumz~X_*Czca{;*vg5UZjVujRUSGLpAw$p;S4Dulq7LcWAnt%8Mx(Q%0 zHXum|vNaPrQa>ZZq5!{+*Wvu+NO4lgNKTA2H5hb&G?6SX!}(8*@8LzMHtFIpUl$S(w*c!LHTNYYrBKWP-)0XDt*y3af#S<&SUlQs);O{K*vZlJB z-Poet-5i1^o|~z_-ws)Gu%sbgw9XYn4;e7V3wKAsJ&G@(`l*D~8O=35Ruf@%(r^cH zm?J;|;#K5N!;X$fO0?UuLhPA-)+{f=jNxw9>tu@fC3xUq(8z+_%*S1r5H_9}HJaj& zaGKe)fP>QbgSPDThWw?fjFpn``D~w&1h3IJjEk;Fq8`i5n@$XzE%0GyMNj8uoHrCM z^Ey_l^G{0?v2S3e_{p=AMzcJ(E6Uf)i)V5}kBJ;?QqHhjFN~NW%Hww$N>3V6uyR_; zOgg1h&a?W*3t#Vdlu!3}AC{+Ww_{;YG)?53)FmzT)ZdC&i`4GThJ2|04@wiZIttdQ z?DOu-@v79>%y2A-wiUzMJ;ZQf)Z2FbLXt4D{kwZnDTLmhX~UHdixc>|BBDN zk_a9o*yuCw_+3}*Hju(sJmOr$Ibd||aynp1Mk@iz(XLn>^Ia9#WPLv_IOX@<4vMZ} zULNGV8RS52wA)s6*&aTd7pBZ0;%92B$BDL?t}f_*E=R}DWqhoK;GasU>%bu% z4c2AsL10ce74dg@9k+uJ4l&N;q`350$U7Aaj>P;^nc#L5XPg)?h{j|f0<@<1Z@n5B zK30ehWrDk@sk^DUhlOR*r#8(0I5+WWb^A}m$-@r^r*nK3VruAqrUOB?Gf@uXQO1iY z4$H}&OYwGV>F%p(ZY!y-%PB5+#f5j)GdwUCU^|58L>vsNp&4-Z9=clv55{m9I#6f?bhsImyqg@l8Ii%U4Sybq1sDoYAq_?D z=am`K#|_o))a>^wLQW}J;hU047$K3tp1p@+ny;utAzeJ-wHbNvpV5)m!6q?!nOv2;D%LPPyVcUuBdoo*j1*vfF)Q(bMl?9JgxYx1#Ydpq)dowz>s z-L97Pu2yKif!%=XVMcScYyDhPFw zp{dvd-DlMDF+>vxzPJ&>6qOpR71`%aYx&D9jHR%f0!mdw`VZx)8!HN+k>dJid$heRd0 zep;`wV98d^>gJ(n`l9(FWzk|LDTUrW{LjBYfj4!r)#=0 zZM`AqsL=1ECu2=8yiVjzROasFMBa4zWJJi0VUgENaA#veDfZzd)Xu7u!hq_bTSt1BNiHa^cUuJ^Wa6MSI`7!9|ZdTp|t zYQLP|wvphtoZ_^S>b#ofvX%}MaK#Ni#G9ZDfC8YHu`Phod^if7Xjm~>4~H5Fz4dz> zp~^EYu(pggF^#aZPY(-|_I8~uZ~lCJ_3Qe`uLB*Q2HH=>EqmP+#1g~^y`@|9!u9sN zNqWy%FLjSC*c%v!%=7Ky#Pzi7eqQo%Sq=#JJTCi!SfL3KW&!xPfdWwNK4Ag(epmnq zMTGc;f(0ztW_Lr%dpW?p8xdh}JK*&JUGIj(KnK_jkWF+xAcSN4zhc3si__DgGdd7`H1gDNX?%b@DVQG@AW92E7#*UApdIRs_9Z)x(O-}pq)5k? zg$(CJjARE7XZerk1&`-}I1W;#1QDy59;!vqR$(BxV-UxS;EM}_0R%YtRn`OC;KSdp zEKdlFCu3|;bTk?X>#;o?uY7M)q+dcY&}gj#86?UMn zFKf)(*bC)4TIXOGve3n^*zaM+_9BaASiTTO86xwp&BLb8)m-LnsSE_^;LslC$^aJl zTG8CC7#?<*LBKL}dl~fj>a$(7q4Vf)Bn(jLmaeUquBTODZ`~f`D~{TvzuLrTwTi z^Pt#65Md@tj~t0koG*=9ZK~NSE8MRP*dS8IE7P~j(#Gr37xOdEirgNBoks*iGL_>p zUyXdB!mVPzO}T8UKL1BPWvRV;yEtsIGGnnk`KTstqP_|RHxo_uyZN4LEfsKBEi!oc z)LeD`YGvVOed=^CbEhGFwxeRPrUvVyBT?&GZ3_K$#8^_=N?rDJO#wLJ>6ZFcA{Q=( zv!=8!)NGs(Xfz=98I=95w)5Ts^djtZ)y*|zZ#Gn&wC9nK(_OLLSa{G|f5L1(XLmnH zSXW&7g;ek$?K|Z$ffUE|x=RrclA&|47~0Vtso)oP{dQ zYlZY~PzngRka6FP;a+hw2y_slI0u5Mn-K{ahbI$Xf~9~UM!`80_d_}fLV1^u{Sw$y z`WC16Sjq()AmbW+2k3pjoSMI%or3}Gd}8zrO>D%%%;)8WA7Db57@KXb;6%D2l4v5@ zWFy^aA=YLc^3f#6)nupjRF}gVwaw=EPB68!=p8bkLT! z-c_OOXj|h7caYe@NLW&kZg%HIu< zT@nxu9gF*qM0Bi!@Jf2U2iSN8E}UY@le19}0TTa60x3#ds;Ol2F6!;tHX1F=DhI_J-LWK!I!|CAzi9yQLFzARRnbBkhU5q!z0rcH7 zV*NP@u$~1CWdws$9!L!s$qpRK^phsJ%aT0@(@Bc~fdC3{$Ge3=mkM3uJK>0=WQfln$5F4bN|YHIqS zWlc*fP)i$F0Hz>FLo-+%QPrt0B2Nv=e*gg<^;OcK978p5uz2`K8fc-V9ynz{0JsA%2yh&f;X&6984pG<_`(5? zr+&gxz0pct6*UAPAk77qnwSf8@KZP0=yrLSwmKU?|Aq@3IL3x5OU+`V=hY7O9~D*q zK3Dc5FXaoT`+H{CL#5knu-V{iYrdy0)mo#)TnqdHY6mc=6d52I>8VNwjW*ydo;uF( z!-2hMu+mF3N89Ifglmw=*zQJU&blZJCa}PV9iYd>5&|QnQd5E)`jJ5m^Ru;XqpL-| zw>|VwUG5fS3#F?Wk}@)F&C8su&_6@!nw za7S9S6W!H>>SEsEVBX&+uPfQi3Yo0U0_m`y>9I%j zw;XaLvo*P!jfeuOylsr#q_kZL+U~n@Mq2Av^P<v6$e4c zb1Uwg>1-V>PQpVa?7}C_8PJ<7wbgC(G>;a9@2A;sR~C(xmPpGoH=1j9=q)Fdn!Tpn z?atc0=DdZH=;ivHJ9_0Aqm|fav(cJ>^ZArsu}iC7?`T*e($}g}uQ}~#H$&jj1*;u! za7b?feE>u_(Db#@wlr_`%#%VM&UzrgW#D;NnLJJ9hawc`P_Cd@;?NL& zeJR0c0DYtcd+_^V$c5aZKmRKSY-c5wlw<-wA8d7SNN zxXD(k{d}A`2!gez3lM+{_rL`e7A&W_BYhe{Y@YB}9FZ-+iy4?3+Tz)L1p7f<%^c8OM#mhYAZg&iUjC16K&vr9bdixGX2azoC zVRhzlap=q9;QMJgnISqwcDOx`3*U@#U;rUogk-=17J7o9Ap;hW&>*3pkpiRuD0fT* zFnVJ^cp{N07fRmMkl=ch4E#PG;G#GV=RJmk|H>DDJN~dZiO)Tbjv&1HXrPW`XNW9S z9SvlYY8XG)!U?asaNq+Mejg1~dDOoH0d7l~4$i0?vCg zWLD$wC!KdMHLYH0sj?=l)HE;`sD=u?Z~p;ORG^X3H|mz(YWV6KCfiw81$%d4H;m58 zc)x+90Qqb91wz3fqo;-*=?-%-V(6%^eGxjrjrW7~3|KIl6-q9J^2oVBmh6E|(P&=8 zNNyytkm3x!02k&0=!wA>U`+%a(R#i=90w~n{BwNPFe6}Jl306$i`mdTmRG8_c89mQ3HcHV$^`>EtnIU}9_)o%B?re(t3L~8s zOGApkYpt6lxQb32ZJM(d(d$C~L?u?3M$GYPS%6!g6WT&wzBboE?M=U*4b9C2+o5(Z zYj80zKh&A&(gWPtk^Yom4|I`rc$)XP8K7#6>S~X4YwUuMUtQ~E+8$ub^|zOMnKKI68%Mn4ho*MwT8Oe=XA#(grIJ9la z;Av~~UR~CBN!kt(eMLpAMC~KB7J{Os>a_jV+^M3({ourk!<`ua_cND~cN&rc967q}DFdT4p=yPdZy~DWw-(B}XlJt4&2y z^+hvPnTXQ+p}&CGW43~!J>pRg`z83M(p8_TWdz$y-5=8#2_EER^{csY$8XsWy;v&U56E%e z;pz5fNPv(EY>F`}}T%ovKd$Ba!%!Peo!ArUP7< z4iJHaq|{THXoXFd>tM2g<_U!I9w8Z7j~D&$>x(u z_8aLg>o63gI;|u-;95?yS6w&>NG%E4(VvowFce6GOb5bks7cZM(mY9f(k)Fngwk55ZOAt8tOD#EY*0LS`>CO}^pl;FX{fU)ct=t!{?g0q+w<%t~;+ywlTFi}eIKt{+|ZYa!UBbh;i z8NLJQo`3@k2=cT5Ir50$E#JxuM2{&XA<&d=6$Fz`|~FTXa^(_DMD~2TC?0uaDuhkkxng`tk6pwtF4Y~35)|?&!2-b#s!)H z@uXhQz72f!Ji*Q;!P+81pU{TYB^C8FM#vG;%`#NO4fp~qL6AF#3+c?6rn>kLG;x;B z3;fcMZ9; zpBLC53RR!5&_u6CgNJRQopAyD3)Z>>(i`iYjJsXUsm@02Hd-adui|wzgLU+itW4mL z<~o|uEcM7k+tM(_${2rCY+ECaBZvbhj<*}b)3MLhg5hp~WFfl0J;TodmN^8{w|QEj z>8!_IufzCxo}D>R5!5){-59+)s7vc}b0{~|PcgU3u(2$5BP<(`WD#gTml3{H6emgc zl_dl!(>#Zgqd@XbW&}p5<(KtaL{zYR5+ zhm`vL-u4q}({gPbtZ^5NHgqA}@F;Uc@eZXG282fi?SV(d;D8nbJgOgwWXBv4f-K(4 zXvmGYlQU0RDmQZDm2rNwcwb3X=6qM<78AWTj2jWrc|fbbrnMh1+b`(!JvxnC{tM|i z;ZKBJ7a};{m(Kqk8-CZ{h(CN{WGypEvi;Cfs* zm=`XOuo{oCf@E|q-hLs`ek0SJD_K7Xc1#4Mb_n5tC>|OX-A^j95klJQnNoN?D#M592)&yaK;|E;cvm9? zCIoDYh7kP?Y=98=eqs8T-Nl7s_t)Aw8aleRU;Q`3Z~mL+cYnYjpkfD9$39;14u%3$ z5F$4&|xB=hI$=HIE=ztjvdFv_qrulKO$#RlV$hk{g@7C4v|h-sV~U^*L*bp~+^ED-veFU8Dl9-ADYQd)MK&pJfCcywNe!ukA+VqUz<_B6qXFQ6Z0WSuuQWw@u`Y;X zvhBu7Z>z24f1c0&v!eW8B-x+2=|^R*4;7xP5XS@?1a##kf8 zNDn{&vmA7>zycWW0CGiE2zS#WoQ$#OYI3uNdK8=h?o-Tk2#^Y`_J(~<#vP7EWwwUt z7CK-{3XHV5k>0(24qysuovq6q?W!DXI^6JJZqw&w(d%tZ@wS6x2sNDS07oo!6roPS zATO$q1JWw`Jj^A*E_7FmP7ez-;8Zx6LsW}W12BR#H&~sq3$rRWH%>Cpg>JMXh;XHa zILTwZrn5rl@*=15qbBnrhf~9b(*hO>;%2iWCsG2Y)53>ddrrOfga%C*?baXW!VLGG zNQ{6A6H8wFO_YQgaf5BE9bH>}T&A+Z5lKB+m%d&2`n0=nf~dVI3BPSloN8}f%Zo*% z&|-JPe&OruzPy=E+J1G$F42@cl94b`7`a^*deWV+(b+sxTR2~mvXGks_wjCB4LXbW zn(L=(%9e@}R?D)MD-td!MK>(gT3Z|1aduk^-^=NEv|lPq1Fb2`iW*8x8mlN!*5pi9 zgdA1n9yjIhQ0gJ)U+-$)YpXeEeLdfdvdX68rrhJUy4}7CVxcNyyT0hAGySr^3PGW$ zn?dW^Nq6;CXT?He!AWzsL}wYAFJUOSl2gxx$U@>CvYX#P4bP{3o)|viQMc$#S2Fq?@~?&c&=+0G zc{mo~VFMiCWIUH~QRW6QCF!tIh_^V@4Q~HBkF~|<-egd=dCWZ~1sw+q{S>UR)_ELw znGXn=VqZG2E0*ty2Ck=PusB(2%u~cUPAAxaBL)^MrP;4#xGW_&t|YmxrMLqTNYioh zla4gfb}WbtHC1E=aSC!29d$EY`pL-rUw4-Ov?+Zz(|bPBaK|q^>P%d%ikR#Ztx=lq z`g7h;QkH8gh8jgP?2%0|gE$?LpN>djANa5|^k!CyrO?OOL0AUvMvyWpz=J(ruLrq@ z!ah*LBoQE{0SIuNNthta!GR!|=|IZAkkCle@em(^T(HKNgb*|VT@@6hfB+Q=yqz7v zr9ua&hcFF1P7@QL(Vs373(f|`*R!LaR)Num6AOdJFG3^K`%SpV)IZ8R%}eEy)7QlEuu-%*@OT zuT-j1NhOt-nVFdxEZZ`*n`e4vZs6YBWbP(6dy~yMNoGHm81|z*j;zN3)gStYTAo+%3JjddEa37O9q`LUeG@lX3 z1x)~gKpb-c2h0U79Q)A6;vkUe!KMgA*iUzZLE!wqEez!R=MBICpWzi7G6Mqp!Oa+l zwHQY4S z;9@$!Q;dm#5dcG3@q?Ryr+YT^Km!-YyqHC5^^6S=+%eg7Vy``;fr>b0HAIahVk5o< zkNWh~6N&Su4@>`PD)S%vl78EheqG>j5~IKB#rbd4;9^kipijp^qqQkfsuB8+vmb17 zDt83s$^ZeZK>@N-JJVV-CKJkF^lNO5WtIlDM2DJ+Ot~PlG(s1I#1(Rb4OxbnF7$Dm zi&!92>-eI?*+}rPR(iVjx;asKOtNsjtG>d^w86tv>S9#yVkCFeZ*tV_@-!UvbnGF> z)SXrm({67|Mj!kPl^}wv#L^f&YO}Y^RE*%WmKL;}?7NcU zx0@S|W`|Y!QbPDblJiD-#ByTLT%5ydQX~xp>tS}Q(H_chm)_)1$f(X>2WsbU3ZoZN zy}QG_75)x`ksgcjkt>N|I|ZQ^wMj(t9Op*AFN;{MF2SDgCdYfTsq?rv_C`qCkVrQ3 z!v4@(dEHvKD5M3DJF$`zJ00&s)WypRzq8u>mCB0c^0f8*w4+qdx1BPc_^!Izmg<_$ zt26e}1DIjn)Fp64?&rkw|I>SA?T6;7{d9-Hgy6}%+_kL4Ga>D+tLRu+yImP`Rg`)! zE57KidDX2vZ^#l2&kecnT8qyb>(6CrXVNm^Oj>>+#P1hppB2SJD!=cReH^SOzHD1o zc3YRdTb*@L68}M-Ne1bMuGX`Gy4$Y0>vri)hy1Rq8E?Yt-sU^X2>Kg7&ab|kTYNP; z{c3jdo8|f6E{~I3`m#CwtTg7RAbzDFW3H}hPFcU9l(GuK$Z*l#e9=;K-XS#aOA9Xt z>R*ra-A=V(g}rRAe>>Do3=wLio4!WOY2+eZ_qSm^el^&6*`>JdRiHR}KhX&s+>lT) z)=7068zFR)OcPiAZMQ?6cO$*njhO{*#)eP(dk$Oc8AUGn^6m!ag0tb?lfiD_;CP_# z=1&s>_Jh~6^Mt;>UR?QVX&GX7D$#W*(qx~laFoSi0+-cRv;~?{#HA$kp2XQ4M4GMz z+0KX94~AMzW+pAyNjG|%4;NPsH+KK?_Q=0G82M?5p{Eg(_;y9mTt(_sW5?cL)615$ zuN4V54Ha_@%B8;k>!rD`);E5;AuRrOgK*KQAJ#{S75%i>|JD2;`X5eyZp0^ zAb6M&=79r@1z!tm3)nFLf)7igQ}4(9)!!YA&P18h(f;g-22H(0f$FJia5k$Z0-o8q zxaX*USl&D#zmy9^P=SJKOu%2DnhSU*D4>d@u-1Fd`Ol_E^{PUIDn5oCFsByy!L%kW zo*v#r#DqC@W?!mXK2~>7*9tW@De`o02=-|Y@$3uroJk8tJ_<_*DLfS6)*tSHzicQz zq%FX%KhkY1!FM7-jHH-P4O~bIBIgw~Dc5Y8zX$}W2ug!s5Wo=ujVS+?SO;;=g94WY z{$fI1t`F$InGY85%9@DxfCYS#If6-HIoy)=)75A@D)DB5%!j=U;f~R?G&>p*>&C-7 zreWp+ltRn}qNhMj4MgyK{0JamO~hOfuB*)zsx7F~aTKAYhOGcNAa{bp5)BSApeVTkki1=n2`HFPMiN}BHTVkZ0_3TNCjyh^0bVq{HRs^>MvuCLfX6SAg3(_F!T}+XT(*Gf~*TK8dWvAas z8==o!Fn~p6Pf!=g4;~A^GR;_NpbW>YQ#*m6S>&q z;jR;r_VaN;^v}mO zGwLAGYd<4oK0AG_Ja@Og^r9;Apg!+{Fd`YOap7`J#%f6{Gs#c#@SCn~^4<2Eny5>= zt&2UDRGw8Q3vVPTXHw~LZQ5#491iEZ>X5tEinl%TmAXnEuHQD6traEh<|MqTOgitb z{C-gSdZ6*Hw}sRCzP|-OGO^lso$^;bHH02;e4z>DIQn6x?}t$=6nUqm;iGYh3;B5m zvf9gL`FXqitY2|6+CujYuH?(k%8z40FZ0GtO9?vC@5f}X2jy=ETECg>_&C;${OGj3 z7HXI!_-RjIg`Q|;EmO?Jbq4uY*`!rU-7O&4XXG*q08 zbd!bp)A`}o2b=FE3*R;u|E9hCZABR3pu^UgWkvg0Yxc+1&=XnSn!IVHqkVI@?Q(hS zyS-&1MTMW1hkn04{+p$d?-quUhQ6KZdO4wdJJ${baKZm_0R$+5KmxP+&%2SU_V-nCrLeWYewAvnB!y&=qn0 z{%GxoHAR1bnT^^LBXw;vc0r##(f(5GljLmYmAODQBdFFyys9qM6Fv8;ce4M{`WOF# zdoJz2tckpBZB%L^4ttJ#?%@kW)`8IgK@xGTKnS=13RrxpX7xnFMqSh7*I(GHX#~D7 zNVT=D_Hk4BTQ54l!U?rgE z3f5m%~5C2-KfXg zRATpxwSAwf4K0~`6_-lYq-s;+mCuy(8=F0=hyK-nnyIZuSwWe#F?|IBo3J=!Q)bWD z8Ff2TlV;uSWJltb0_@to z%$4pYJoYn9pqa&GmS?Fe_q0~p8V}l=H=1iJto7g{a3T}PRBdk}^RTINvzWyk5NbE! zD_G1&I6)08kZTxfvk+>3QIdF+AF>$ZH^}-g#BMyoXC%UIG~8n#+qR&P6-z=ESZR6&{u(LJ;g_1}#S0^F1%iV)yElTlw*KRi4|mvaRyQ zduiDHK<{B{_^X<*q0-8YB)7LhUBq%x^2YN0BhjyFm_bW1AmIg3r2s=XQ%ld>HdFh#u zu~8nkT3T>f67#ww;<}rJBI#Ls({)YRc5%vVLG)E&#I3UE{aDwle#N`NmXCuyKTZsO zGpu;qRedHaU=j42!KxpI>OOQ=z3-~LQx+XoC2ti(4d=uz)#csvOR*%p>8QLPl)N2l zxa*hD_CVj+>n0)R?U3xSI_*_!*2nIeqmFrqbh%+RMInsNTzgK5CqA z2fFWu`j3>dqn7I9mP%Ge_k#mR%{Bb2V8L0td|x2}3tkR&9=0@`boE@1Pak)6oOU!{ z4)vaPHEl`?4qGMLZ4C$Atvf9B+Z4R62~D!CmZqzb!QG*5v^^geHt(jV*CYj_k#_45 zrYA{O;%X?x@gT+KIMZ%BnM7-=tpwk_w8)wAtkX8d>w%H?Q{!JPj{a_A^pCrpe_WEh z>TlW-LT+S9YxU(f{q-Lf@;IN-EbZGL!VKww_r;{LBeLHr~XGa08E;y{5vOk5EC@|UC- zsUG?NEFwZTDm(xIJ0jJ*!3~~bAi(~qwzK9l7cE`eN9q(AC(|p3iVy=6F$p#^Q)!fn37rK$EEeQ(Ezw zthE$2I`|7XPkCmC@8y7JE>Ky_f}TAC4nP6;0^lH2M>9%GBTiR4#Zb^Ex`+`1ETHdL ztUP}HBti2tV&1q!%b1yXxT>;Ad1W=kXV42_CF7MCBHYJf0ELN;`1uF%Ci4O+Q{+RC z2)yzftXdy&!zzhMfqfAdaPWWyq&0}bA>3gk(LDtSm`wOa{H|FtG60VC=5Ru+ARKWnBlJX#_ zCno7#f#)B(iocucJ#TAVugX0y4ik1I3ES+kYLjt3-_%QQgp8en_{|irx3Z)wMg51S zx=Xr`6RAyeZOYZxdJ`T5jKic)7r{U`!>FcKab0O(fvH!=~gnJ?NydwTo zl6)XZS*uK5tIFJ{%iC`#e?8pBV=5&$-}cGB?X7&>nR`$e{=TW=q)te>sLR`vW^b2A z-gH!MS4A>B5N2`H*T4fmeQpP>!dJ6XJm=#tzU=L~A+}Cr4W#r39W)4l+f9$+wpV%D zDm!hf-;oPA#*W(Loc~AN;+I_X_n!84^U14jNtck8@r~4!}CNuaItcH4*Le z)As1U-J1Wy{J?iZC11DYe4|YN%~<_uTf=Hs!)z-vM>jR(GdIY%Ouco@bp6mW*sps8H$IWmP(-YcQfB-lk^bZIiQwS6Q z6!;{EziK-~VKEnQ08c_&4c-Ab0^WnsK-83qx>GX4yQq42DHccnugfCh=x`hVW=Gik zc4LVh5fcG$KwId)J>EZ+1*JaI&?Q%!km`T=3sN8S)YVj{y6V8^kXJ2;9v}d8U|wKf z^y}xp{-xe$zv4rq#}Ci^WSpw2^JW%An3RD7;_SczE)`iIz6uX+WUztn#m5WVK>A-4O~2oKvL7-V8~Il~!Ch%o|AAbcs>?1%{bpJ)C5X+!w;$n3&7=+pO%`ap$Q`9l;583Cho0_wXr?01VWz5#FA~Q zoAp8qb62IA9%OmU3mqZTPy=X^nCq4q>0q|Tdo9|{Z1n0)w8{*h5zd4`JJndb&e;&V z8H})CZzXfKf=6z`jNoX}Y;V$NYo>6p%C$CuYhe74nrctD+6>wmGbWVUh-Pd4pmc3k zI#|j)9eP9Eh>lxN@?siTPV$+E7Ci8zO@uh^B>5g?_|kGZ6<|FbV!M$Pu$bUA9_~C9 z=Z6M?|I_Vf1#J|CZbiDz2HH3K*))6Fj>ZK}XGGxuI4h3W%1?$|Ky|WNlscbZ#DOuJ z=sus7G?SiwUlGi|%&oe{Pg$NbLTPt=^lwVsCWWTOjF|fj$5o-UV5T^qiF1bli^4QE zF$WUaR8iGzYVcfU;AN@>B>?ZcIyXvk){7!IW$zlR?#m;0QvHVm5KdU5npnt**{Cg8 zD=R$A4LGk$KdH(%%?{hnPhYOe+bzgHE{Zv+N;|8LK5S`Ut}I&4^?O(7^83b&551jd z%ElcbT{zB<*)5J`C&ixrV^_speF5{$LQWdmsQbzoTxNHj?N?1DyNZGnStU+}v*zLt z$a$2K`?jj{n)FY+R>U6``7Ngf?iVKQ6{c+!CGQJqyF&6-O~!F!U+YDe z?64kfQrT5)-bQKSUPbDDQT%nU(6CdTchXk7*I0YeD#}Xtl=AET9vsUM$_FjAS3UK& zeH|2P-VTpG*vHymV=L}%I&7@jk&1SRThbP~n@(D!4{*@H_t{a@UiG#g^>iXMBHHM< zyYskNc21c?bK^>75$FGDU;9C4GdD}J>P10Txz!@uZEs*DhU$nqxtG(6FDDoG8l+;5 zrN72{$cx=*>-8vyjijLUyp&Bz)fp<)>4`TJ9d9O;Kd$utc0u@Npa|k-S5k;N_O_R` zz2e8wtlxBJe3VKLWuwPk6F2kyFGpJ5EcJe~Gy1oCWB+<{LX44E?EG%NN#N;S43wLo z39jwcRQvfr(=mh2a4&~HvjDFu6aWz}23j75g+9?gho+Pc2TpkSb1|`F;A*7v!Ad4N z&R8qm4HHktE>3yU*LnrBFg?VANHrk*g+3s8XjSBn*%4tbP+13qLf;GJLrQXs8g{6dvk&0N4j z2%3OjWkJNj|L3`YkNFK$LxH#&QhVy~MAJ!4i!02?EWyH}+{39Q$h|kreJsuwi!l`4 zM6}05tS>E7#7%TZcn!zkWi5J0hpEY`5bKXCCEFbKIGkFY>)k^F-E|lmDh5039itBJRNgD1)O^M=S~3@wTjq zR-$a?LoLM7AkeJW-MGumSZu8@CQt4ua{=~&019g!?8YI_pOZcTU*NB)0bc+XL_B#E zuZ?t6Fi_0}$wqo&LY)yAZ#ry>upT2WC6!1lcQn)yZyrcwXl2~QtcCyrj(sxGVGxiN z@mqop{F2xz_TV^RB4By1ngzHA6nHAW@!bDoEa^YAM}Ak}w3qHM8EHKkYBuF%CU?G*< zi!@WiBxBt?tLN1Y1`>xCnP%1@&-H@zw2JKvMtyA-eXSV*u$VP?xYq&)_GT@fwwMmE zSpbQ-)<(IGCKc9ZO%|3t&Q3}X8-*9;g8D-)F9@k1!h+wj)WK>nK4Ly4Y$?_aMi%uE z?&0-(A$B!8aw^nyHpq4(+WsMU*rDIWVj{$JCdzX%!gE2iCx&$d+H6Lc>_u4*2AJ1- z+E%+dH-!hS=EZL&d7q{S9cKk^CcEzBM{MV(ZKZ~u6veMsmM-R|Zsy0XXQOuxyRS{Z zkz}nkG_Isa-PNY{W+vYkgq_xuOy=es2&n;E*?~)05&Rtcg^4@m`7HTwo2$3W3zuR% zmLeUl%QAmA)_W+eoykbr&JTHA8L*obxD+2UpAyj)lQdVH^HP@nR-SU(UbZi@bxe!g0_G-Sd#= z=kfMiDFGWLc{|O@^YN+oo7?X;H-6e2`*u?K+Y#YTo^?{6b=D_9AMZ?#emkE3t|j|b zL;1_D##amNZNrqK454_uz;b!Ra4hfN8k6ELA~ogs4tGrc$bPcxLvl4%L+i-^^Cl-9P9929(CbqvOb})9v3ft4LDeF5%fZX?K?Vs z)#st5vrY66>2SJnT4$K^Fs%u#OsN^wW+a!2s9_|2xi~dE6yJ!=1w=uZ>LM;e^}~6L zVpL=XsA~}{p0Q%DHr1gqzRE_6+A~0+%u)ltSh9iXWq;%Uyc+tivzh;XF!^^ifv@vC z?`1)Uu^Kz!9upBZLtf9Z9=F%g zhaJ!Vbj$FBU+-_lbU={-(W44ClX7R%A_r5diR;Y_Xew^@u|(a|`DhP(DN9KK8yP~#W=0T|1WU253sDYe1DBILhhx2w zA&dlAF2#{qoyddsZo0S9&9>ai6hx`_b!6_`$O+oa2_<)QHd(YGti^jDqy`+8WG>`n z%q0hJR%D(umh2WLU<=+z@t^m$*v^W(Q`B;Lo~MUUa4?wYyPp;Cx|)6m0vKEmAGCO ze_b7WR~C9FiT|p->_bP*c7`w879N+cyFwZc+jE*(wk-qau%uuyatR9w@n3C@}gr&{)MvQxK*;(s=QQ`9o82g zHq~y_S4Lj;`l%0ypWcl}kj?5b0Cqo}#AuOh%3Mqs-^a@tl&@4`h>%Zak_v{SL)+J0P@ zbKY3G-&l3l+rHn^wb|ab-qO6%)VNSqv@R8x3${BIJ3URSg0haeU{6_p(9pEeRJqV1 z*&3eQAKttf+kHJUIGpK-3Vj3rd3EM_hvb{t-hZ<({!jbU|8ZmZZzo7&s@$(n8Q`3e z6>|XJwH1AoM{U+h&N|yJ2fEG&+iu6Zh>OEW@oB8%r`5r)=Q>#heYY?`lm^TIjtI8< z!t1H-H`6^gqip~k)G)gp%*pub#AkakO+sXW;lm$d3JzLo$#y5PQBp1EJ${d#}-hht%p zdgyQ0wyA#jerx4-`#XQTGdSpHY_0J~`-zU>XIffcJbm$tU+^Ta8V7zR1%AE(5q`eF zi@(13ylQ+Ha2=0wMczFc;W`%WKN0Ic9^(g(Oe)=Yav&Ft_CxWWW65HX!AvS5 zQvcPQz;&X8vjV1Kd?sQ%2_T}&Mx>9~@Df;>;vu}u3jhnQ#3D1N(=3}N zUQ7z4nBqQQ9H7knBG=@rk6?T$v8&S58IEKpOI4lNw zT0z=6@#f|s`g*=v8WfoYKhq??H1Nwup&E}NmqRs#FJqr+#ynFGSNl9!Upr3c3EQQ_ zXX>2u9OgWpQy0ktKac8YGikJBh0nze7Zxrws5p+(4WIG`Y-j)hQKc-4_!0&L#s}6j zNP)=iq4f+|5l`+M(x@s~n!pdx!dfI4s3C(beW6|{Hd?|Rn4&-`FndgJki<9OkC)4T zTCDlI$?CrwO8TnR_c&YU$71(`_`rEz-6i+uGv3C-K4$H<&qiE~2kZ?MmU{WRY6V8> z5(hCi6vJCB;#Y*J$f2zC>&^7VzZ)!OCh8Cv6*L5x+=0U0SYa#X6qUOeOFc}f4D7Hr02(T+`6{(yE1g<<1BIh`x4R>pa-X{u zb;cACv^yGhI2gBB>Qj>-INQJ!^ai=i#CT!iT8JWH)N3)`Z!FAZH924@PViiab^!>) z7Gz(u@nF00Fb5*0Swpr)hbbe2W)j_ZGu);lE#bDS9nIPUT!+Iv*V04;*~$%D%?ako zcquVxIo^ppiuowtot&_x%JS{35Rycf%M!MuoMw_EW#NAO7Pyr!D~qS1u4TncJE-Wr+@uA6G;Zuw@m z6R+7(o9v>y^{XD~9(o}~)g6zyy$#s+NZsD7D}pkh4th^1Jy6Pzo8^btm|n>&3AnyD)s$gzV8oVvz5E1N(BI;i|uZZ^A_pD1!i$u{avckAnqt!O?5*es$;T z-K9_4!sNGGD_^ay|G2$HRvod`KTJtD)XbiIuBE0)`h@PIr-r}!6^#KR9sK{kKnJd$ zfq0c;K$v*-g}H+fP{usQ0R#jLPN5Xd5Vx$%1v9BW z9QcU8NvI~C8nQqHf@EJ5L@>y-9`ha%3n;QY%XB?Vu?Gw8O2{S>^C)hMe9m(yzITN? zW>fUCC;(_U&TzWU6RQot0&M5Z1q=nE#UR*f(8sjP#X!k}tF`z5jz5egNSLlh$TM9Q zM6}p=sC~&r2{Kp^@aPNX0+gg-Pld-|0gYyqzGs=fz-TNwjt!sjETT{Tuqc_xpkPiTn<{kx-~|F&HAPn(Lr?@RcP-Rfk?v5(HR%E=hz z52-{gHoEY|awjt)Hww*l>aCxXN7UnG-RbAlWvf*!MGpz>Rn}HZe2d4ugUABM}~Sq0I(5Zlp)`t4_j9Os4XCeTdtDfe zU}QDg;i5cqFfVB)(UaMsJ2`eX)MGE%?=H)cQ)i_p`&Di*MuS>nGj0o$H>yhZGolY`@-O7I zcNN*Yvh0K82!Y_$x3c_K-J_Qc<%<;|GsUsD<;gcqvJay@RNf!8)E;z7&bw+k$leo4 z+FJRlDfL{MvsIeCU6grVnR!>2eqNW!xqH@FbScSx(^Nvr_KCdUrlpp2?33O$;*0>T z%XY;@XWf3IY*${kS6@Yz(RFj#MUV2n6R%l!10ix>4K-Yhjogp6ZP!&2nR-1ja!#O7 z3x#hI&h7KY>|>#jG;X|YK+b`*bVFLSDlG&NwiMMk_zoHxj}`T2ZI!SFCvBalooyH- z)@n-*+ZuOU8fg68QOb9kq$eGXb9EJC6$Nub*;#ihfkh_*%z;9(ASvH%>^$%4-DxV{ zYc4o#tvgrNyzZ6Ub=MsA58q8re783DTTb=4_D`cVcb$1x&1w84ku!bRTl8+E=&Sy^ zD`m$?cjwhaJ)VbG!@X?r5!n8)HbF7lhl!4_r@C)?WuImVaP7GtZ3PQH&X6k9$0;sc z4Yx23Je=VzEcsuew(V71^faFLHi89A4qyQ&AnJw4AetPaV;YYg#sMPca0%lqAg&uA z_-1B^cyI_7uCs3GacA9WZxd}l?-s_ziQwTC^(hIZh>pM%aTFk+dPA6?HuT%g?Qb^M z#VX~~%{THWEI~$Jex{{CNHxX*bz|t@&!2MatFS<&Ddk=@Dg6Io0dM>HJwO0&7MDPH z6U3$hqJ{_~f;)J~BVt0}{I}E8uz#jwr~SKyt1?fajc&%hG5%|of z_<#iuYa*ZNM1Ra^;*RJv!|gK1<21vW9T8Z-T!8!dGS34nfKY}+R?P)q!Fi4wSioo4 z5pBgeY{WT=3nG6L<^sYEupT#&3@zHUM7}rrg=Vmx7(j%xz~#{wLCixd3|>Ya%KP;-9JE*2SxqsQVA`XRgjs?_Z^%Nv;a+pJ94Z;-B)rkxcL~Ldz2lw zpBJ%GoV1=9c~u^Bugtsb=sr?3Ue^ZV7&w*4Szz5t3+`l<+XX3W#qrm*g?CjsCqkA$ z!{0_`{3jvfy1kC`bu&M5svwc}hO0)|M^2u;7OK(@9;G!n|tTO3ckL1IM5=6M`k`iHePMKz37oBJ)%7)X{ z+M{L(HOy~X%ddKcu6O;lmp$zqUYEViB0t(vvn{JVZK%8MXt^2eMp8qR^LB08T1CcI zS;kp?IZCFzhVr9^ij(HrO?mlFW8HpJ(RR%P!s)?M{>Z8X*`)K-uO1sv=( zKd>ORMd$6Zl{VQ>dG2II!CGy_p`!jsXl^)YZREelPE89MrVUx{Qf(dp1B9IQHD8Wa zy&h70oKpUNz4zOhhSz;%uX-y_n~L`8@=ivFUk%iK>MF&JaW8tl6EldQsrr(aWV+fJ-EXZu?pD&_ zK%dXu4zon8ITAX?^wM(&G1XG6ElnFuZAWcgZ+(L>6QeX+%Ss=&ra-U$7zCoB9NoAw84X6FJch#EN64KccOpV$ zlPN4iM>?GvgzgSQ8LTnJ0XX96Bv0Ugi<^ZM_o)OI286j}Z|rG&H_DFDrV6L2?qI=f zfzL&@8!Mpe0&lQ@UYqkQR{(;OpX2Y6MN+m`U@6B=|2SvLUo^`CUyG!Gx&mlXIh?*Kd0|3T1T6B3U)*>x`Jl>bM1INvD6Yc zfG>tDh8oB-H$Xuo_7_lX1}Utsj=q$I4+8?1>g0z+K%Vm;`T6tP_&mP~1Y{9#3P3zu z(8nz7MJzB+?=)vmSfX zK~I}DM?=KDP}C9!^Y%cWl~}ihXy>^o=aB&GsR&mH;iUxsg=p`^SdaB2@680kb2h{l zQ4xSK5ac`_6R?^bG7|1E>}9;=ZL{iS+v8@_;^*1o6)+a%xt!#+m+8Nq6*v{^H5BMH z6=1s=>adpRzMPkPR+_d_5j~e1M+WIumfvJl04Z#JS;<>bZXb%Ghci={9WJu{Cvq}} z%j$+BUANK#ZxoXAmZ}q>vE)qAu+!LfS{QfNGrXP~zLV**8WT!8&Z&@ml$)@d>~|FF zHjoy-Tbgn$&E1ige5_48k>(zirJbb(@w>hf(m$2QZ_3j*1^C{$!jMtt;}~(;>Ydtwu6LRm4`O~ zj5Y4-g-K#uzv^qaQI<25oheJ9=8xK#3q&lq8ij)

CM#Zk%c}5evRqoceKb9@gOF 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
Aw(;*b*8k(-;=gYw|1@O#rnUN4 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�G0T|j0%MX_C`<_TgMVP+M4}8! zW=VRwOPLB5Sl6!^1IQKmR&R;gX-bUY$uw+445y-jMO`4WmjNcS3y=8>egp(FCyaZt{?SD9gYk~Xi$jkV#@^b!?W2RsA0FFwe{08` z;Yz{yZY}4j!AJCLXT#0OO>gX+dVBXAMx}2p@3^T z)Abs^bUbXIaU{1WH#Vtded*Rozk4Ciy*==!7F?)-8$q<=}%8Z z6w_!>f*pi(_ZYRKHuH|GjQPy8rEKSFzUO#J&b9iY8x6rb4T0A?%0HXzXMH@{NwWyO z0b4uA{LktCOm~0<-)>{DywLr*)CrgLo7t|fC)%EkH3JF}jwvsGzqIM6-6MZLG#$Z$ z|8jEMKaMZ_xPR)qz2gE4c8`CzW77|-V}IN?`TgD*)*tqa^Cdq*1%ct|k9(*8%c-3( zjrfvb1LFV@qI`1ue?GJQ@5g8Ud~oz9X?4@L3+>NFYToP!{T}6BQ^B>myaNT!y#en^ zAd4XzguYG@Ii;^utIPC;tYn!hnWMl4Iz+}7*3qH?>@g%_C+7SP`G?w4lm_GuB*}A> zx;#7!*GKWm==Aw7PEA~!96s4mgQ>&L@`7GhYEe>xWK4+0$HEY^fqo&Q2CyJQsR07` zV2a(IiF8anHrT>x0;QQ!Ny!lD8Sy0r2`7Ib05sy`NgGpiGV#M$OLgTB5~JvNvM^O# zSwH|sqsTa!_mha@*Ga}|M>^92x16Euejx`qu zD^VOsyTdmJO2LBHhAUs{$R`|?1tNe2Vvx{T2o^9c;KLZ%#VH5)DL6wcZbV;cZFlFM zo3ql|*X;0AwGpK<`UA}Az#eW8F7rN$3QzzXicB6NzvT=qyfq*=MXVknX=~Vle=7d~ zpmn^Z@NiS!(PpH`A;_kudn<5J;ysKI4nRERace1J%zUP!Tzb426+t+H1^;v@6&VI# z!MmG&4Y0wk=;N^xN`t4P#UG4Sg9SoPK&Ots?bevGsHyn9NoM6(|EZLPDg}r@jesphl|qh;szxuVYE9}ov!+fjuTjNUB}EUqQo2&q zgq#i7bX~?|PWaRX$Of3>an7gSfYQcn81m>^Vu1?FiHPe2CPY{f5nzBn9an&W1tkaX z3E^0}Ru{~>EemY(8KwoFWxLBb@6zp*()HUM+GVE>^SBkSku(|Hg;w%Yv7DoUkLBFS z9NY1{bZn`2`b{v8PFGd^_giQG--nBDmZx>3MCZyjRwT&+a{Oex6f1HC6NH_FI*RXM zSE`D%h9X#i=`}k)0P(+I0Z9gAnBgcp7U~Jy)9lT8A*LczaVLN&~Rqo5cY! z1z7BcO8VJk>$lVe->yX&KqviH>i%M^epuSXp8wPCv41F>wp|9WKRue&$>eb2x@cK7^kx&6njO9=FF4v&!rQPq1q&D)T-Z_%>-1PNwnw$n<4vIm7Qi230S6z7 zl!6jLD&>`-Fkd1q`*@sMAn?&>@$0=o=%>5^8>81de6O};-EYr*rM=)rO*&XWU2wD@ z6^}PKk%ZCk0V2t)Sgy!RNT9=*uShPGCpV;~)|kvSDkXAKVM0NJsMerrG^q$M=rBSp z)zquwu%e(x#Ndve4_F}F=xn0rLtQXnN@9wP#u$PTJ)%hLy$Ca~>!6&n7!Px$B8XrI zJt9o2M=eS`DVP*YrxAFmCa@1u>5@aYO>!I1m9gjZSHplJO%nMrF;4RijYzo6Fdxh` z9?5s%E41h{Zp*SmERXh9YYlp}g+Qq;QseD{l^%}*Na`#gqjy}m-HuXDL~ z_YhG$_U>%>R!GXf?YO^n;KoEVV&kJt z`PaaLO|9pLI$oL>fU|PrkO=^v0;?rE<@SLd$BF zS0c9PM2YWmL-T2z6Q0tQ>PkEu}nMd*pr_u&A!oGjA$9V zBA7;WhrXRbV%9<6@n_Rg3*;dvL|;v}F(&wAOYNuJ%yj_=SQdRc-u(T1?_ZXO|Gql* z{m#wk4SwD?$(;D7{Zq_&X#s%+-)!&y!>-A1b`29-k60Kk5m@k-{YccLr?Ug!?V6xE z_-X&-_p4jJUhe;5sq2q3^0zs}mXhg%e^bSdfW^Fj~;i1_}aa$3`xX4IXSLIZ$7W!OvoOQI$?Ti$NWM#{^YUV=!qDEgVI}^&=SyccQESGw*CEZq>Ed{d{N^*8o6fRd_S4zX5 zZjZ1Ty0xYHrT#LofI{F}MH04%uBQE-7XKUl!V+{qNVltBYG zd>O$4Q4w?qfx+31Sy3m54ZnL$i`G#TfdEk8#i3fEQQlk?DF-N@x%q7lP2)*8QxK2V zQN*?nh|m{eoo@>=!(awMb$||y&3|tT?$rTm2b5{Y5hwIjp6o7zW^}Hv1{-nd&4D0R zq!AM$fdyNLu`GT%R*Dtf$75CWf<7Lv02J8#BMYxO@PhmI1_~Z`WIt-pX4LmeTP`k= z*Q=e^t1^z|*_J&fi2an5b@Di{0B2HqM0xZXRSK@8+7fR=QGijYs0*s}cu^>*w|lI* z!89}Y(Wp%jk~5Q%C<2=QeI^Av|ByAAy`6c%W{Vs;QN*j1ju2#1p)Obxn4vL)W&}F0 zs0es7*NBzGlwC)UXvSffP8GuAtqvX40nMQuk`GVP6cQ*&ARvWjU!H?x;X?s8{iD@v z8|^NHXM6mV{?;A2W-`fc)P}#GY5ULH>#wzkuay_fTa8&U(QxY77X3=KTb{@Vmd`)j z2BNcb^`=sryT7P*d&fv;Mb}De^E*Q|KecB5Sgij`efqO{|0R!YmKk`T(NM0`WF#kg zWib>@g$lhrQJ=_AGClT>HBhbg@w+(TklmPM)eT z`xIIJl$=bXzBsqLziWG$MjOBW1;{`0*eJys9DoSy?hG@)4g&5OV-QK>{zWSR1hjjh z3NbPuJHR2+;aG}?uO>Qy9*#w%e{eEO!W9o_;en&NXJ2Q3e zlmxYA9W60SuGwRb*$A68;3*7QbIdO!a+o7E%_}!CBBm!qoV_A?J^iA3uVlMA+{j$` zQod;}B??Q!7GKFq|H$J#Q_psGzCBd@N`K|;{*s524Uf0>zB1c=f1&^JZt1-Pd&r~z z^3=Z9R>p3Pw%i(NCiCem)bIAv^ZkvNhuUsT4`49yVE2xP2M@e@^w?`BPJD3m@b6C@ zf3RBnpvUu4aq4QWVI{ZVRB`%CQg!zA+PoL5^RCt8zuZ!UW`Ozc%eB7yHU39U!4Ee# zywOqqT5H*z#^T$}W#>zB$(_J>3sEIjS0c2@stBrM{qm?6j3V6Y{;+%Ohdtxpt&V=bdqTt>Y#aD;Y2v#* zvp*l+_S62wKdg-4Uh(Js+ej{^WcUMEuy^9CrT&j*n%|qKecD&?MsvZ9O3#_1wAF0$ zbh@M)Of_wB*sCr2a)Y`sIi8iD9G4xxF|3tWT6AUdXcoExtmO%t5`z?jwoj+2H(Pws z(V2wKL`UUV%;_o>-5QSGlmqO|l&#!kC8?04g9Utgs0(gwU%V+z&?BNQSPc8Yf=#{* zJB>mn&0qm)0r)`t7@@5+fbD=7VtGIQb<5B1tE^p-f76;m1B*$z{Edcn$%$JHChqBG|Q#gPRrAcj8tQk z)D#7H5(%SH1HN$D9-AJ$nQ*Ycdm4dRs&Q3)Zy9IEYdq#{S!Q8Wy3K7^aHvGWncGAf zG4fy($us8Uc?_)c(vhD*8`&33J6e(k$Mj;c_g;PG!+O`v)|^K}#j9oZGF7}gDnT4% zl48Aa>#133c@o3TNr_l7w+si|y#7$bSW)VmTk7uB=EGhsPh8hy5%UjdinE(c+Gd3& zAlIZT2P3%zF)S zTB?R}d$Ch#F(pRjx~m#0C(89{m=j@9#Oa%&fC(^lftYFw?+JxXp*6=P0|ypjzctYt zZ~>y5%QwjRb0?X|8>1}2qD2!Gi{1?S1$BrvHVWM{KtSma5C8{Yfsik(+dx;0+{#i{ zwNF!^eO^U0PB7JFjoZk-?KC>d9YyX~o#>efmb_<$syo+zd3Lvkbb?``;<(Y z{(2UO@J?UD8|{@>>$1_&?N+J8cEm8-3R+@=t{_N!G)_iziNm&2l=!?u6=7bXpWx?sTT=t#F`N(2>eSPvbD za+=s<9w)HCr#CV(5RVom0MShfVNOTmh!3ME6V?XDVkodSJ7)6-3m6{*3g8egMtVfx z1?MyNe4-901b_hQg2)Z%fV9P@P&GU3(oDb)mlRu4+@6=qePmm1E6-mj&0j1lpjbHC zRD7|s{90ET(lU6WEKdH=)@}|EZ&`M_!T)Q6=$}{+sSCgY4D49gRa|Hfu()9{*J9U) zLHbW100(Bp*DQ8;3Iw`Hi~}NlA*ukHLfl7229zaC4Srix9pDN(f279Xij)}=5$i}} z9zgKx?6|X-M9q_3rH9%>r+NkJ6!sCMBPxPO{=u(Uz)>Fv01FTgd_b!4DE*>{4!Hs| zNLZ$#cf`nGxahO_Ca~b0&4qAEpALrJ>CJz&*>}6fd$-uMCt;zUPMB*vgj6b z3RqAelVwD0^ve=J1ZD?fcB~Y~rxK-38ht(V{KVw6->o&@W24D=GRADsJim_Sh+mslpHVWE z9(SWW^Tj;(6c!vR74rKcRZ@p1MXEPxiez#R#{Nk%zgk{xGE^C@St@g?Qbss|LuvC{ z@gs2p0P{rlkmv`9X)uK6$eYZSHmgX0W{huxLemK*25YKP($LV=5Fv#h4B7T`h5k(rq#3Tv`pji~bf^4}4(-E?(sSEn@ z3XTl)Au)*51uIp-@qAyqBUQ@NY2lRONo3x*5l1X zn4$neDRlwE0(wMDjTsj3PAUkd%%H&ewn9b>-~vE!vcVq#0yc8sKokVh8aD9t;ks<5 z0F(oq`NhWG9*j%}c#(VHATlzJ3?Zl#_z`~Buh6nKjfRW_OX*-sF4BVIfD04ru3w2p zr(27e8l3JcXSfUyz(+mXRf**6Sa-R=0@P&@EC2|wmH-Rj3!ykbe)h>^4WIxPP!|Y) zqAelJiQWekhJx?*=f2yU2NpbpM^x*%Q|G=@=e-!Rp9{HmXQeD=*hbSWZCY$gbZ|=9 z|3LwIL>QIADWyk5`CO^NpF&E;rlQHL<;m&PDcV&@d_I{SqiyUmDzGJj6g1{E!yqNk zhP|EHF;+h`g?I&`DW6AT?|XFdND2D&iJSC^%mu&#dO_3$LTqN&Vo|qdMWF^D_|{gZ zanWnqYS$1|zsqahDrFdvQ*QU_$v|GtN+D|=wb!n^G@cgjsS6I(`thhdTb_2lNPj+H zqr<#EXxI;1D&&8&CI9uHagQmkHaXs&5M_|ZnG|wy!j6xk_mLut6UUhZ1qKh@p~hZk zZm%z!j~8X{(y;@wX97pe5}rItuM@ zWHBQ^BZlzatudKnvHeAdEYS#BFZxY!u|i6)F~+Y>%Q3jJbZMzFiib7HCOjgrKqe9r z;F{8zQbtG1H_`%%#czVN9KqyESZ7Vx=r_75UG-AS9Q;?!y8on2W>%prwuS1`LlD9B z2^%m)WyTH`$f9MrI`hTu_SdA&l9#LPFP5s{W=`c5A08O}@W}K>%XJS2iyv&Rd9kwq zN4PgfJD)5LzOifbE4#M5vONFz@WE#nPe0thd~fIYOA{>|ey;X69D5b7OMs z?$X@L`**!^V z3|((5yj3ARHdVZ_rRt5r%2!$|Pv&`!`_eCk z{8vi@hx0tssX7W!xCx_c2^wQg>wwLGVg?o_duyZK)M7BzE0yh9C1)h40tdss)71sH z8Zw`b)O;`?mA&5`el}PI7EmOB1>cM|M4;i>NG)jbY^w2#`L^$u`*5ry8u_P{QAz{B z6k=p>aE2a{fQIFnZ+4A-xpVsKU9-IM)wb~uCt5z7X!v-#^~qor_pkSrzgV3uA~|xb zQy$%bLyLN&%%HC}oBJhK+EN}75xz0xR%t1VnPjSpFNteKbqP+M&b1!!Dpy=dH1QT) zib)$fPEEgBQI7?2)JDt%98nu`3_AVBC=3WiX~19>egJXywCWYwe6>NuEk#GQXZlVI zZN9%Wf3CN2M@i0Vb*MAVg8W!2Fz6kzA_)y3pfq4Wfd4s1`b?z;9x1`x^6(G!@cKJ<$|GgK)Std}^RZiVTRE5r4Yo zL(0vwscL2fpNy4#JX-p6W3{L=Z}81aa(V|A%Ken`R(;KuVQQrO1TYsKl0$YVK_%HEQfCCuOxV*`3^P-DnYs3HGY6((b%DOH(X=qU1;a&pXB9;G=YIx$tQrLRw< znR25lHQ9r_x5^#H5vagqHOI&?DvjS59rTxsbuU2SQ9buNWsEFoeUiiAwd>Lo*F|xt zCzaTqKx()k;~9R5k(daJvH@u^dpjf%V|uuFK^a=fW6@r(Z1f zu(-KUXlF=Osgq9?xE}PDe%Mp+u*rW1E23)OseI#(EY-o1^h*`FM?I7ex|zK6z6|?9 zfnyQS0p6Rf*hh_1G8OcsOQUtIT@XPJDQ^^hQ_dqqgvq z-m>=xYd+Xq^WmoQ-}jcXKGzc!f01%ahl+R%2*o5qu&nvd>$DbP!tFf zQ5<#>YlXuaF7P4{Ac}>x*Lefqcy#aB>U8189IC!bI6V-`%>@_Q!AnF=;3QOCmmTo{#t1w;B;NirM3_* z1~=LT7Tj(L+^Wxgu`26wnd@w+<4mbzC7Art>frS)Rlu0@xqr2+{}&>|eCgJT97l^Y zHCve|k9uCdE?WLvyhCYi&8-;9O5I-Iz1!b#sw!_VO<84-xuVx0-kj}B!8gOxt~XIM zA?tTU#giauRLU*M<}{51AG(U{n!>a|t|c=yL8o~xIweVON>nK}($TSG81l+JRdt!+ zY>ggEFBFsvW@RyPUVBz&^-xzyCjmB0iuE$haL-7>Is$AG&?dW8#sZ6%=SvjVzr;$+ z+aQiIP5=%x4CG|`JX>CoJs7s-V=E>Y4UwqJW~f81bjeCQEYe4wjy;NZsj{sQMH= z>1n&VyI$Kf|MZCTXr}E(ciFA367p#tPBuT7YJPRD`;~>k-yhoX_~5RmXO95{ADle! z_TGuBvmJO}UhJs7(c5^gtMc+_-?_2zN4ux)FCTg9(!Gyv9{Xge^^KO?gL&y_(WwYV zoO<-<(8h42#ismNuJd?-cej*jJe+So7D(rMq#*5N5y?#6<3T4H6r8er2{H9%#qko? z!^W)pWP8{8kNYe$sR=`A3A=;NvGlM#{IIp?&936#_cD{Hc(1SI?H;k- z=@aPi(QrL*@a1ebY63(Acv$~s-!xc&Qh)&gxivrUp88^O^XFSPeY?ykdFq?h$uF13 zKHfI?(MU5A=qG)Z_gVr3Cmk%x*p}m-^?Qiy-4XU}D{#$cSs_s@XGzu-p9Q5$yE&=N znAl~NV;j(-is{f$a>LkAcW7g~F$qgiRw$xMlVhmlu??u=a2Fq!7axnS0Gx3@^vtLz zuz>7TIx&U~(FEV|k>Z$Cn51=}8%v0-aJcvM_TF8Xy}YSwcWGgt-He>DAvL8;vY5jL zql@4?+CdZ*_^_kQk;^l6T9Ji}R}rAFcKBy%z{#Jjo<&^{S&=Uz`#)QK~lHCY&G^CgSfF`Oc=##otZ?9O&c<@pj>@cRghuPH!Z0EviTvl)7SWda=z)a4-! zW~-*jb7PkeUK$3Jkni%~)qE=Sl(&_oif)Si-4y(JJz86SfMmwT&^w-n>3#NZf<3LGm~ zG?DNylHMV@W+1@+4+>Bt5K(|L^(V}Whl?YNIRfOONKx>~R0YywLdf4A%6~ds_0Fc8 z-}i+dw7Bm#X1-MEzEbKq6)+#p(eL&d=)|KB>omxlOgahytS3S`ZGlS3Ck6r;wsgg+ zWa!!TCJDuk8prA`GeTnx+#|4nC58nlYLQ_Nm5Bb2QHJykekt2K6JgZE-Rk%*bwZzM z4Fzziv*GTk1q+1x1XX|-S19=s>pJ>HLTHwb6_IAtsU@&=-f7*D?Swb9%Vpdy*)7v) z#^H3ujtn|QKRA9^Ys%>np zcDc=xpwp5XVDRRo1UkZSL9 zk9D04YJmT*T*)!wy^Z__SJhU3-^wl|LEMAkEQav zm9nk&_}awS4(zN*$xhQTF5*8t1|!?-xRWTco*R+O3Tj6_DacT`;q!tj5&lD;-N;;r z-3dO;M7sJyv4e@&!CdP$+%Y&GYon&KQg>y0HbZ>S%cOkofeg#d+QJJ#*EUPCWK7=a zO*xY9=0%{0#_8T{A!|giC_x=9aZ+4D+w`=T&-Ox%$zgQan zdS&9<-BZuDZ~17n;jO;12Q5KH;}k(1o@yW#j&@mo7m~g{T;`eDo1>-7KgPv zC#&X{R4HuGdlM5WAH{%x2^R-=naoG;D4Bt;C=JBMo|MFgj*s4NoBwY&zkvc<{ck7` z`7WaeMDr~EIEo9t%ithAS&0W@Z;ofAC}&$Www+Q46xd#z$=X?-OIE>LI2)}Q6jM@d zVCaZrI}M`VA}Ru`NFfV>1?={bPElkcz!kjU6<()z1RPKZ&;nvb+Ch=h04$&=;5`v6 zpp>9AI6uw*Y0U>J_!+Q(gZ=52g2-HetI(Zw2%|gNPjsn(33LRaE?^?i85UyZcF`#k zJtF1>T_N5KAN5Rc>2FwovfyHOB~=4JfCUEbbqDM74%FoeOzAC^B831D036U7q9Wjx z&u3}@0vbfDU)iMNr2xURnJT6UpNv(!yE*s$&1JtI$fYiLrOElADeL7%|4p{YlC+Zn z>;7B|3>~~8Fpwb5n7SZ8Nk&nSl@Je)h%cd7lP-RoiV5 z3ldSpO(KE?XbLD92GWF>S;!3#!K7Qq?dEBxEg~Nf3?kx?t;)5sT!i0@yN%+C8PVDk z&iI%wr!%ed2E}5URumU0YC1*e3(Vsd)kLacKGQbqv|U4?f$ z!}q$1@vgs1r>ME$W`qAmeKzZOmFL~b_Ww9O{Ml69cPm4$&3E5+z*guPG&Ya>H{th(a!vZCEE;w+@R4G6noPuRUqa>iw6vS+Iaf!CLcQ z=+;t_4LK>9L^{Nj>&oc?Qb+rQd3_sMp` z?8Em4${&o>Ln0;H>E=`youUu+&OhEg_u;Ai6a}B0Kk?+y${YK(U*Fn!cWL-|cg^{c zrlXtcuZ@gdADh3wXa6S`F8%(*!keR^TOq?%dqS-tx&cv&=+!yOB16y(@guliPy_Ajuva606A zqQHK+*bNrks`B5L8VkXKH`Y^5?c+!dWV<|xJ-ay5NTj~IUuVy=`3$P*;SU_ut z^FK7v19M;j#36Qm3Ix9VZdJemj?;_`_;|iMSoyFc#1ZCnkp~6Ek>cEKS+4E=Ovz!S zAxc}dM)pD|?q9-+4YQaq`4gYZNQ`&JM0sMOS*{HmJW)~Ev2mGE(Ofz9XU50o&=FF| z3SgmqP}@h?w*NGijFzgq21?EVIT6fjSc=C;~-Vfdz^UFOYV>($aQU znto+^A`K$$K?L3m5KvHXrIcV@m~IcO{ebuyQ2BLC&=KIwf2N~QFoIfz zu@Qd+69~o!$jaaa9cv13;73OQee~Blg7Vn1wcTgFT|t(Pyi0V0%XPS4~FOwiK5`2b-~Az!wMd|_$4g81BBjHjZkIV}oF>|~K%cb}T ziHI>X&t8u~(QZ((7##mLFJKR6VbC+^G;d1P_gd6j?8Z^MX~?YIVp1^|j?jm|0;oiQ z!f2WnMA(w1p}8c!m7*35B8Q&(g6Cec>7a{}M=zyWX1!^W}VpH&9ZQxp6!R^-km)EcWIJnypy4_Mpa1U^BtKNU3!1h*s&Y$Lszn$>^X)gHV zOz?|=${!%QFSgw66&WZmm1nyQ0ulT;>f`WCTdEhcD{UrKjthnd(f)r5Pr-+n7<7 zRTE4P`iy3C?C->e4>?qHdXg=2U7Et;Ryi7T8>y*r2T0drWI+dse^TvIrj@$Fa6CC* ziMjxN4lN+Q$D(r3Mayv|$}nbzTqR*oS(Z7I?vN&W9fVXW{sGltynC8?W7nd`L-ZW~SK*-3Ufunp&6muQ6R-=UZDEZ-PO65Ci`C8HgsaR{pP~f2djJDKY94OvwPm^&AAX(4WzCR+$({sR zzAUyIIl#f#%^%OMSJMgIuslYqSNBy z)9I{`6dx7sj7z|f+8!0dmHz<%+@hAU0#rc76jWVaP*wPa?x zi9HsQVe#Pv4hk))xJgG;W;m1byPPVx(D4zu!P*I5^#A$C*!gi+;U z^8ja);qMv{h~1u(KWptK^lO385xR=G=-Lh+sSfD(2ur%w0F8X=0_Fe_M2OS~?DuT^ zk-eYabG2($6bWDhlZFU9@LO2O5*Q*2T<8=AM5kNw7(X+U78E1cL3mO((?r732!|sv zGKN8PzB|M^(M6a+2)k0W22=z9hwvlnD30v>;KG_hxfDd8KmZ^_kBI%B>qo@cjFmG! z;7X4O6!_JfZlsttk(d;WmqxJQ!{PF``u%VB6~Eq{`DRz}UX$y7bN0CzD zjB_p__Cg#0m9AJW0|ICeQ5sMnlqizQ5iV*)$W6IQO2PscaRD=eE~Bbrjm8}s7Djek(vTsjco8gs zT!h0SE=FR+;8aiAOv@h6?%d4TOxLKCl|5Y$oXE@GUR-#xv-)I9*`e~nL&e!wm=!hn zuhybH653Oe4R5vMQ4Bd-0KpxwfMTu8`%#zgr~blkTfFa8Ti&eA{%CXg7gIfNcZKgY z`!0u4kGoRF)6(*_T70L;Aj{Th{YrUy?0VDs-;w-bgDa7!o>f4HPEcr(k7e6SVnKR4$EtUS-u(KdrW7YgCx&@6>lb)hZ&oyLwHNvpemYiCZ(@^Xwacc~wxaZN4 z$)mu6L~Tq`y4vW~8FU+xYJIgt)o@BPC&yV;GTx)!sBk3PnFcWR{S^ynkZLtP$-e#GF{ulR+sHBoUrfbZX-1Upuj}0Wd*`%nsIs z$)sZn@tQSREApf0B}c`SI9w$EJ?_stkgFfCr?i;NleJRQ{gbCYIym%Tb2fyGN0S|I zj#a)nS$TJ)^^N(_50?f%*uMiexlhj=d*|4Jw+`)j`^aw6$R6yRerde(=6K)Dg^_a; zo32fa+*w)t@Zx@KOW$ZqJC$o_Q_C|H$`X^Y*Qo5(CN>zAgC-rKT2fWXk48upQj*9b zLn7>x65_JrV>4o-y)jWNZhpN_T<3|8;;@>5XJ%ZSI{|rlyelRaOH8pRs+8&SgtVBA zP%05ox{~7hHL^}^5^T6-pZj`!_)1yU#gO}@Qvao}^CBbZqV%h!p7X)9lev})A;;xn z*NdeYz`@OOpLDw_`)*CnYYq8tv;^O355M0p2FI-TH&s#>Fh2f#s_pB!-fy-I;YUh( z8J^S(h%q4j$MNOA9a;MR@V4&{Z~fuO;aVot5mw>a&CB2>c(i>hA4bM zVS~|+%#bBe<@5hE83qBhlK)i@2k?R7Q_Tt8j;?)8eGCg3EFjyU*l5axe~=grxpcXu z^;BOMbpeJ^J1UCk5!KkO4H#RO81?KD-b9gnjFCB~cd#Vakm5>GGIXLkpjm_%EnP{v zGQ(f7fPhGAhEI?np zw!;e)XfNbA9~l!w5P>Tz(lQcpmhANG+-oC)E1l?$=@T{me`LLPaNBp9=K1ek)!t6; z*piq@<2X08KHft><@0zTax1rDGRXk(`P%I1W5Q8oR-nXb412Lsh}L$x#u zfC!BMQX)_QEC2`y?fjlENFxG00$2bv2)MAm8XXa8B6g4&6R}*tt{Gz@dV~*GSHC|J z{%CdGi@_j$!Q0*b`)z)J;7XPKV%#zx$N1l{$E(In4)-{yff|LBz5u?Uj9VqnEdrqo zcZ|fSS(8%qS`EDxE%u~6yjd~9vg%ks=I~Enz>JCd&v_mx(H;+;LMk?kH+jt)+(N1) z@*k8A+g;iXW*IUe*kLYgi+G&HwDoSHF{SG*G9k~#W87$kcfihCx6NsTZr<#3Y>mb? zmBlx2OT>5A)gP$uKHFJ2*B(04eGG!+)*5_*QG=W_$Fl&e&V?QKPi?ixiwFOY#VZM~;d4s75UNpQ0TmvC5IFv}Kabf%T|Ar1pn(A&)NDQn{kNq8DdRyruO^ zG6f?FowwLt7S{Wt7N13=b1B_*;kIgjvRG@@XD?CY%H%n@NKIKjb1GFKn_i!p7f}1E zoN@V&a!_8-p}VveeXcH`^{1iWd%A$rJ%b;iCtyg+`$(cOisUwpw%F;bk9T&~kc(60 zRTaWP^K*028~_FEAJZA&B*A77^fG8bbHIrUT^}Sm!~*c*RIB;2%$8VWQ2pqQ;)2{m z{cXIcZZz2UmsnO5dV2h&b6Zo}etO~f#|OJ^uZ%ocTmNF)!1Hb0Z*OdQyruK~J*(f} zv+mWg{U1&o{c2$j9C&B)I2klA#`eB_Xv^(g>#prsdH>M%%bUooJoetyp^r|ky*CtG zC=wBdQ7W^BL`sH33@cZlTGQ%!HL4bsvP!`gtP~EwnxEs8=6a+#g(+!)N1W%z0zsTt zC@n}|UP-=BQNR!{kT1bSfibp2oLeX_C=%y63vgM@w2N|_k^)>uaA06OqR(7fyd<+Y zJDbz?!D9QZ`rw@=AqwqgT_qIp^;$mzp=(JWGa)*I3vu`P3fHB$2PnAP5ZVD0+;1oa z3Z8eCKkF!C=Zv1GEM4zp1_jmByd&Ltd^8yXBHRa6^f|TWXv%z$swcILBmMh z|1Lj8D}aKB?O~FK`E6{3l8W-F{bUeuhq)2UWVW0Pw>S?|I!}HcDu)u07=buPdA=eR z5-==XupogjHXhxx(7iC9u2HS;C?uy}Yy4ZaPF*#IynvqL*S@a9;L{I^I4kIES z=RQaK)4hp#1VmK*-WVxnlbz8S!2vsdwmp8jzZ~8eD1hmh=_m&ZFeREH@oL&f*;y~G<7U27OWSV1Ma+9m3Xx}%Esi& z72$W6SHIm8xZP58zcuhyz58+k<7)eCh5b;#$Qd0~DO#blq!hqMQi`64LkVpGlF|l+ zq*0lY;`i7`4{uQ;DTUsHD*y`crK6`{!plLPHL|UR#@#kq%BG~QZ*b^`^imA!*4t%k zOu66#+M=}v@fxFemA(KF;2Q%7t85aisc8$45v?=ISn$Ee6smzUB4#VQt18Ai+fR1( zjHh}>W;gDd-+SoJP~=FdYCNjF((Jg=Y{zTwLA&pEljV9t3Br+UZ9>(*(jL0L2nF|B zL-%@ow>qK=_1>#}O@wkZ7^O``g~N@N8)9YqYU;MuRBf(^uXXqnAr{S$XAJ5~liq6Hx=_uGh<0%LO49`#`H__Ba^x%%i?aYQS$Rpar+#g7WS}9~ zQCS+YtJRWa%jAL@NH||HC=x7Aa|Nq9xKSgOd$Ks2OXmSbO* zvoh+xdtl?|NyAJ)ec12WTM;`rxcaN_7E)gy?0I*j`p!V*^VQX_xA(rgd;N_y?N4^K zy?bEj;m%F3PaOViX7b19=U$&a_4xQ9lE|JO+jV=_nrjEP-q^qH%BEEpx9oU(eDbqX z`)_rT$@|8jR8=d{R%k7CYE_Rkt4q41z973bPr**Dd)X3XkAAVzmL)8s`t(}2ij2fm zuB{;3nxDlj1)qyL&wZ+x3+-WcL1CUmaGDZlyQP`V+`sh8Sgp-;$n%BHpdcSlHej%b zt-jn`w_4-Q%dQeF+3Au@gmtqOu9-v$R;ag#GKyhxXgQzoEFe~`^3GQ{&qeL@1P@zc z_fyT`hfQHnfVSXiTa>ooX;$`394?S)7S0G)0yQOX@TOLmz95 z{Hh$;C4gV9Ta=aJzhZg5Gbh87pY1Kkaf@#8bBzeG~Ef1fqO!CJV z7vZ^r(Fy(&)MoUW9OW?*WfP1Ep)l)*HxTEmCAs_+%hej5Z&v1GLcO=Q`_y31dx!VT zbu~@2HVitg?G|&bA*HR-YoiJo;2YLyS-WIP1WR0^Wb;_z7RfLTS`4odd*mXgET6MK z)jnPSIs2y(ffszb31EN(3UF~J-5GeqN|FlLr4-Z|Vle<1RVY`5%Mg!_HO8>07O>!G z(l=Tk*q1EXURk^=5t!_(nHy+0+bdX2qY@JK1_sIjf-8O1SNm%&<3imP<@nBsh+Eo% zi`0YmurMX+L(mzW>xmLSke&|#1UFXHF(M*u2?9a57Uw<;fS3}2DM*U8f3Ga+0#2f! z%R*-exey%yMDdN08bK38E6@`=(_TXT7nlKh0+KR`xfw?MUOv-b&SDwI{Dto1xz6gD zVfp~h`{gsOku&WA7N9CU-X0xqEd>r}4j>A^0)T)EJ~{PbW#aXQ2FynZB_PO{M8+>R z5zK^)vRD+I>ap4W*9b^*s-UhR?OuPNjz1zMLQYzb>_XvnGDK zTz0WieW})bE$O(|P@u0Q%R!i_L*$S+GDB)=%QkKccD@Nmuq|}%#MS|o}dUOS9aYiQWbcrjF2s9Ed zBv?YqQwp2XfVxMg(ds0E8NEgFC&RQ?t9i+FABwRpsp!_0Kl9KiSmqaDDajt*uYDv4*z#y(4>{PaJuD z`ozbV7G9q@b#MQ^rziG4-M{kjo~`#L4&UFp{Qmw!*G^5pI63msi2rPzm!iRV>XWcGC@8hvv5b4kc%Xq ze2sNkrZw|NA&t~cM2l39H-|^AVZ!1hi47BF60sx#w+vD^piP(MAgU}ORwZ*8iWr=? zc7}_li8^YE;$3|%YP(+PChPQK)Ot2#zFJjut;Tyf?!1#s72i+#9yhYPSn;?c_Oz$s zX-DXJSLD@TCDue-AFgVIJ^t;%)!0t_&9O~FuJQD4whDefKlQk-s#bF8dYJ9+MboU_55* zN&5Wd24Mo^$a>S0^`9&#$8ri#lo5kR7a$-#K2+FAXJ^A3c=HN;1(E=X0y4bh@;D6$ zbTQdAFuu8Y95LiSdIQ;*p6$ZiT%J#B#VvdSf3`h6%lEc5KiaeN(qJ3<$CX9iuuPJQ zn+;VqGh6}YKwSJut=ahmAqVialPY-&(Qojj8S_I%@Rv^)|MWlzTu4I$9}31VIobR) zAQS6oJfGi{tTjiD$dn^O$EFsE*^^`rhP-`MiElLNBgSQ_EmbkoUUfJTV7CCniBwg9 zi$$StyG zDD8~+JHuR;(St6oCNDk`r3nB#&b5Uu_mp2w;Uv)&LtJ#JrTx9E%%8>rb_gi`-2a5U0xXC& zCjkW>0UbVFkA|oUEC3M*JEo^dW5KP~0Fu%>O@20WkFllhHxV+~XJ(T?)u_R;T2rZ# z#}pDS?o?q`t&p%+(44LR73NhBf&R2-sKSS2|*l&?9iW#bX{Z>o$4Z{f5Ze zNYAn59aDV`w0>Wurux6Tz5BcA@^=~wXZ`ZIg!O!LF?;&An@g_MdTzE9U#@lEZ1Lai zjNIxBUvCTD?2O*+t+?MCe`~OEsx^GPHhLfw+-P$RYEA75Ws6)YxOZk`MP-Ucx1+{k z^+^Tq-hzC=U7Eu;BXVDw?}ONY%H3vFFk0NyUNhVhs$n%#u@vf8NH7Cw@RB0~HD7N9Vd zyqWD*JF1G3tx^-mCNlsQy3%=xEEb zH{?q*HDZOPKuTY*v$^)&o&9%{7R0=4nQu?j+&+Br=jW$>k~+}yVq@)%F8|w`yB=?7 zVae>t#`>q*JKjzWJl(hP)scN4%}&3ZnfP#K?A4jc2S@fkJ-q++p1seGZg{e9)wN^e zw@yubG`jjxN8wmd-mA&25i4sk^-xPOS1VVDVk%HTjr{#%23<$kCBLbCK~eGv9|A!@l05w3G#+vUoltJR+C z)!ut`DL=8OTv*{fXbEAF`lP+|S!Wpb7#R`Qs}*%H27gVO&4IPQBFl1;)XM!rH08qB z?-ow}`rL_M&rkjO%+arpZTM_c)2({fez&Akp66S-%rBFI1&n-HX}4r%QAP=f!93cN zM}UhyXf|u#_zMDJ22-`2Yn$4ZN4yPQSCw8_uE_J|vh-WP{1Qa4=K%ARnlf*ki@h7tdU7%$dGV}h^X{n0U-AMp7A0U(0(u=;^ij1;ueQO z+@?Qd?j;24V3mTu9m|c2y#oSQV1?g@!7TeTxM)>6Y|S?FmRJOHYMO$H##HolTl{EE zDS>9Jm+h%3#gyoDSDb{HbW?x}9ijF&2FfV@>6HRuxX;uWtD(hxg3E)+3j?u*9+aIZ zgQ6F^E3fp0ZV)-Jc*Z~973QQbV8o&dNqDd`N*@3gaQzz=aPLA_`~op&ov2J>XFI}k zondPJd^fic5RlQd27><(>QOYO+%ArQV$>qchw!>)QGg55SZE?h%xsI!vs>I%1s2S7 z)eylj-C9Nl8eT-x?P!Pu#$d9ud*%%Kj%C;@qa|KM?R^#H3s6 z1R&T@^~I(}98AH2_m)=>c1&x)?V~PVx-Y=@kiOugUyENC(w`x#vQ?+6mP(@qc@c4b zxk?t-C=zN#r9#%Cl6C6U?MO;{Y&twjg;g`9s9P@TGAc+tpsKSvKs~4Uud*pP`O_>A zUkQ7_$sZ#k9ErHVg>^2X&!k)Y_El~p=Kly$(Jvtxhj|7*2*YGgW(A9DMs1T+ywdC0 z-@oF6`Qwict~|e@?2F?A|8MGM>VMAn|7lB@n1Un4n$xubJnI)4O0Tzs;0oSqF2anP z8Q6o4;FI2p2i5_pvtMg*;fR)WnclT2eSNphCjS{m=p=zK>?@w z0*;Pk^MEClg=M{oky?LKO`x{DqPscTS!ypcledO+XbJT|h%aWZUtl1FIWK!@3|VrO z%S3va9BERsy$A;2!GMDRIUJ{Ib^7t1<-a(;@WqMMAEkCQ-&)ale^t$kt-TL7w%uM^ z|8R5b%Uwgywy%7+Ys0f+2VYJdeK9lr{=}*GrcXT{+x`5+zN>o=-afeNojs|GCr`Y; zu=~Ry&%9UFr&jZS0cr}jL)7t=(mdb*!3%?bbSH#nF>Ds*&H1??0$4zIK$W9GNHIO; zfDBcNUov3G377#Id#)I86su*2!doxSUc9<%_o+4OM#`&eEKXDb z){JEk4K8sOigf`O#CeR5)CJ4z`O9jhxjP-kGnK_x8zUF13$G-+XM%c~g87JzErhcX z6Mey3RVgoh!95lY>iqNtSfoB~3qJ0M2)Q!DHSaI4WgQs;Sx}Yk-|#mlcK%^z^qct; z-<+TL=Hm1pE=~Xb{N%6BjzcDYy1wCVgY&2#r;FSeN0PtHM4!p82o~^TaiYgl3Lz!N zZb7LbYId(`sEeq@mSs!Vr&@<*w(UJN*taEFv#O-9+p0z~i=+teDlm|x0nYqXdnPv| z6%val^sF<@>1X4WCARpCQh}aVwf(0 z1xITmduxKMAPe0Bu2a3Z|I{E3rG{VWi_sc@1(3#E^a8X7V8Qnv_OS*QneP&2`NGv% zd7-D2ITD|kh6AvGJHSEuq6q*Cpa}jA3)1kgh#BRy90Kdm8Kd$eVYNEtTr$e*@>Av90Ewx-}nBbW(3tViZJ@1da z7>GXW3qR@%-03J~+w4|DF@3?9PlNM6TK_&IrFuhBE+;mSEp=u@+_IurrIZtQPip{Q zAgNR2g9YsFV&_F`&~4VRg^XqCVq}?0@E@{BH@cOin+%&|%gyrdLBXozKAVu6J=!%O zg;mA!0fu%gsP(FIMvS864i%rWLN8mPm5&&7s5#qp+R4Fz_s^~QulF|m>_Gp!+v*& z2xM`N(rE~^RP^*#bSEvrn8=ihDeWb44F`B*o;G0%)fqiWgT1Igsn3<5=5eX)VS6NG z3HdZdMVcbWWxv#JlNCpb+xl8I_SN>rogSA|1WSkI1u7vSjy@BnSROD~AZ($JCHZd> zWusYEP-b#REp~NgzFF<+?c7pn_X1Jc+*ARxAj-8tCdWwv;1V2$L>Q6gB0WL~!dQ#t z0E{ncZ2ksUBw_M})Xs8aQN1VDSeR@sYH^A*M0n~lgp?5a0zpcWkGL?0VqnM-6Mf9j zG27Sn$(rzNI1}gpCbwr(vf=Ljqkntu;IlQ+N2v|1SNf87*EiqX*#2Z|&x18BkJh(8 zKe+bpp0(Gvu6=Rj;LGXLADx+e`{bcVqr30zKXC8((L0B?-yc8q^u)xA!z&&Q`zM2{ zc1dge<>LCGC`pTci>Klj2fYsYt>hmKhH=1ZYq=uu~kt0#r1B0*IADDuYBN zz?ho#I}X7GOsd6225nfO4T|zB=Vq#Y$rX6nGzu&X*S|q zD0f_|F1lWs^4_WObKR^ie%Ka!*irVNCHSZ<^t`A1-Ju$Q064%#g7t!59N6-^$%B7f znEK5k+etYH2x0g=;=Y`2{7Y_ga_`0Vpz7xgLVY4VK%_~9@lqseG0`d5DfjTZq zDx(%o*v2J!mDa+k_3KXdclfijYE!P#%lpS>SBxBQZ{1%RA+x7RBMRW2LLFt1g#Vq{ zSr|z}-hu^4Y-uy-qEMUi2ZVx8Ge%V3?<+K7P~59>a}~MS%8U%&3zb?U2P9*5hB+%^ zdt1+FPwSNpYp$+dKGqW76e_KhWTmPUsuruQ(dGz9<;a#e(z9E@0iHl7q4MXGd#S{! zj&Fd+9o|^N6Bc^`8iXG%S_1*~^ZD2ByOi|PIHWKpqAy@E27G~cXf5)r2zd9_l%H%4 zA5;vm6usI&51cMx8Hf2FRcfrF=|2TB5`&=sQz01LRj?+d^J9=+Iuj3@>< zA+Qd_5wu38n!b zrb9FZNv#?u&L&AgqqLxfC>sLJ(0@Z5_Zw9#oPh=CiC8ay>JrC%L}Afwbg{1*LH4f_SHn>R)4lU#i<;ZAHg0}?`bhBS3#*TN;=N<4l>(rv8B!`u1(zVCKu2W(A>9Bdyr^UYUOqqM4)Q+(9 zYE|Kt@|5dVRq@?q;7)A-EV$bezSk6Z*jfs402TlQuU9pHv8ns(UCRk5_}$d#pD&&H z7L4RUj=D%Q=Pv2OQq%d;mO3Dg$(G znH~mJ`W?yIL&l(r&?}tw`LzsLnF3h=93T!O z6|#W#Dj#$KSeei-!hxV3p!9MWXGDnq1T!L9Qsl~5LdP`*W<-pVbQw$5*EJs>?3f=} zabweZM4LM+V$G_&RE0#=?eXGb8dj)jNJQqbW*#vby5)bqV-lt~3gy%RWpoK#<0QG&Im7fCW5G`yeczt*rtJ00ORi zE&f|=CD$4X!2%|tC+Q2kdR##V)uMijty!Zg7&INalnUY) z!CR+6E^x$lL$66bXi*{fS!LurFQgV@9kJ3P+2m%8SO~orRs`Ha0P=`U1uh7F)rDr( zl-GJ~7_kejft`VpY>ivjrOE?SR$7hyI#rKa-YU&~uyxHpUp@1iiP76D8*n=KrZSsRhGDEi1`lB3Gp4h^O z*6ME#)wh(^hjnguzMR8qN|uu=XB9?esj!tccq44#hXN<+% z$x3gc(h;UXz{I*T*i{qlDzg^RP;&xfyB|R*&nMXiIG~o(8aSj%us|gPCIqW!204m1 z-lX13GsH!<*kDT^0wmSaRE|j|LnfMD8a9bBS{2b<$d)Vt3p6>)DC~kdD2I1fo>f9F zCAKnx>#1N_EzVNs{l}or0#VIC3Kt?FPgx{0=8BYry@4q?OL4BB?rwdtD!33)uF`7i zEV|{@H6P5K{prb(7i&Xz`{R#O>pI^(u=eSe_D6e%pYIuYxogea+gIP*vF^^H-Or{c zUZ0)+V0!d}v$M~SpCp>>?eTr@Pwabs;y5A3PY2z^pf$_&$gGm;JnU*$n6+(6Wt(1I zqZEfolMv^ifh0GP!oW$N+$Nk7njSoSwb9Wy|5#`VpU#?X;v+ z+M!gPtg5`+klbfCEtiRgHSD)r=s8c6n2vf?`z@j|pYD)bLz*7SBBVqMk(B*Oa@aioIfe#lu@CQ5=obr!{3ZtPBuKs z@FS1y0Bd)HWJ{jr8R-m$4N z_W71&RBChyqXjksP6IPhw?Y-s7>cCAXo%^f(4ypF)>Xiu>)*)YMZ+PGB7NZ%&;RVj z)kk`?bf22fiw;CN%{WJ9WSEEyQD4M86ZbCeDe z;^9{-guHrY{>U)XdtZx7X6Zd+&h}}hApPORUIapAV1e-D{tCRI=Xyd6X;2UeW^;>M z1>8T|5#{1edLTsk=Yla7xZ`wRz>EkgV!k~DSs-jB5MSROo@y$k{zDLRd$zNj5fE5# zrai`eArG@7#*fQ@h{pvZ3T}HUPj zBAjfBramRgcwOSl4b@*#`8TmiP{k$zS6Vg1hv|6{aFAw`(;tEb^aV5pkI8fCjS*jP zt+D7*(seOzn-7~f`S3c&`hf{ey+npre=TdrG6{R@WfBp)iq&#ii@2aut?0z2l%@ds zxZ9$_tQss}5Ck0{SPEHGBL7c~O@-8_0k=;K4qt&}gt~v)Ujc!SGM#PyJ+K4QZu6pXm8^a?N|G-hs;qL0!(h zrIr&B*GyT_e8SJ3=GB(K&6c9O&F-sh{#)(-hixTb0c!DWUbC>CYBX((=+D;#pEgvU z3^-bK`6U_=D>WRw4cTup7iHj{FOlX;6?jRQq#Aj)2(eDo>1zy>N3>21Ox1uq*O&^Rkvvy`=@YIAH5@Wrga(h_j|X(%TenPP!uaPq^f+kheAw zYAeBcdRYdPF=KlLo^fa-xWyrEku_MH_U22o2|X^*6)1R6k-3yBk!M^e|hQRtCOQ2%n54Jd*dhW zpE&&K)c6NS_dnWDeW}VYV%1mabnRyCYP>|P`Zi@At`O+dIGelh%Ph#WNprdEvOIK% zGzAoYUrt_9t?%>tTJ5fYSYliX7RXdpCTo+oD5f)T z;lbnu8!htD5*t&MaG>v!DR zu>RWe{;R#UQ{@gk8hZ^A-mk0=u$Dky!37GWfdDM{9u8U;#xJ zEHKLHYxAR8Ju@PBfHd#0GEseD>&VQ|z}x!|o$PKt+0uj-FvV7WiKrlHw$!^kG!j0! zszj~FPdcpDLwEC2qc3GgMu;iMMguEw$6V=-;D5Qz&j$4!GV}|A)dZ&)F2OD}n^r>T zDL|$McHN^Tcub79CBTA{4T0(Al#ptDyee?G%E!I|D+bKtsp^-9s&Oaf5?X^H0T&>S zDgJ2@5m>-QcOVRZdeCyl7P@MLK|b^QuEcClDIcNR02Z*7>H4fbsie%N<2l@(t3`QwZojvjVdU4jO1sF)>~4Hgy=~{e<3F zakSFpab@JgFZ0fnWG+)G#3>FfI``MSQg6?OiEtstesR@kmlao(bHQ0L=L zEk-Yj)f~|wypiCWby=9ps9gCm#PWn?+Cp=!xfn6i})k=~HCgxH?N5v|mLl15<; zTZ*fFakoYpGC1DaI`n*?^;kFC#NGOWTC*{!P&3pi&dp)5s!*Em5u+E%uxBozGM30>aiz(^sxmWiq1YAV_qnY55-}Rs;*4y1sMP8mKYRG{ z%QKfgUO4~d z%S4SvEz>*<{{aF*1uATopg~U+NB7I{(y!CE722us6)F|fI#sePRT#UpYxKs@z@?$C z%bit|QS&aBq(__2S_0DJK$>h|#sn2D5}=a54gbFx3Z?r3hCjTXVOprloC%l_soz|d z=8joM1YoQ50w>HkPM?+8A1%AMZPm%%uKW8A9&2wr(NMq1tx2)DTp|^7#;UT|SO^X( zGz?x#l{%6N(p`YxVDM_SV1YIxlg$vmQ~Ce`Or$U28*@ns=PTe8V^;{+fsBcZ-A8tg zNi*Y1MK!uMk868%+5Th{*EtT;C+d9Djj8ad`q0VRlKmB49zE77oX6p2(}<964Y)5% z=)0l}g(&_I0o(x#xWg$PEMWM9uAjM(U?JL7Iny2F%+7%SOb0q3bfEMLm7MXpcn*{? z1EDk)u&*p&L3(U-vAYWT?D}A>U{EKR5``Hyo$Cz~KCn3L0S=f2CI5ABl(;caivV>2 zQ=;~mFeX|qk z^ms=+MSSJ^BNgOWenEV}hUAx98+imx(Ff})UxNko2r$T-lOJ!Y`EWxOj{ps?*H*l{ zGRkK?9ST1l2tOH!U2Swi-haginz6|oSzw{!$7lEl^OYPGsb zBO79r7*wD*-KbX(Bf_fjfJM?{mk)b%>)eLTb{%_e;KdrfWUGVzMA5EQMa2@r_J-;= zK0UniakKI32HBt1+y9@`)y}`YvHLeS-gG#9qHM6|657@ z%~toNdjE}%rio+{$FbE;>8+mdkK5uOcGjLQ5B1qhHjdj%->kP;dhB)_(m4?8NSw)* zn^aDptrU~Epefj5i^NoBUfL8~NC16-L7l5$mXiu7^gfk=k&aWVcNT@y}uR!wo6dJGEJx~;T+}UumHo80z zZ}C?jYVUqJI{xeNtuHsWKUkT3vbO2o%Enu%!KS;z-FKJwUs<>IYHI6^!+Y+YIPhX} zl$`<`N#8v^@oZx9!HL}uCimPred@`~^y|HCZ&jHmf*x|h=p=WPcy^b#w-s_Gu&i@g z);R4+k-T1}j4sQFW#K~qovL1Xt5Y#B1J%CHe{G1-sI)eH@<%N^Dk~a`0C90-(G*~uP&Yc zYJU2!uAcq+^2~c<`|j=DaIL*=z0;PIC}KHzWAUt1Euo73JvhYIzmcC+nL@C;Mvu+Fu;q z@i%9W|KZ}vzrQ;DFOP2g@y@kBz!zLN@oH_uRC$=Cn+|1mlRR^Eu^ltS&Z2l?Q{A0E2f*EyFgI}&wm zEz)%Avnv(ZVWp4Jf=*%%xX0u0Pw~^<>xX%WJz%cP6pXPWhz;Zi%YO5vbAI$`qPH zv4+60GPMjG18+bP27IQxEW5P8rIsN~0Anz&_NvuFaLo^JfZ~*h8+_~*gKlUX5ID2g z131xKz%uwGc#@cw2LpR+D{vj6GC~)RH$;wBrvk@ngL}%I2WpB~J)R$~rSvkYe`{6p zTzBZ|FnlqKW=Ww=udHE%?COZnEO5f722-~AC&V~hoW41jGa5qC$)pIMiBl~>o(T$2 z|7j5D4!FHYmH@^;YyKC_<<1bdk zo(x97g14FrZ+H7|w0N%8I%YyzbVLV=3{>Jly}U!O01L_`LhgN;Lc#t&;TIh`HR*qK zvVsm(N=n2rNly?2s~s9P1@MbW13@~Va@Z&y#)Z1rmUfr`3ved_CKwQrZ@Jc`$9i&; z!?M<4Uu!jBJ483mlG-Y#BW+^MGuc6FQA?06g~ZaJOmld6`v;SAJ4?#iG9gTB{ z!?&y4-%Yms%gy~?p4)M2d+UwC@JzjTwkmW!Qhc|{b)l{BYFi1bLXX<(PDcYNyI??n zqqXK~W6kx(y7h%#f1a2v77DOpSq5_jEt>lrfgKQMi1cD(xjR-{l&E!=m212Z1iEFk z3~XwNNvQ!5ygFklW^_Tl!Y&g>?=f2KYU1wYc8Q9eCU{b103b+X0dgZEm4zK- z#HFHK(18;hqh9uTJYIiK*bfcVq{fd`6LZA&b+3MV>(=M1x-YgTPB-HcT)rt8TAoVA z)^xXR7#_U3Zo{oT+wPH9GkJ&=Jm-{F7rB&Z3CL)NE8^oyD=3_@J=eH?d>%C%2#e^;>s; zv2fwb%V)p7b`eSJ&!=a8b!zHw#*Y1D=f)3K^}gNJJ{FEF*PA+|5+d|SLSV}n3%YF% z^CpXSSD_JOps|SSc!~W;k@bMnG#hbqovTO{UaA(%DQ?vHZ#DRD*89K$G^OtkCtj~a zwAV~nF-FvXJ+}LAFP{GM_1S;8dG^1({np>zzWVKr`ESmRvLkdNRJg@SM5SohF5g<} z*;^IgRo~F$@UWDH0~^e3i_M8lr_N}oF>0#~s+c4vq1D<^j4G8)l@;exJ5zUeY+qPD zaHqH9LQ~aPdEq9PvQ?Q;qsT#{%M=L%3U5KK1F|3!Es&roVv5GG2Z<7;8c}~53xtCL z2X?~4GD)vv_i-6J++abOLdDV^^LrjCQ@PHqT7Gu0`_Z1==hyTcZ;o%{e?gg61@9EM z7B|}6F}d26r(lUMD9MYN%`jqoKiCL?oJNcw;YFUw3ytM^N02IIi zYBL`q3*xXZ&<6-VaR}tl=TLK*@_eiZMm zEPpl-y2pZ0Uxe#Yqw8V~x$u^=5yNcMN-oBFi-Ky6KD1U|z!Z~oY~X;BTql>dX%^G& zwTeM=O1H*gqA4JVOep&%iLh2+Rbe%~&85O0c%w}w*b%`R*jYUjE^?-@sbh}}Mu5jx zSuHCZx*?Z((4|@FvW&Rx15R~^B?nr8e`WKz-KO&8Ex}L4ohvF9sjjU|{PEh!3;lhO zJgqTHE=v7}|Gj+4kB(aH->j(o?-vjL-NT8Olf93(MQ*OGSQxIHZ!LVQr|iLC-PNY} z$)NLu-+I{R=#WbpIQN*0e&+lsW#5~DR$DA&7XTEs?XiL%gSE7V(voM$xT5UU`3%?g8E z=c_9l?5$lxUr;DjYO-zR?nFoP)|GHzPMg$O0 z)G6@9*z*LQ1{@$Db*S8(mCfyuR6-Ee3%>3`l#Pyzf_w=;z%8G{=hIqnzer;c#N&(6 zfxM^xJr+3S(nbAXj$D)nlrVD;|K%H^oQ$EU?`Wd1-){2BO+KBex}s{&`gLde%C{t= zn`=UcyOU>DbzfLFbSIVC^6JF#PsgX99o_lC)Yz+;=~q(|AJ0y{nm+z?{K%t;laEHX zzJ2QWM|1O^?@8RLu^x!ndrZ3RHu=F=@$P_~G0e%BcRCRmD=Xd~aNx#ysMI?eDFzzW zy9}#5mIj?7ghd2#i5Tq{Vq)g2Q`0}0nfc|pxvyu(e=#}wtBJ#3AKLZNhPCf5Uw)~f zdZD43gaF90?N-rvNPD5iNhs=x5)UbQTU?5xQ9B7a(;??XsS{9`@LNt68)hRZ=cURb z`hr`H!AI?77@V+f_I7*t-NE>WBS|6%KHo9$^Ftec4{Lnm!av`={*U*r|I?$J-`>9T z&5fDg&hEP3U%Jz&T4xb$D%9)@+xJC_j#e`mZb?;?S6U4C>6H}Zkz)xvkko2fg=gct zN+$P7jTX7HCDt^xZp;1Do?SF$7guk(+uwG%t(wRias!F7sgvd=5as3x^szIaZM+`vSx}>Arx%jOvHJfY~Rp7cOajoz)VPE5QPgLYw_&SZUtNt(;AApF#Z=t{&2?wRcs?5NTMAOp0U^t zq&WsYe!jE$$6MJFN+M7Heguj5o>ZB_ReOrXo+2za&>L(%2Pxd3L^%g|e(n!Qnrbbs0;tsI1N# zji~LV3X>*V&IUZ2n9TK6xe5}?h&yBKo+9zZTA;Fs)p)}B&8~Q1X_3xm$dfaVcgXcd zsorHQZL3+^U%#%}Q&C}c>T(^`zJ~7h-6O+C*j8qC$~j+?vjmKx)B^;p9#g^6Sg<(n z!7m0}5CX}BSh7V!QmQ^|aGgKY7D>gJD&uEFc^8OhnF0+I?_-X22t>Ih%bZ8(_!%|- zfCU`O(tQDDr3f=ICQ^#Uq}l7la+qjk_L9bk?|ui4B*t|%J@!9s<*`%yH{T!Ma(^9Z ze#!Iw^^Z39z1+Rx$=1H-sU3sw?^*L=$H>!Tdp(+TSQvv;6pM?y%(SV6Gve~$ICSEjE;UlDXHeSSb7wgRj z0+wB+Zn6Z(Pr@M=#X80kuvH^A%PyZc<#BFy+jazfshzRdfZJQ4(jZ@iVZ_oBftNia ztI!)uls6sOdF17#J6~M7^X2@t&*v`vMX z@BQ7K%imm^`uW(pE3NJw9_0oST)nDoeghdDhhqNuwubYat*nkgtz)l^8y^Yp6?#jV z+EgM|m55A1oxitwU~c=w!$Z?IQrmW4ShN1-hHVdrJ1!9G5^`>HYKEZuM0xStf-uf- z?9ai<=4Jv1@b9>-V?$9axODJ1vZ5S{^x`GRd{}R`<HYT(KwIyTq zQRw0$HL1X8wI37^63hheP8@*h;ftYdZ;sS4wucm;RAWhp>jQ`PtILHaP^1~vkR?Vv zPao15*wYj+BZ7wzh~q&46rdX@(wx@m3#jp&^!ZX(2I>S5p`v$`6QFoIwW9uNUjpv< zhx$*0@I#Nl=lnn%&$dO=^l|!5x>HEw3RE&Mk-pCN*PiK4;H-y~6hYDP79b#WsIlZ= zZ6K{9I@um)4S9cUkc$>QMb8(O28*3AaxRhd=~|LX3ve(;=d4 zezLWWZsNTaWtf|S1rNJ|x0(y@b_A~1yRIax=c4*q5)6v8>r5if@6fr;YFVpEU!joJ z=+q5bO|x3wqLAQ~(rr=?8dDfitJyCmf(*Mkh+|A7wz!4Fkd2mtEyRu&X?7LqAqyz} zTRjFc3KlJf6hH&MbNJD1EfSAdrED@_S$aIEI9p*jT4Wd&iOXa;tWL7+j42*3Ud{>- zNUTsT`HR2U5UKvz-l?M{i8aNZGpP-oPbSwtJvs8hriL$eH+{5c%Wofk^iRM3)jxju z@>e%zKRLJi)3xMx29H-aC9DBzr7UYHySN&WS|!dQlb9Dgeh%Gq$!umVis$QbPf!A>|&kY z=;m@NOt7_XmBlDEdM%OW#Hywk@nz9UyUVK%kY-j{wrXT#ysEeYIFS-8o0kO^&=dd! zkPts$0n;5&fFj7=fRI2V#E}bWG~9BCVmBdTN#R?BiBJx{T`GJeG`d2y)+Uxx|I-(6 z01%+e{{LeEZ~zvd)5O0>E0ODRr0f(Z@|IP&wX-8V*Q=!)ta-J0Or4cG`-eU`d+haw z+V}cPZ}-L?ude-gf8XoFLl08z_fvZZ-kI3?-t=x9N8dkn^s_UkK0JNu{Zo_A$B#c5 zJMiMvz7J<+KiCm?Qd@c=V(u_`HhUct0o_DYODZYE6nyMNiIHrWnKJiWWniu&bN?PgJ#2_(!jBB$$>)mevdOXnXDeGuiH=_Z}pYN zY+fvv%AF;R{`f%4(7D4?ug>56{QO(5XBJ-1&j0+%TR**U?U#3N{q2*te|z)VU!R@+ z&D8PFwvF6xDZ5*TD{1&{dz5gpXBdI`bbC#r(_z=SxbIB0YbNfPiIQ?=8xNU}26PCD z@Tof+ajq?p^)n%EV^}htJj9_eUK>6tjbm(3&-z?M1fZv62f-$y06psYFA! zFBmhCh^Hx5n__y117~%hVrxqe=|Ojoj$Ph!;96>1>h_j(=U24e?yjAw3hZ`kiG>~3 z%J5XF6iFg9irGtXtK+X{&syfp%D^jviJGrKgvkY4d$^rKA3zkL8^e|y13IvP1Bepq zR<#T)K*S3caFPHEm^dA2Z<*?E27#{b+OoerE?_~cSqo+CmuqS)RxqYiZ!Z+9!t8Cz zlmV3%ONultO&0)F#o{o;18oNAB3PcV7PIJvMLPfr2u%TZ7EOxC?hph>i=HS9K`Zo{ zHDUjOn#jR;V5}}Q-VmDZs5)LBI#!n|9jyuA&2XwUh8Z2!6HJG&5@qPZ;h#!OxrQJX zb_$l0S}gdBQnP2;LeyQ{C(?&>Dzs3T7qI}nKNnLVhDDs*(|p1AKrlcb5kKE80D-{w zwj&)XhdZvk#%H#criVf_0zY6ux=omFi=Z6^W6%ikJ?K3cFtJ?5PXGi64aUDpiP9g= zwI@#2hbNk2NJdX}R+4W&-d%aBzXk=-ct-{80L1Z;=JEp#kv+-a{<=u&!`0;!e^3B8 zKuW}&A8)DssSsaQjw{g@o2q`YHTl)HS}yMVcuNgW<6j9q`+oa)W##k1vU~0RTdhLo zrqpx$)nWd)Toyn9$&bmvQXF;VW|ob(yeN~`DU&O_sk{d?V>r>U;;Zx6Qo z%c<^9R=2*rssEG9AN}{=efK|q`@8@9XRp8e@!kLPO6A`Um9imPZ}KWKjmk_diH#Im zl|n5k$dqR<kgkKWQLDeNXlb-rJ1- z+|H5Dj_>>N_~^^&Lj)9jFg5dXa*FBDvxzr*&(q8qtz2;)rH)_?56`JQ_ZafVy*A-Ljr-Ih;kaav_qdPbgw(x7QqzL@s7TAiDZXA)E}wXQr~v4 zV{mrOrn_4P z%7{iGcrE5({hx=e9}_j)l=3AC2xi+EuwHQJHEp(5#4gr^0Wu2N=*;(8v*&0}zyI4MZ%Yg+pno z3b`uB5MHFzd9Z-*n$E7_X}qe_FKhsUp^z{g%F5!i&^x0LYqS_QMg519k)s@i>r1#M zI}%{QD1E_^WC`RiaKPlBu|J-0zyW2P)4M>}a^UZbU|W5Aq>deAvnH%mz%MFIb!@F;=QR*N#txFzgo!IlOLn`Gpiip&lW@ zfUgS*r0YN6ksc872ue|aAl-8C4Y($oOTmTNwz8R4){|qf-NJ@jS0#_Ir##hC&h+b4 zYx#)=ff1k=U=RcxjAKvQm4G-VreS}5m_)bH*7!tUW9lOWrJIx7(j9;TlzNW+RQsQ9 zN&awswYlcU8>_xpU-|jEIM^Yy4{H;jtgWUsz=qoi&a0F2 zsw%>J6U(+YvoS_PM&K&Q397{1CDpsz+Fl+XeX@HWu|@k+wYpoKj$d}g-%Snw;@R*2 z+dqEy-9LW)-A^C?kDKein=1Qrr{_+or$Ml3(-^gdUWwh6!6aUUc19s7P>F>67mnLP zC0(RyF*DOh%r&8gYF}NEve+$ldgP8moztN<#VvsfyVtE$y3{(0MDJEQOATIDa8ovo z)upvV9{AJ_uhfi5b+xa&AyQLBBC*_Rl$s+&b=Bd1;*kRy4`wWo5XeePN_xBdkH(9W zg-VB6ZiN(pI|c<16miQ>gNO+37%U)afJ>O-WC@I$aF$=h0(MUYT3MV@!d0*shfxt& zVppg=DisAk&ARbM0tM0#z`IL$E3$5|_*K#~B3NTx)|)ipq$V)f!gXd-$n#`n{f$~H zS(5!`Z-=X#+WPgK3-6DuJvUf(y07;B^1j={T~9U+zq51g;~i_Br1orn@5uglMh|{` zcK*f0iDwhXpH7WGJ~i>~^oiHUwmjR^I$I{+W;6BZ%$oybLk7+#+*6hQ@v`E{G9Oql z8FEa8Y-ggb3sogx!S$BvD-F@>4gViq?;YJ}dR}?{y?^YPJ+`~MB69#q5KI6F1`s*t z90`Is=PDLiED{x1tekVsIcHYRp{t{;?v~^*9v_dr9$T`kk;ij(XZC1+A0hSl%tAjd`(f>hpRS$$VpZz-*woXN>+UX}I^NuIyD@kt>b)29op)Mys#S=E4w!4syKByP ztIzuzPFNHW1pD<0iiLwFIp{@-0gUlECpsdV0u(s!P@cBbTyQqriJKob3!bH~di)$X@Cx+E@kw)1#0nLOFrafzd0yz1RA>&<)+~ZabNZdXIWd zXC1mtb%mRiCDYQv0ZD#GS#dxtQfFtt7nAgZ8;3q8iw52M1Q5Om$i`*>QY|*B0;!u0^*7V9Zd$u3$^6UusQr*=8 z!Hf+ZVNYgpNkd^-SgF@6T&ONA))kj>&KIse%;@Gd3uzVGkLQ$h$-q&Cd21Q~EObP? zWRQaQ@DZv5bZt&aS$n-=!ql)WKsn%|V>07!AlrDIvwp^&s@onkP!wRvKqTpq z*ST(%=Uj*XQcw6|XWDm2$h2g{fUz?6X(kRR3g`>L|DrNYclz1kDF=`!5hRQ}=WLHR zjRn9#nhFLBP9)5yy8QS_^I73&4}zqaNkB)`@%w260Uj7g`!`qs#_(<)`2bH?)CEF~ z0BN0c;8U?bV&oA}5FDzT?EDq6d!i`V1s~FAV}S^GQ1Cl3Vg^Sr<-0wzmYf zH3ykHwtYM9eLraVIAUkdXV3r$_~~ST=PbSj3Zxg$`N|K|QILX^n=h98Uk%uwbz5Kd zxu^@kf(vfhHE;Dq|NR<25~{teR3vS2a|utS?(tU%tAb90p;9Gi5Psym%a*(v+q?8RAwX3b>Vz})c@e}8HA>kW-} zM;jjwHQ!s7#BJiq+JTo_S3cM%awRkhoqI}x%Sb?Xk>RmbdgtmAg|nSkYLQ{Y0x zajnUFCGNPEa9oPpX@H-KdG@$X7i`Y02Hm7axl*U@kd+%VJ`ELQZZsQHM|7oU%(5F^ z&9j8_QPlc*Pw-ur>qWcucEWcp8GO5X^7&Ni?(oW&sZGz;Z-2UV=d0<|o3-oS&(6G^ zUGskP`fvB_{IGS)-SP3$WBq%RfuqflebL~I)x6zhJQ--X8kV0hm7Vd_5jlL=Tz|}{ zJgAm$uPea`k*rG!f)nPH?3l5Na)7$vjJ5WLPmdGDlQ#FmW*h0p??)QHnCkws?W=#j zbLL+jUH|p7hrfFJ?w?-0{^h;vxKDhX9fhm7GC6T-aA-?CN!3!L~0<*odC126Hcr8b{>V^H$=^;30Tqj(|rY zwM?+55QYwTf*JLXaIiUG*xTd+>sSYx+%&^>M{U3$2@QC#(jx*3Xbo+QIO;<+}?+;J??&Zq=b~^cguXp{|LDQcFRcDn_*2N=Z#0WHGlwhx=FSj&?R}Z#q3o2udhDL&KWI0O=C1Skv`EA7crTG~J#ft=G zC`Ah-aQ-Ksihq}tVv-s0CoXlE9|@#zj&M5(baDnW#rYKU+%VWXR^maicnKT>?OwjZ zJq80O2sr2({b8mc-DXNZQg47yf+=u*!Gx{hi*ff6vnY~PWG}5BcD6j(x$PgW@Bi7h zu7~|8+pYfSwPnexL&3SJ#uu|guQsiIwQc?DJsaK~+VjQ9!_1LA-M!_`)@@Ht-*|p_ z_uWy;X@B`drDUkQkhtninyQ^z**=}@m`!!eq2F&*;RDUw_fbc~NssoJQ+32nsHF3D ztDo@TOFr%Ou<16DVo~dru$grsVA`Crm{zOmCTgo@^tBsw@@;zADVOGqO}U|7my%*8 zQg+ypTw8a~ZT`^gy&I@`6jQxQ>OOW`KJV0j)ou9manCQt9ACC;zi2c3*;xFC z6|G+_@BaCwnQu35eY|q@wb?b-){H;dF!5^r(4C>cr8d*Kr0y^`gjkzx~al2mg5SL<#d|p! zI39NHaa+$fN6$okrvtX#YUvSON_Ne!f70xF<5kSLD&Dp0KXe-Jd#Wy(#79h}d+g=w zDk~-{D!V1+&b)$pG&nigg-nc;6fgoB$;&|QfwW4s1ZVDSAOJIV-Qp#9^UlZJ&rc

rwx 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

ez~LT+kIR9ywLISHuzYM-Pyn8)9r2F?(6^l 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 J$lpoQ{{l^3RmA`R diff --git a/libs/spandsp/test-data/local/short_nb_voice.wav b/libs/spandsp/test-data/local/short_nb_voice.wav deleted file mode 100644 index 4dd098a2dfbeced8b1166a002b210190cd3554a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192044 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

    *jQ^_mtmo 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 diff --git a/libs/spandsp/tests/Makefile.am b/libs/spandsp/tests/Makefile.am deleted file mode 100644 index 4713d611d0..0000000000 --- a/libs/spandsp/tests/Makefile.am +++ /dev/null @@ -1,427 +0,0 @@ -## -## SpanDSP - a series of DSP components for telephony -## -## Makefile.am - Process this file with automake to produce Makefile.in -## -## 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. - -AM_CFLAGS = $(COMP_VENDOR_CFLAGS) -AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) - -LIBS += $(TESTLIBS) - -noinst_DATA = sound_c1_8k.wav sound_c3_8k.wav - -EXTRA_DIST = fax_tests.sh \ - regression_tests.sh \ - tsb85_extra_tests.sh \ - tsb85_tests.sh \ - v42bis_tests.sh \ - msvc/adsi_tests.vcproj \ - msvc/complex_tests.vcproj \ - msvc/complex_vector_float_tests.vcproj \ - msvc/complex_vector_int_tests.vcproj \ - msvc/dtmf_rx_tests.vcproj \ - msvc/dtmf_tx_tests.vcproj \ - msvc/queue_tests.vcproj \ - msvc/t38_core_tests.vcproj \ - msvc/t38_non_ecm_buffer_tests.vcproj \ - msvc/v22bis_tests.vcproj \ - msvc/v29_tests.vcproj \ - msvc/v8_tests.vcproj \ - msvc/v80_tests.vcproj \ - msvc/vector_float_tests.vcproj \ - msvc/vector_int_tests.vcproj - -MAINTAINERCLEANFILES = Makefile.in - -AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_builddir)/spandsp-sim -DDATADIR="\"$(pkgdatadir)\"" - -LIBDIR = -L$(top_builddir)/src - -if COND_V32BIS -V32BIS_PROGS = v32bis_tests -endif - -if COND_V34 -V34_PROGS = v34_tests -endif - -noinst_PROGRAMS = ademco_contactid_tests \ - adsi_tests \ - alloc_tests \ - async_tests \ - at_interpreter_tests \ - awgn_tests \ - bell_mf_rx_tests \ - bell_mf_tx_tests \ - bert_tests \ - bit_operations_tests \ - bitstream_tests \ - complex_tests \ - complex_vector_float_tests \ - complex_vector_int_tests \ - crc_tests \ - data_modems_tests \ - dc_restore_tests \ - dds_tests \ - dtmf_rx_tests \ - dtmf_tx_tests \ - dummy_modems_tests \ - echo_tests \ - fax_decode \ - fax_tests \ - fsk_tests \ - g1050_tests \ - g168_tests \ - g711_tests \ - g722_tests \ - g726_tests \ - gsm0610_tests \ - hdlc_tests \ - ima_adpcm_tests \ - image_translate_tests \ - line_model_tests \ - logging_tests \ - lpc10_tests \ - math_fixed_tests \ - make_g168_css \ - modem_connect_tones_tests \ - modem_echo_tests \ - noise_tests \ - oki_adpcm_tests \ - playout_tests \ - plc_tests \ - power_meter_tests \ - pseudo_terminal_tests \ - queue_tests \ - r2_mf_rx_tests \ - r2_mf_tx_tests \ - rfc2198_sim_tests \ - saturated_tests \ - schedule_tests \ - sig_tone_tests \ - super_tone_rx_tests \ - super_tone_tx_tests \ - swept_tone_tests \ - t31_pseudo_terminal_tests \ - t31_tests \ - t35_tests \ - t38_core_tests \ - t38_decode \ - t38_non_ecm_buffer_tests \ - t4_tests \ - t4_t6_tests \ - t42_tests \ - t43_tests \ - t81_t82_arith_coding_tests \ - t85_tests \ - time_scale_tests \ - timezone_tests \ - tone_detect_tests \ - tone_generate_tests \ - tsb85_tests \ - v17_tests \ - v18_tests \ - v22bis_tests \ - v27ter_tests \ - v29_tests \ - v42_tests \ - v42bis_tests \ - v8_tests \ - vector_float_tests \ - vector_int_tests \ - $(V32BIS_PROGS) \ - $(V34_PROGS) - -noinst_HEADERS = echo_monitor.h \ - fax_tester.h \ - fax_utils.h \ - line_model_monitor.h \ - media_monitor.h \ - modem_monitor.h \ - pcap_parse.h \ - pseudo_terminals.h \ - socket_harness.h \ - udptl.h - -ademco_contactid_tests_SOURCES = ademco_contactid_tests.c -ademco_contactid_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -adsi_tests_SOURCES = adsi_tests.c -adsi_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -alloc_tests_SOURCES = alloc_tests.c -alloc_tests_LDADD = $(LIBDIR) -lspandsp - -async_tests_SOURCES = async_tests.c -async_tests_LDADD = $(LIBDIR) -lspandsp - -at_interpreter_tests_SOURCES = at_interpreter_tests.c -at_interpreter_tests_LDADD = $(LIBDIR) -lspandsp - -awgn_tests_SOURCES = awgn_tests.c -awgn_tests_LDADD = $(LIBDIR) -lspandsp - -bell_mf_rx_tests_SOURCES = bell_mf_rx_tests.c -bell_mf_rx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -bell_mf_tx_tests_SOURCES = bell_mf_tx_tests.c -bell_mf_tx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -bert_tests_SOURCES = bert_tests.c -bert_tests_LDADD = $(LIBDIR) -lspandsp - -bit_operations_tests_SOURCES = bit_operations_tests.c -bit_operations_tests_LDADD = $(LIBDIR) -lspandsp - -bitstream_tests_SOURCES = bitstream_tests.c -bitstream_tests_LDADD = $(LIBDIR) -lspandsp - -complex_tests_SOURCES = complex_tests.c -complex_tests_LDADD = $(LIBDIR) -lspandsp - -complex_vector_float_tests_SOURCES = complex_vector_float_tests.c -complex_vector_float_tests_LDADD = $(LIBDIR) -lspandsp - -complex_vector_int_tests_SOURCES = complex_vector_int_tests.c -complex_vector_int_tests_LDADD = $(LIBDIR) -lspandsp - -crc_tests_SOURCES = crc_tests.c -crc_tests_LDADD = $(LIBDIR) -lspandsp - -data_modems_tests_SOURCES = data_modems_tests.c media_monitor.cpp -data_modems_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -dc_restore_tests_SOURCES = dc_restore_tests.c -dc_restore_tests_LDADD = $(LIBDIR) -lspandsp - -dds_tests_SOURCES = dds_tests.c -dds_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -dtmf_rx_tests_SOURCES = dtmf_rx_tests.c -dtmf_rx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -dtmf_tx_tests_SOURCES = dtmf_tx_tests.c -dtmf_tx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -dummy_modems_tests_SOURCES = dummy_modems_tests.c media_monitor.cpp socket_harness.c pseudo_terminals.c -dummy_modems_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp -lutil - -echo_tests_SOURCES = echo_tests.c echo_monitor.cpp -echo_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -fax_decode_SOURCES = fax_decode.c -fax_decode_LDADD = $(LIBDIR) -lspandsp - -fax_tests_SOURCES = fax_tests.c fax_utils.c media_monitor.cpp fax_tester.c -fax_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -fsk_tests_SOURCES = fsk_tests.c -fsk_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -g1050_tests_SOURCES = g1050_tests.c media_monitor.cpp -g1050_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -g168_tests_SOURCES = g168_tests.c -g168_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -g711_tests_SOURCES = g711_tests.c -g711_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -g722_tests_SOURCES = g722_tests.c -g722_tests_LDADD = $(LIBDIR) -lspandsp - -g726_tests_SOURCES = g726_tests.c -g726_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -gsm0610_tests_SOURCES = gsm0610_tests.c -gsm0610_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -hdlc_tests_SOURCES = hdlc_tests.c -hdlc_tests_LDADD = $(LIBDIR) -lspandsp - -ima_adpcm_tests_SOURCES = ima_adpcm_tests.c -ima_adpcm_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -image_translate_tests_SOURCES = image_translate_tests.c -image_translate_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -line_model_tests_SOURCES = line_model_tests.c -line_model_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -logging_tests_SOURCES = logging_tests.c -logging_tests_LDADD = $(LIBDIR) -lspandsp - -lpc10_tests_SOURCES = lpc10_tests.c -lpc10_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -math_fixed_tests_SOURCES = math_fixed_tests.c -math_fixed_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -make_g168_css_SOURCES = make_g168_css.c -make_g168_css_LDADD = $(LIBDIR) -lspandsp - -modem_echo_tests_SOURCES = modem_echo_tests.c echo_monitor.cpp -modem_echo_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -modem_connect_tones_tests_SOURCES = modem_connect_tones_tests.c -modem_connect_tones_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -noise_tests_SOURCES = noise_tests.c -noise_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -oki_adpcm_tests_SOURCES = oki_adpcm_tests.c -oki_adpcm_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -playout_tests_SOURCES = playout_tests.c media_monitor.cpp -playout_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -plc_tests_SOURCES = plc_tests.c -plc_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -power_meter_tests_SOURCES = power_meter_tests.c -power_meter_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -pseudo_terminal_tests_SOURCES = pseudo_terminal_tests.c fax_utils.c pseudo_terminals.c -pseudo_terminal_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim -lspandsp -lutil - -queue_tests_SOURCES = queue_tests.c -queue_tests_LDADD = $(LIBDIR) -lspandsp - -r2_mf_rx_tests_SOURCES = r2_mf_rx_tests.c -r2_mf_rx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -r2_mf_tx_tests_SOURCES = r2_mf_tx_tests.c -r2_mf_tx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -rfc2198_sim_tests_SOURCES = rfc2198_sim_tests.c media_monitor.cpp -rfc2198_sim_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -saturated_tests_SOURCES = saturated_tests.c -saturated_tests_LDADD = $(LIBDIR) -lspandsp - -schedule_tests_SOURCES = schedule_tests.c -schedule_tests_LDADD = $(LIBDIR) -lspandsp - -sig_tone_tests_SOURCES = sig_tone_tests.c -sig_tone_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -super_tone_rx_tests_SOURCES = super_tone_rx_tests.c -super_tone_rx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -super_tone_tx_tests_SOURCES = super_tone_tx_tests.c -super_tone_tx_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -swept_tone_tests_SOURCES = swept_tone_tests.c -swept_tone_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -t31_pseudo_terminal_tests_SOURCES = t31_pseudo_terminal_tests.c fax_utils.c pseudo_terminals.c -t31_pseudo_terminal_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim -lspandsp -lutil - -t31_tests_SOURCES = t31_tests.c fax_utils.c media_monitor.cpp -t31_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -t35_tests_SOURCES = t35_tests.c -t35_tests_LDADD = $(LIBDIR) -lspandsp - -t38_core_tests_SOURCES = t38_core_tests.c -t38_core_tests_LDADD = $(LIBDIR) -lspandsp - -t38_decode_SOURCES = t38_decode.c fax_utils.c pcap_parse.c udptl.c -t38_decode_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -t38_non_ecm_buffer_tests_SOURCES = t38_non_ecm_buffer_tests.c -t38_non_ecm_buffer_tests_LDADD = $(LIBDIR) -lspandsp - -t4_tests_SOURCES = t4_tests.c -t4_tests_LDADD = $(LIBDIR) -lspandsp - -t4_t6_tests_SOURCES = t4_t6_tests.c -t4_t6_tests_LDADD = $(LIBDIR) -lspandsp - -t42_tests_SOURCES = t42_tests.c -t42_tests_LDADD = $(LIBDIR) -lspandsp - -t43_tests_SOURCES = t43_tests.c -t43_tests_LDADD = $(LIBDIR) -lspandsp - -t81_t82_arith_coding_tests_SOURCES = t81_t82_arith_coding_tests.c -t81_t82_arith_coding_tests_LDADD = $(LIBDIR) -lspandsp - -t85_tests_SOURCES = t85_tests.c -t85_tests_LDADD = $(LIBDIR) -lspandsp - -time_scale_tests_SOURCES = time_scale_tests.c -time_scale_tests_LDADD = $(LIBDIR) -lspandsp - -timezone_tests_SOURCES = timezone_tests.c -timezone_tests_LDADD = $(LIBDIR) -lspandsp - -tone_detect_tests_SOURCES = tone_detect_tests.c -tone_detect_tests_LDADD = $(LIBDIR) -lspandsp - -tone_generate_tests_SOURCES = tone_generate_tests.c -tone_generate_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -tsb85_tests_SOURCES = tsb85_tests.c fax_utils.c fax_tester.c -tsb85_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -v17_tests_SOURCES = v17_tests.c line_model_monitor.cpp modem_monitor.cpp -v17_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -v18_tests_SOURCES = v18_tests.c -v18_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -v22bis_tests_SOURCES = v22bis_tests.c line_model_monitor.cpp modem_monitor.cpp -v22bis_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -v27ter_tests_SOURCES = v27ter_tests.c line_model_monitor.cpp modem_monitor.cpp -v27ter_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -v29_tests_SOURCES = v29_tests.c line_model_monitor.cpp modem_monitor.cpp -v29_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -if COND_V32BIS -v32bis_tests_SOURCES = v32bis_tests.c line_model_monitor.cpp modem_monitor.cpp -v32bis_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp -endif - -if COND_V34 -v34_tests_SOURCES = v34_tests.c line_model_monitor.cpp modem_monitor.cpp -v34_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp -endif - -v42_tests_SOURCES = v42_tests.c -v42_tests_LDADD = $(LIBDIR) -lspandsp - -v42bis_tests_SOURCES = v42bis_tests.c -v42bis_tests_LDADD = $(LIBDIR) -lspandsp - -v8_tests_SOURCES = v8_tests.c -v8_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp - -vector_float_tests_SOURCES = vector_float_tests.c -vector_float_tests_LDADD = $(LIBDIR) -lspandsp - -vector_int_tests_SOURCES = vector_int_tests.c -vector_int_tests_LDADD = $(LIBDIR) -lspandsp - -# We need to create the CSS files for echo cancellation tests. - -sound_c1_8k.wav sound_c3_8k.wav: make_g168_css$(EXEEXT) - ./make_g168_css$(EXEEXT) - sox sound_c1.wav -r8000 sound_c1_8k.wav - sox sound_c3.wav -r8000 sound_c3_8k.wav - rm sound_c1.wav sound_c3.wav diff --git a/libs/spandsp/tests/ademco_contactid_tests.c b/libs/spandsp/tests/ademco_contactid_tests.c deleted file mode 100644 index 4071999d03..0000000000 --- a/libs/spandsp/tests/ademco_contactid_tests.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * ademco_contactid.c - Ademco ContactID alarm protocol - * - * 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 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. - */ - -/*! \page ademco_contactid_tests_page Ademco ContactID tests -\section ademco_contactid_tests_page_sec_1 What does it do? - -\section ademco_contactid_tests_page_sec_2 How does it work? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define SAMPLES_PER_CHUNK 160 - -#define OUTPUT_FILE_NAME "ademco_contactid.wav" - -#define MITEL_DIR "../test-data/mitel/" -#define BELLCORE_DIR "../test-data/bellcore/" - -const char *bellcore_files[] = -{ - MITEL_DIR "mitel-cm7291-talkoff.wav", - BELLCORE_DIR "tr-tsy-00763-1.wav", - BELLCORE_DIR "tr-tsy-00763-2.wav", - BELLCORE_DIR "tr-tsy-00763-3.wav", - BELLCORE_DIR "tr-tsy-00763-4.wav", - BELLCORE_DIR "tr-tsy-00763-5.wav", - BELLCORE_DIR "tr-tsy-00763-6.wav", - "" -}; - -static const ademco_contactid_report_t reports[] = -{ - {0x1234, 0x18, 0x1, 0x131, 0x1, 0x15}, - {0x1234, 0x18, 0x3, 0x131, 0x1, 0x15}, - {0x1234, 0x18, 0x1, 0x401, 0x2, 0x3}, - {0x1234, 0x18, 0x3, 0x401, 0x3, 0x5}, - {0x1234, 0x56, 0x7, 0x890, 0xBC, 0xDEF}, - {0x1234, 0x56, 0x7, 0x89A, 0xBC, 0xDEF} /* This one is bad, as it contains a hex 'A' */ -}; -static int reports_entry = 0; - -static int16_t amp[1000000]; - -bool tx_callback_reported = false; -bool rx_callback_reported = false; - -bool sending_complete = false; - -SNDFILE *outhandle; - -static void talkoff_tx_callback(void *user_data, int tone, int level, int duration) -{ - printf("Ademco sender report %d\n", tone); - tx_callback_reported = true; -} - -static int mitel_cm7291_side_2_and_bellcore_tests(void) -{ - int j; - SNDFILE *inhandle; - int frames; - ademco_contactid_sender_state_t *sender; - logging_state_t *logging; - - if ((sender = ademco_contactid_sender_init(NULL, talkoff_tx_callback, NULL)) == NULL) - return -1; - logging = ademco_contactid_sender_get_logging_state(sender); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Ademco-tx"); - - tx_callback_reported = false; - - /* The remainder of the Mitel tape is the talk-off test */ - /* Here we use the Bellcore test tapes (much tougher), in six - files - 1 from each side of the original 3 cassette tapes */ - /* Bellcore say you should get no more than 470 false detections with - a good receiver. Dialogic claim 20. Of course, we can do better than - that, eh? */ - printf("Talk-off test\n"); - for (j = 0; bellcore_files[j][0]; j++) - { - if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) - { - printf(" Cannot open speech file '%s'\n", bellcore_files[j]); - return -1; - } - while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE))) - { - ademco_contactid_sender_rx(sender, amp, frames); - } - if (sf_close_telephony(inhandle)) - { - printf(" Cannot close speech file '%s'\n", bellcore_files[j]); - return -1; - } - printf(" File %d gave %d false hits.\n", j + 1, 0); - } - if (tx_callback_reported) - { - printf(" Failed\n"); - return -1; - } - printf(" Passed\n"); - ademco_contactid_sender_free(sender); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void rx_callback(void *user_data, const ademco_contactid_report_t *report) -{ - printf("Ademco Contact ID message:\n"); - printf(" Account %X\n", report->acct); - printf(" Message type %X\n", report->mt); - printf(" Qualifier %X\n", report->q); - printf(" Event %X\n", report->xyz); - printf(" Group/partition %X\n", report->gg); - printf(" User/Zone information %X\n", report->ccc); - if (memcmp(&reports[reports_entry], report, sizeof(*report))) - { - printf("Report mismatch\n"); - exit(2); - } - rx_callback_reported = true; -} -/*- End of function --------------------------------------------------------*/ - -static void tx_callback(void *user_data, int tone, int level, int duration) -{ - ademco_contactid_sender_state_t *sender; - - sender = (ademco_contactid_sender_state_t *) user_data; - printf("Ademco sender report %d\n", tone); - switch (tone) - { - case -1: - /* We are connected and ready to send */ - ademco_contactid_sender_put(sender, &reports[reports_entry]); - break; - case 1: - /* We have succeeded in sending, and are ready to send another message. */ - if (++reports_entry < 5) - ademco_contactid_sender_put(sender, &reports[reports_entry]); - else - sending_complete = true; - break; - case 0: - /* Sending failed after retries */ - sending_complete = true; - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int end_to_end_tests(void) -{ - ademco_contactid_receiver_state_t *receiver; - ademco_contactid_sender_state_t *sender; - logging_state_t *logging; - codec_munge_state_t *munge; - awgn_state_t noise_source; - int16_t amp[SAMPLES_PER_CHUNK]; - int16_t sndfile_buf[2*SAMPLES_PER_CHUNK]; - int samples; - int i; - int j; - - printf("End to end tests\n"); - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - if ((receiver = ademco_contactid_receiver_init(NULL, rx_callback, NULL)) == NULL) - return -1; - ademco_contactid_receiver_set_realtime_callback(receiver, rx_callback, receiver); - - logging = ademco_contactid_receiver_get_logging_state(receiver); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Ademco-rx"); - - if ((sender = ademco_contactid_sender_init(NULL, tx_callback, NULL)) == NULL) - return -1; - ademco_contactid_sender_set_realtime_callback(sender, tx_callback, sender); - logging = ademco_contactid_sender_get_logging_state(sender); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Ademco-tx"); - - awgn_init_dbm0(&noise_source, 1234567, -50); - munge = codec_munge_init(MUNGE_CODEC_ALAW, 0); - - sending_complete = false; - rx_callback_reported = false; - - for (i = 0; i < 1000; i++) - { - samples = ademco_contactid_sender_tx(sender, amp, SAMPLES_PER_CHUNK); - for (j = samples; j < SAMPLES_PER_CHUNK; j++) - amp[j] = 0; - for (j = 0; j < SAMPLES_PER_CHUNK; j++) - sndfile_buf[2*j] = amp[j]; - /* There is no point in impairing this signal. It is just DTMF tones, which - will work as wel as the DTMF detector beign used. */ - ademco_contactid_receiver_rx(receiver, amp, SAMPLES_PER_CHUNK); - - samples = ademco_contactid_receiver_tx(receiver, amp, SAMPLES_PER_CHUNK); - for (j = samples; j < SAMPLES_PER_CHUNK; j++) - amp[j] = 0; - - /* We add AWGN and codec impairments to the signal, to stress the tone detector. */ - codec_munge(munge, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < SAMPLES_PER_CHUNK; j++) - { - sndfile_buf[2*j + 1] = amp[j]; - /* Add noise to the tones */ - amp[j] += awgn(&noise_source); - } - codec_munge(munge, amp, SAMPLES_PER_CHUNK); - ademco_contactid_sender_rx(sender, amp, SAMPLES_PER_CHUNK); - - sf_writef_short(outhandle, sndfile_buf, SAMPLES_PER_CHUNK); - } - codec_munge_free(munge); - if (!rx_callback_reported) - { - fprintf(stderr, " Report not received\n"); - return -1; - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - return -1; - } - printf(" Passed\n"); - ademco_contactid_sender_free(sender); - ademco_contactid_receiver_free(receiver); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int encode_decode_tests(void) -{ - char buf[100]; - ademco_contactid_receiver_state_t *receiver; - ademco_contactid_sender_state_t *sender; - logging_state_t *logging; - ademco_contactid_report_t result; - int i; - - printf("Encode and decode tests\n"); - - if ((receiver = ademco_contactid_receiver_init(NULL, NULL, NULL)) == NULL) - return 2; - logging = ademco_contactid_receiver_get_logging_state(receiver); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Ademco-rx"); - - if ((sender = ademco_contactid_sender_init(NULL, NULL, NULL)) == NULL) - return 2; - logging = ademco_contactid_sender_get_logging_state(sender); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Ademco-tx"); - - for (i = 0; i < 5; i++) - { - if (encode_msg(buf, &reports[i]) < 0) - { - printf("Bad encode message\n"); - return -1; - } - printf("'%s'\n", buf); - if (decode_msg(&result, buf)) - { - printf("Bad decode message\n"); - return -1; - } - ademco_contactid_receiver_log_msg(receiver, &result); - printf("\n"); - if (memcmp(&reports[i], &result, sizeof(result))) - { - printf("Received message does not match the one sent\n"); - return -1; - } - } - - if (encode_msg(buf, &reports[5]) >= 0) - { - printf("Incorrectly good message\n"); - return -1; - } - printf("'%s'\n", buf); - printf("\n"); - printf(" Passed\n"); - ademco_contactid_sender_free(sender); - ademco_contactid_receiver_free(receiver); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void decode_file(const char *file) -{ - //SPAN_DECLARE(int) decode_msg(ademco_contactid_report_t *report, const char buf[]) -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int opt; - const char *decode_test_file; - - decode_test_file = NULL; - while ((opt = getopt(argc, argv, "d:")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - - if (decode_test_file) - { - decode_file(decode_test_file); - return 0; - } - - if (encode_decode_tests()) - { - printf("Tests failed\n"); - return 2; - } - - if (mitel_cm7291_side_2_and_bellcore_tests()) - { - printf("Tests failed\n"); - return 2; - } - - if (end_to_end_tests()) - { - printf("Tests failed\n"); - return 2; - } - - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/adsi_tests.c b/libs/spandsp/tests/adsi_tests.c deleted file mode 100644 index 500bbf0858..0000000000 --- a/libs/spandsp/tests/adsi_tests.c +++ /dev/null @@ -1,865 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * adsi_tests.c - tests for analogue display service handling. - * - * 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 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. - */ - -/*! \page adsi_tests_page ADSI tests -\section adsi_tests_page_sec_1 What does it do? -These tests exercise the ADSI module, for all supported standards. A transmit -and a receive instance of the ADSI module are connected together. A quantity -of messages is passed between these instances, and checked for accuracy at -the receiver. Since the FSK modems used for this are exercised fully by other -tests, these tests do not include line modelling. - -\section adsi_tests_page_sec_2 How does it work? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "adsi.wav" - -#define BLOCK_LEN 160 - -#define MITEL_DIR "../test-data/mitel/" -#define BELLCORE_DIR "../test-data/bellcore/" - -const char *bellcore_files[] = -{ - MITEL_DIR "mitel-cm7291-talkoff.wav", - BELLCORE_DIR "tr-tsy-00763-1.wav", - BELLCORE_DIR "tr-tsy-00763-2.wav", - BELLCORE_DIR "tr-tsy-00763-3.wav", - BELLCORE_DIR "tr-tsy-00763-4.wav", - BELLCORE_DIR "tr-tsy-00763-5.wav", - BELLCORE_DIR "tr-tsy-00763-6.wav", - "" -}; - -char *decode_test_file = NULL; - -int errors = 0; -bool basic_testing = false; - -adsi_rx_state_t *rx_adsi; -adsi_tx_state_t *tx_adsi; - -int current_standard = 0; -int good_message_received; -bool log_audio = false; -SNDFILE *outhandle = NULL; -bool short_preamble = false; - -static int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - const char *t; - int len; - static int cycle = 0; - - len = 0; - switch (current_standard) - { - case ADSI_STANDARD_CLASS: - if (cycle > 3) - cycle = 0; - switch (cycle) - { - case 0: - len = adsi_add_field(s, msg, -1, CLASS_MDMF_CALLERID, NULL, 0); - /* Date and time as MMDDHHMM */ - len = adsi_add_field(s, msg, len, MCLASS_DATETIME, (uint8_t *) "10011750", 8); - len = adsi_add_field(s, msg, len, MCLASS_CALLER_NUMBER, (uint8_t *) "12345678", 8); - len = adsi_add_field(s, msg, len, MCLASS_DIALED_NUMBER, (uint8_t *) "87654321", 8); - len = adsi_add_field(s, msg, len, MCLASS_CALLER_NAME, (uint8_t *) "Chan Dai Man", 15); - break; - case 1: - len = adsi_add_field(s, msg, -1, CLASS_SDMF_MSG_WAITING, NULL, 0); - /* Active */ - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "\x42", 1); - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "\x42", 1); - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "\x42", 1); - break; - case 2: - len = adsi_add_field(s, msg, -1, CLASS_SDMF_MSG_WAITING, NULL, 0); - /* Inactive */ - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "\x6F", 1); - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "\x6F", 1); - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "\x6F", 1); - break; - case 3: - len = adsi_add_field(s, msg, -1, CLASS_SDMF_CALLERID, NULL, 0); - /* Date and time as MMDDHHMM */ - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "10011750", 8); - len = adsi_add_field(s, msg, len, 0, (uint8_t *) "6095551212", 10); - break; - } - break; - case ADSI_STANDARD_CLIP: - if (cycle > 4) - cycle = 0; - switch (cycle) - { - case 0: - len = adsi_add_field(s, msg, -1, CLIP_MDMF_CALLERID, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_CALLTYPE, (uint8_t *) "\x81", 1); - /* Date and time as MMDDHHMM */ - len = adsi_add_field(s, msg, len, CLIP_DATETIME, (uint8_t *) "10011750", 8); - len = adsi_add_field(s, msg, len, CLIP_DIALED_NUMBER, (uint8_t *) "12345678", 8); - len = adsi_add_field(s, msg, len, CLIP_CALLER_NUMBER, (uint8_t *) "87654321", 8); - len = adsi_add_field(s, msg, len, CLIP_CALLER_NAME, (uint8_t *) "Chan Dai Man", 15); - break; - case 1: - len = adsi_add_field(s, msg, -1, CLIP_MDMF_MSG_WAITING, NULL, 0); - /* Inactive */ - len = adsi_add_field(s, msg, len, CLIP_VISUAL_INDICATOR, (uint8_t *) "\x00", 1); - break; - case 2: - len = adsi_add_field(s, msg, -1, CLIP_MDMF_MSG_WAITING, NULL, 0); - /* Active */ - len = adsi_add_field(s, msg, len, CLIP_VISUAL_INDICATOR, (uint8_t *) "\xFF", 1); - len = adsi_add_field(s, msg, len, CLIP_NUM_MSG, (uint8_t *) "\x05", 1); - break; - case 3: - len = adsi_add_field(s, msg, -1, CLIP_MDMF_SMS, NULL, 0); - /* Active */ - len = adsi_add_field(s, msg, len, CLIP_DISPLAY_INFO, (uint8_t *) "\x00" "ABC", 4); - break; - case 4: - len = adsi_add_field(s, msg, -1, CLIP_MDMF_CALLERID, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_NUM_MSG, (uint8_t *) "\x03", 1); - break; - } - break; - case ADSI_STANDARD_ACLIP: - if (cycle > 0) - cycle = 0; - switch (cycle) - { - case 0: - len = adsi_add_field(s, msg, -1, ACLIP_MDMF_CALLERID, NULL, 0); - /* Date and time as MMDDHHMM */ - len = adsi_add_field(s, msg, len, ACLIP_DATETIME, (uint8_t *) "10011750", 8); - len = adsi_add_field(s, msg, len, ACLIP_DIALED_NUMBER, (uint8_t *) "12345678", 8); - len = adsi_add_field(s, msg, len, ACLIP_CALLER_NUMBER, (uint8_t *) "87654321", 8); - len = adsi_add_field(s, msg, len, ACLIP_CALLER_NAME, (uint8_t *) "Chan Dai Man", 15); - break; - } - break; - case ADSI_STANDARD_JCLIP: - len = adsi_add_field(s, msg, -1, JCLIP_MDMF_CALLERID, NULL, 0); - len = adsi_add_field(s, msg, len, JCLIP_CALLER_NUMBER, (uint8_t *) "12345678", 8); - len = adsi_add_field(s, msg, len, JCLIP_CALLER_NUM_DES, (uint8_t *) "215", 3); - len = adsi_add_field(s, msg, len, JCLIP_DIALED_NUMBER, (uint8_t *) "87654321", 8); - len = adsi_add_field(s, msg, len, JCLIP_DIALED_NUM_DES, (uint8_t *) "215", 3); - break; - case ADSI_STANDARD_CLIP_DTMF: - if (cycle > 4) - cycle = 0; - switch (cycle) - { - case 0: - len = adsi_add_field(s, msg, -1, CLIP_DTMF_C_TERMINATED, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_DTMF_C_CALLER_NUMBER, (uint8_t *) "12345678", 8); - len = adsi_add_field(s, msg, len, CLIP_DTMF_C_ABSENCE, (uint8_t *) "10", 2); - len = adsi_add_field(s, msg, len, CLIP_DTMF_C_REDIRECT_NUMBER, (uint8_t *) "87654321", 8); - break; - case 1: - len = adsi_add_field(s, msg, -1, CLIP_DTMF_HASH_TERMINATED, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_DTMF_HASH_CALLER_NUMBER, (uint8_t *) "12345678", 8); - break; - case 2: - len = adsi_add_field(s, msg, -1, CLIP_DTMF_HASH_TERMINATED, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_DTMF_HASH_ABSENCE, (uint8_t *) "1", 1); - break; - case 3: - /* Test the DC format, used in Taiwan and Kuwait */ - len = adsi_add_field(s, msg, -1, CLIP_DTMF_HASH_TERMINATED, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_DTMF_HASH_ABSENCE, (uint8_t *) "12345678", 8); - break; - case 4: - /* Test the # format, with no header */ - len = adsi_add_field(s, msg, -1, CLIP_DTMF_HASH_TERMINATED, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_DTMF_HASH_UNSPECIFIED, (uint8_t *) "12345678", 8); - break; - } - break; - case ADSI_STANDARD_TDD: - t = "The quick Brown Fox Jumps Over The Lazy dog 0123456789!@#$%^&*()"; - len = adsi_add_field(s, msg, -1, 0, (uint8_t *) t, strlen(t)); - break; - } - cycle++; - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void put_adsi_msg(void *user_data, const uint8_t *msg, int len) -{ - int i; - int l; - uint8_t field_type; - const uint8_t *field_body; - int field_len; - int message_type; - uint8_t body[256]; - - printf("Good message received (%d bytes)\n", len); - good_message_received = true; - for (i = 0; i < len; i++) - { - printf("%02x ", msg[i]); - if ((i & 0xF) == 0xF) - printf("\n"); - } - printf("\n"); - l = -1; - message_type = -1; - printf("Message breakdown\n"); - do - { - l = adsi_next_field(rx_adsi, msg, len, l, &field_type, &field_body, &field_len); - if (l > 0) - { - if (field_body) - { - memcpy(body, field_body, field_len); - body[field_len] = '\0'; - printf("Field type 0x%x, len %d, '%s' - ", field_type, field_len, body); - switch (current_standard) - { - case ADSI_STANDARD_CLASS: - switch (message_type) - { - case CLASS_SDMF_CALLERID: - break; - case CLASS_MDMF_CALLERID: - switch (field_type) - { - case MCLASS_DATETIME: - printf("Date and time (MMDDHHMM)"); - break; - case MCLASS_CALLER_NUMBER: - printf("Caller's number"); - break; - case MCLASS_DIALED_NUMBER: - printf("Dialed number"); - break; - case MCLASS_ABSENCE1: - printf("Caller's number absent: 'O' or 'P'"); - break; - case MCLASS_REDIRECT: - printf("Call forward: universal ('0'), on busy ('1'), or on unanswered ('2')"); - break; - case MCLASS_QUALIFIER: - printf("Long distance: 'L'"); - break; - case MCLASS_CALLER_NAME: - printf("Caller's name"); - break; - case MCLASS_ABSENCE2: - printf("Caller's name absent: 'O' or 'P'"); - break; - } - break; - case CLASS_SDMF_MSG_WAITING: - break; - case CLASS_MDMF_MSG_WAITING: - switch (field_type) - { - case MCLASS_VISUAL_INDICATOR: - printf("Message waiting/not waiting"); - break; - } - break; - } - break; - case ADSI_STANDARD_CLIP: - switch (message_type) - { - case CLIP_MDMF_CALLERID: - case CLIP_MDMF_MSG_WAITING: - case CLIP_MDMF_CHARGE_INFO: - case CLIP_MDMF_SMS: - switch (field_type) - { - case CLIP_DATETIME: - printf("Date and time (MMDDHHMM)"); - break; - case CLIP_CALLER_NUMBER: - printf("Caller's number"); - break; - case CLIP_DIALED_NUMBER: - printf("Dialed number"); - break; - case CLIP_ABSENCE1: - printf("Caller's number absent"); - break; - case CLIP_CALLER_NAME: - printf("Caller's name"); - break; - case CLIP_ABSENCE2: - printf("Caller's name absent"); - break; - case CLIP_VISUAL_INDICATOR: - printf("Visual indicator"); - break; - case CLIP_MESSAGE_ID: - printf("Message ID"); - break; - case CLIP_CALLTYPE: - printf("Voice call, ring-back-when-free call, or msg waiting call"); - break; - case CLIP_NUM_MSG: - printf("Number of messages"); - break; -#if 0 - case CLIP_REDIR_NUMBER: - printf("Redirecting number"); - break; -#endif - case CLIP_CHARGE: - printf("Charge"); - break; - case CLIP_DURATION: - printf("Duration of the call"); - break; - case CLIP_ADD_CHARGE: - printf("Additional charge"); - break; - case CLIP_DISPLAY_INFO: - printf("Display information"); - break; - case CLIP_SERVICE_INFO: - printf("Service information"); - break; - } - break; - } - break; - case ADSI_STANDARD_ACLIP: - switch (message_type) - { - case ACLIP_SDMF_CALLERID: - break; - case ACLIP_MDMF_CALLERID: - switch (field_type) - { - case ACLIP_DATETIME: - printf("Date and time (MMDDHHMM)"); - break; - case ACLIP_CALLER_NUMBER: - printf("Caller's number"); - break; - case ACLIP_DIALED_NUMBER: - printf("Dialed number"); - break; - case ACLIP_NUMBER_ABSENCE: - printf("Caller's number absent: 'O' or 'P'"); - break; - case ACLIP_REDIRECT: - printf("Call forward: universal, on busy, or on unanswered"); - break; - case ACLIP_QUALIFIER: - printf("Long distance call: 'L'"); - break; - case ACLIP_CALLER_NAME: - printf("Caller's name"); - break; - case ACLIP_NAME_ABSENCE: - printf("Caller's name absent: 'O' or 'P'"); - break; - } - break; - } - break; - case ADSI_STANDARD_JCLIP: - switch (message_type) - { - case JCLIP_MDMF_CALLERID: - switch (field_type) - { - case JCLIP_CALLER_NUMBER: - printf("Caller's number"); - break; - case JCLIP_CALLER_NUM_DES: - printf("Caller's number data extension signal"); - break; - case JCLIP_DIALED_NUMBER: - printf("Dialed number"); - break; - case JCLIP_DIALED_NUM_DES: - printf("Dialed number data extension signal"); - break; - case JCLIP_ABSENCE: - printf("Caller's number absent: 'C', 'O', 'P' or 'S'"); - break; - } - break; - } - break; - case ADSI_STANDARD_CLIP_DTMF: - switch (message_type) - { - case CLIP_DTMF_HASH_TERMINATED: - switch (field_type) - { - case CLIP_DTMF_HASH_CALLER_NUMBER: - printf("Caller's number"); - break; - case CLIP_DTMF_HASH_ABSENCE: - printf("Caller's number absent: private (1), overseas (2) or not available (3)"); - break; - case CLIP_DTMF_HASH_UNSPECIFIED: - printf("Unspecified"); - break; - } - break; - case CLIP_DTMF_C_TERMINATED: - switch (field_type) - { - case CLIP_DTMF_C_CALLER_NUMBER: - printf("Caller's number"); - break; - case CLIP_DTMF_C_REDIRECT_NUMBER: - printf("Redirect number"); - break; - case CLIP_DTMF_C_ABSENCE: - printf("Caller's number absent"); - break; - } - break; - } - break; - case ADSI_STANDARD_TDD: - if (basic_testing) - { - if (len != 59 - || - memcmp(msg, "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 0123456789#$*()", 59)) - { - printf("\n"); - printf("String error\n"); - exit(2); - } - } - break; - } - } - else - { - printf("Message type 0x%x - ", field_type); - message_type = field_type; - switch (current_standard) - { - case ADSI_STANDARD_CLASS: - switch (message_type) - { - case CLASS_SDMF_CALLERID: - printf("Single data message caller ID"); - break; - case CLASS_MDMF_CALLERID: - printf("Multiple data message caller ID"); - break; - case CLASS_SDMF_MSG_WAITING: - printf("Single data message message waiting"); - break; - case CLASS_MDMF_MSG_WAITING: - printf("Multiple data message message waiting"); - break; - default: - printf("Unknown"); - break; - } - break; - case ADSI_STANDARD_CLIP: - switch (message_type) - { - case CLIP_MDMF_CALLERID: - printf("Multiple data message caller ID"); - break; - case CLIP_MDMF_MSG_WAITING: - printf("Multiple data message message waiting"); - break; - case CLIP_MDMF_CHARGE_INFO: - printf("Multiple data message charge info"); - break; - case CLIP_MDMF_SMS: - printf("Multiple data message SMS"); - break; - default: - printf("Unknown"); - break; - } - break; - case ADSI_STANDARD_ACLIP: - switch (message_type) - { - case ACLIP_SDMF_CALLERID: - printf("Single data message caller ID frame"); - break; - case ACLIP_MDMF_CALLERID: - printf("Multiple data message caller ID frame"); - break; - default: - printf("Unknown"); - break; - } - break; - case ADSI_STANDARD_JCLIP: - switch (message_type) - { - case JCLIP_MDMF_CALLERID: - printf("Multiple data message caller ID frame"); - break; - default: - printf("Unknown"); - break; - } - break; - case ADSI_STANDARD_CLIP_DTMF: - switch (message_type) - { - case CLIP_DTMF_HASH_TERMINATED: - printf("# terminated"); - break; - case CLIP_DTMF_C_TERMINATED: - printf("C terminated"); - break; - default: - printf("Unknown"); - break; - } - break; - case ADSI_STANDARD_TDD: - printf("Unknown"); - break; - } - } - printf("\n"); - } - } - while (l > 0); - if (l < -1) - { - /* This message appears corrupt */ - printf("Bad message contents\n"); - exit(2); - } - printf("\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void tdd_character_set_tests(void) -{ -#if 0 - char *s; - int ch; - int xx; - int yy; - - /* This part tests internal static routines in the ADSI module. It can - only be run with a modified version of the ADSI module, which makes - the routines visible. */ - /* Check the character encode/decode cycle */ - tx_adsi = adsi_tx_init(NULL, ADSI_STANDARD_TDD); - rx_adsi = adsi_rx_init(NULL, ADSI_STANDARD_TDD, put_adsi_msg, NULL); - s = "The quick Brown Fox Jumps Over The Lazy dog 0123456789!@#$%^&*()"; - while ((ch = *s++)) - { - xx = adsi_encode_baudot(tx_adsi, ch); - if ((xx & 0x3E0)) - { - yy = adsi_decode_baudot(rx_adsi, (xx >> 5) & 0x1F); - if (yy) - printf("%c", yy); - } - yy = adsi_decode_baudot(rx_adsi, xx & 0x1F); - if (yy) - printf("%c", yy); - } - adsi_tx_free(tx_adsi); - adsi_rx_free(rx_adsi); - printf("\n"); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void basic_tests(int standard) -{ - int16_t amp[BLOCK_LEN]; - uint8_t adsi_msg[256 + 42]; - int outframes; - int len; - int adsi_msg_len; - int push; - int i; - - basic_testing = true; - printf("Testing %s\n", adsi_standard_to_str(standard)); - tx_adsi = adsi_tx_init(NULL, standard); - if (short_preamble) - adsi_tx_set_preamble(tx_adsi, 50, 20, 5, -1); - rx_adsi = adsi_rx_init(NULL, standard, put_adsi_msg, NULL); - - /* Fake an OK condition for the first message test */ - good_message_received = true; - push = 0; - for (i = 0; i < 100000; i++) - { - if (push == 0) - { - if ((len = adsi_tx(tx_adsi, amp, BLOCK_LEN)) == 0) - push = 10; - } - else - { - len = 0; - /* Push a little silence through, to flush things out */ - if (--push == 0) - { - if (!good_message_received) - { - printf("No message received %s (%d)\n", adsi_standard_to_str(standard), i); - exit(2); - } - good_message_received = false; - adsi_msg_len = adsi_create_message(tx_adsi, adsi_msg); - adsi_msg_len = adsi_tx_put_message(tx_adsi, adsi_msg, adsi_msg_len); - } - } - if (len < BLOCK_LEN) - { - memset(&[len], 0, sizeof(int16_t)*(BLOCK_LEN - len)); - len = BLOCK_LEN; - } - if (log_audio) - { - outframes = sf_writef_short(outhandle, - amp, - len); - if (outframes != len) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - adsi_rx(rx_adsi, amp, len); - } - adsi_rx_free(rx_adsi); - adsi_tx_free(tx_adsi); - basic_testing = false; -} -/*- End of function --------------------------------------------------------*/ - -static void mitel_cm7291_side_2_and_bellcore_tests(int standard) -{ - int j; - int16_t amp[BLOCK_LEN]; - SNDFILE *inhandle; - int frames; - - /* The remainder of the Mitel tape is the talk-off test */ - /* Here we use the Bellcore test tapes (much tougher), in six - files - 1 from each side of the original 3 cassette tapes */ - printf("Talk-off tests for %s\n", adsi_standard_to_str(standard)); - rx_adsi = adsi_rx_init(NULL, standard, put_adsi_msg, NULL); - for (j = 0; bellcore_files[j][0]; j++) - { - printf("Testing with %s\n", bellcore_files[j]); - if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) - { - printf(" Cannot open speech file '%s'\n", bellcore_files[j]); - exit(2); - } - while ((frames = sf_readf_short(inhandle, amp, BLOCK_LEN))) - { - adsi_rx(rx_adsi, amp, frames); - } - if (sf_close_telephony(inhandle)) - { - printf(" Cannot close speech file '%s'\n", bellcore_files[j]); - exit(2); - } - } - adsi_rx_free(rx_adsi); - if (j > 470) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int16_t amp[BLOCK_LEN]; - SNDFILE *inhandle; - int len; - int test_standard; - int first_standard; - int last_standard; - int opt; - int enable_basic_tests; - int enable_talkoff_tests; - - log_audio = false; - decode_test_file = NULL; - test_standard = -1; - short_preamble = false; - enable_basic_tests = true; - enable_talkoff_tests = false; - while ((opt = getopt(argc, argv, "bd:lps:t")) != -1) - { - switch (opt) - { - case 'b': - enable_basic_tests = true; - enable_talkoff_tests = false; - break; - case 'd': - decode_test_file = optarg; - break; - case 'l': - log_audio = true; - break; - case 'p': - short_preamble = true; - break; - case 's': - if (strcasecmp("CLASS", optarg) == 0) - test_standard = ADSI_STANDARD_CLASS; - else if (strcasecmp("CLIP", optarg) == 0) - test_standard = ADSI_STANDARD_CLIP; - else if (strcasecmp("A-CLIP", optarg) == 0) - test_standard = ADSI_STANDARD_ACLIP; - else if (strcasecmp("J-CLIP", optarg) == 0) - test_standard = ADSI_STANDARD_JCLIP; - else if (strcasecmp("CLIP-DTMF", optarg) == 0) - test_standard = ADSI_STANDARD_CLIP_DTMF; - else if (strcasecmp("TDD", optarg) == 0) - test_standard = ADSI_STANDARD_TDD; - else - test_standard = atoi(optarg); - break; - case 't': - enable_basic_tests = false; - enable_talkoff_tests = true; - break; - default: - //usage(); - exit(2); - break; - } - } - outhandle = NULL; - - tdd_character_set_tests(); - - if (decode_test_file) - { - /* We will decode the audio from a file. */ - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - if (test_standard < 0) - current_standard = ADSI_STANDARD_CLASS; - else - current_standard = test_standard; - - rx_adsi = adsi_rx_init(NULL, current_standard, put_adsi_msg, NULL); - - span_log_set_level(adsi_rx_get_logging_state(rx_adsi), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(adsi_rx_get_logging_state(rx_adsi), "ADSI"); - - for (;;) - { - len = sf_readf_short(inhandle, amp, BLOCK_LEN); - if (len == 0) - break; - adsi_rx(rx_adsi, amp, len); - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - adsi_rx_free(rx_adsi); - } - else - { - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - } - /* Go through all the standards */ - /* This assumes standard 0 is NULL, and TDD is the last in the list */ - if (test_standard < 0) - { - first_standard = ADSI_STANDARD_CLASS; - last_standard = ADSI_STANDARD_TDD; - } - else - { - first_standard = - last_standard = test_standard; - } - for (current_standard = first_standard; current_standard <= last_standard; current_standard++) - { - if (enable_basic_tests) - basic_tests(current_standard); - if (enable_talkoff_tests) - mitel_cm7291_side_2_and_bellcore_tests(current_standard); - } - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - } - printf("Tests passed.\n"); - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/alloc_tests.c b/libs/spandsp/tests/alloc_tests.c deleted file mode 100644 index 2f64e6ae27..0000000000 --- a/libs/spandsp/tests/alloc_tests.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * alloc_tests.c - memory allocation handling tests. - * - * 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 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 deleted file mode 100644 index 48c96e4d36..0000000000 --- a/libs/spandsp/tests/async_tests.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * async_tests.c - Tests for asynchronous serial processing. - * - * 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 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 async_tests_page Asynchronous bit stream tests -\section async_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -async_rx_state_t rx_async; -async_tx_state_t tx_async; - -int full_len; -uint8_t old_buf[1000]; -uint8_t new_buf[1000]; - -volatile int tx_async_chars; -volatile int rx_async_chars; -volatile int rx_async_char_mask; - -int v14_test_async_tx_get_bit(void *user_data); - -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 - stop bits. */ - 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->bitpos++; - } - else - { - 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; -} -/*- End of function --------------------------------------------------------*/ - -static int test_get_async_byte(void *user_data) -{ - int byte; - - byte = tx_async_chars & 0xFF; - tx_async_chars++; - return byte; -} -/*- End of function --------------------------------------------------------*/ - -static void test_put_async_byte(void *user_data, int byte) -{ - if ((rx_async_chars & rx_async_char_mask) != byte) - printf("Received byte is 0x%X (expected 0x%X)\n", byte, rx_async_chars); - rx_async_chars++; -} -/*- End of function --------------------------------------------------------*/ - -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); - tx_async_chars = 0; - rx_async_chars = 0; - rx_async_char_mask = 0xFF; - while (rx_async_chars < 1000) - { - bit = async_tx_get_bit(&tx_async); - 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 - || - rx_async.parity_errors - || - rx_async.framing_errors) - { - printf("Test failed.\n"); - exit(2); - } - - 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); - tx_async_chars = 0; - rx_async_chars = 0; - rx_async_char_mask = 0x7F; - while (rx_async_chars < 1000) - { - bit = async_tx_get_bit(&tx_async); - 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 - || - rx_async.parity_errors - || - rx_async.framing_errors) - { - printf("Test failed.\n"); - exit(2); - } - - 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); - tx_async_chars = 0; - rx_async_chars = 0; - rx_async_char_mask = 0xFF; - while (rx_async_chars < 1000) - { - bit = async_tx_get_bit(&tx_async); - 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 - || - rx_async.parity_errors - || - rx_async.framing_errors) - { - printf("Test failed.\n"); - exit(2); - } - - 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); - tx_async_chars = 0; - rx_async_chars = 0; - rx_async_char_mask = 0xFF; - while (rx_async_chars < 1000) - { - bit = v14_test_async_tx_get_bit(&tx_async); - 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 - || - rx_async.parity_errors - || - rx_async.framing_errors) - { - printf("Test failed.\n"); - exit(2); - } - - 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); - tx_async_chars = 0; - rx_async_chars = 0; - rx_async_char_mask = 0x1F; - while (rx_async_chars < 1000) - { - bit = async_tx_get_bit(&tx_async); - 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 - || - rx_async.parity_errors - || - rx_async.framing_errors) - { - printf("Test failed.\n"); - exit(2); - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/at_interpreter_tests.c b/libs/spandsp/tests/at_interpreter_tests.c deleted file mode 100644 index d771afecf2..0000000000 --- a/libs/spandsp/tests/at_interpreter_tests.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * at_interpreter_tests.c - Tests for the AT interpreter. - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 2005, 2006 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 at_interpreter_tests_page AT interpreter tests -\section at_interpreter_tests_page_sec_1 What does it do? -These tests exercise all the commands which should be understood by the AT interpreter. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -#define DLE 0x10 -#define ETX 0x03 -#define SUB 0x1A - -#define MANUFACTURER "www.soft-switch.org" - -struct command_response_s -{ - const char *command; - const char *response; -}; - -static const struct command_response_s general_test_seq[] = -{ - /* Try the various cases for "AT" */ - {"atE1\r", "atE1\r\r\nOK\r\n"}, - {"AtE1\r", "AtE1\r\r\nOK\r\n"}, - {"aTE1\r", "aTE1\r\r\nOK\r\n"}, - {"ATE1\r", "ATE1\r\r\nOK\r\n"}, - {"ATE0\r", "ATE0\r\r\nOK\r\n"}, - - /* Try the various command formats */ - {"ATS8?\r", "\r\n005\r\n\r\nOK\r\n"}, - {"ATS8=1\r", "\r\nOK\r\n"}, - {"ATS8.5?\r", "\r\n0\r\n\r\nOK\r\n"}, - {"ATS8.5=1\r", "\r\nOK\r\n"}, - {"ATS8.5?\r", "\r\n1\r\n\r\nOK\r\n"}, - {"ATS8?\r", "\r\n033\r\n\r\nOK\r\n"}, - {"AT+FCLASS=1\r", "\r\nOK\r\n"}, - {"AT+FCLASS?\r", "\r\n1\r\n\r\nOK\r\n"}, - {"AT+FCLASS=?\r", "\r\n0,1,1.0\r\n\r\nOK\r\n"}, - - /* Try all the commands */ - {"AT&C\r", "\r\nOK\r\n"}, /* V.250 6.2.8 - Circuit 109 (received line signal detector), behaviour */ - {"AT&D\r", "\r\nOK\r\n"}, /* V.250 6.2.9 - Circuit 108 (data terminal ready) behaviour */ - {"AT&F\r", "\r\nOK\r\n"}, /* V.250 6.1.2 - Set to factory-defined configuration */ - {"ATE0\r", "ATE0\r\r\nOK\r\n"}, /* Counteract the effects of the above */ - {"AT+A8E=?\r", "\r\n+A8E:(0-6),(0-5),(00-FF)\r\n\r\nOK\r\n"}, /* V.251 5.1 - V.8 and V.8bis operation controls */ - {"AT+A8M\r", "\r\nOK\r\n"}, /* V.251 5.2 - Send V.8 menu signals */ - {"AT+A8T=?\r", "\r\n+A8T:(0-10)\r\n\r\nOK\r\n"}, /* V.251 5.3 - Send V.8bis signal and/or message(s) */ - {"AT+ASTO=?\r", "\r\n+ASTO:\r\n\r\nOK\r\n"}, /* V.250 6.3.15 - Store telephone number */ - {"AT+CAAP=?\r", "\r\n+CAAP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.25 - Automatic answer for eMLPP Service */ - {"AT+CACM=?\r", "\r\n+CACM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.25 - Accumulated call meter */ - {"AT+CACSP=?\r", "\r\n+CACSP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.7 - Voice Group or Voice Broadcast Call State Attribute Presentation */ - {"AT+CAEMLPP=?\r", "\r\n+CAEMLPP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.22 - eMLPP Priority Registration and Interrogation */ - {"AT+CAHLD=?\r", "\r\n+CAHLD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.3 - Leave an ongoing Voice Group or Voice Broadcast Call */ - {"AT+CAJOIN=?\r", "\r\n+CAJOIN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.1 - Accept an incoming Voice Group or Voice Broadcast Call */ - {"AT+CALA=?\r", "\r\n+CALA:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.16 - Alarm */ - {"AT+CALCC=?\r", "\r\n+CALCC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.6 - List current Voice Group and Voice Broadcast Calls */ - {"AT+CALD=?\r", "\r\n+CALD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.38 - Delete alar m */ - {"AT+CALM=?\r", "\r\n+CALM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.20 - Alert sound mode */ - {"AT+CAMM=?\r", "\r\n+CAMM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.26 - Accumulated call meter maximum */ - {"AT+CANCHEV=?\r", "\r\n+CANCHEV:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.8 - NCH Support Indication */ - {"AT+CAOC=?\r", "\r\n+CAOC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.16 - Advice of Charge */ - {"AT+CAPD=?\r", "\r\n+CAPD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.39 - Postpone or dismiss an alarm */ - {"AT+CAPTT=?\r", "\r\n+CAPTT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.4 - Talker Access for Voice Group Call */ - {"AT+CAREJ=?\r", "\r\n+CAREJ:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.2 - Reject an incoming Voice Group or Voice Broadcast Call */ - {"AT+CAULEV=?\r", "\r\n+CAULEV:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.5 - Voice Group Call Uplink Status Presentation */ - {"AT+CBC=?\r", "\r\n+CBC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.4 - Battery charge */ - {"AT+CBCS=?\r", "\r\n+CBCS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.3.2 - VBS subscriptions and GId status */ - {"AT+CBST=?\r", "\r\n+CBST:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.7 - Select bearer service type */ - {"AT+CCFC=?\r", "\r\n+CCFC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.11 - Call forwarding number and conditions */ - {"AT+CCLK=?\r", "\r\n+CCLK:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.15 - Clock */ - {"AT+CCUG=?\r", "\r\n+CCUG:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.10 - Closed user group */ - {"AT+CCWA=?\r", "\r\n+CCWA:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.12 - Call waiting */ - {"AT+CCWE=?\r", "\r\n+CCWE:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.28 - Call Meter maximum event */ - {"AT+CDIP=?\r", "\r\n+CDIP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.9 - Called line identification presentation */ - {"AT+CDIS=?\r", "\r\n+CDIS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.8 - Display control */ - {"AT+CEER=?\r", "\r\n+CEER:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.10 - Extended error report */ - {"AT+CFCS=?\r", "\r\n+CFCS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.24 - Fast call setup conditions */ - {"AT+CFUN=?\r", "\r\n+CFUN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.2 - Set phone functionality */ - {"AT+CGACT=?\r", "\r\n+CGACT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.10 - PDP context activate or deactivate */ - {"AT+CGANS=?\r", "\r\n+CGANS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.16 - Manual response to a network request for PDP context activation */ - {"AT+CGATT=?\r", "\r\n+CGATT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.9 - PS attach or detach */ - {"AT+CGAUTO=?\r", "\r\n+CGAUTO:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.15 - Automatic response to a network request for PDP context activation */ - {"AT+CGCLASS=?\r", "\r\n+CGCLASS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.17 - GPRS mobile station class (GPRS only) */ - {"AT+CGCLOSP=?\r", "\r\n+CGCLOSP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.13 - Configure local octet stream PAD parameters (Obsolete) */ - {"AT+CGCLPAD=?\r", "\r\n+CGCLPAD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.12 - Configure local triple-X PAD parameters (GPRS only) (Obsolete) */ - {"AT+CGCMOD=?\r", "\r\n+CGCMOD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.11 - PDP Context Modify */ - {"AT+CGCS=?\r", "\r\n+CGCS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.3.1 - VGCS subscriptions and GId status */ - {"AT+CGDATA=?\r", "\r\n+CGDATA:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.12 - Enter data state */ - {"AT+CGDCONT=?\r", "\r\n+CGDCONT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.1 - Define PDP Context */ - {"AT+CGDSCONT=?\r", "\r\n+CGDSCONT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.2 - Define Secondary PDP Context */ - {"AT+CGEQMIN=?\r", "\r\n+CGEQMIN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.7 - 3G Quality of Service Profile (Minimum acceptable) */ - {"AT+CGEQNEG=?\r", "\r\n+CGEQNEG:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.8 - 3G Quality of Service Profile (Negotiated) */ - {"AT+CGEQREQ=?\r", "\r\n+CGEQREQ:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.6 - 3G Quality of Service Profile (Requested) */ - {"AT+CGEREP=?\r", "\r\n+CGEREP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.18 - Packet Domain event reporting */ - {"AT+CGMI=?\r", "\r\n+CGMI:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.1 - Request manufacturer identification */ - {"AT+CGMM=?\r", "\r\n+CGMM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.2 - Request model identification */ - {"AT+CGMR=?\r", "\r\n+CGMR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.3 - Request revision identification */ - {"AT+CGPADDR=?\r", "\r\n+CGPADDR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.14 - Show PDP address */ - {"AT+CGQMIN=?\r", "\r\n+CGQMIN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.5 - Quality of Service Profile (Minimum acceptable) */ - {"AT+CGQREQ=?\r", "\r\n+CGQREQ:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.4 - Quality of Service Profile (Requested) */ - {"AT+CGREG=?\r", "\r\n+CGREG:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.19 - GPRS network registration status */ - {"AT+CGSMS=?\r", "\r\n+CGSMS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.20 - Select service for MO SMS messages */ - {"AT+CGSN=?\r", "\r\n+CGSN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.4 - Request product serial number identification */ - {"AT+CGTFT=?\r", "\r\n+CGTFT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 10.1.3 - Traffic Flow Template */ - {"AT+CHLD=?\r", "\r\n+CHLD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.13 - Call related supplementary services */ - {"AT+CHSA=?\r", "\r\n+CHSA:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.18 - HSCSD non-transparent asymmetry configuration */ - {"AT+CHSC=?\r", "\r\n+CHSC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.15 - HSCSD current call parameters */ - {"AT+CHSD=?\r", "\r\n+CHSD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.12 - HSCSD device parameters */ - {"AT+CHSN=?\r", "\r\n+CHSN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.14 - HSCSD non-transparent call configuration */ - {"AT+CHSR=?\r", "\r\n+CHSR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.16 - HSCSD parameters report */ - {"AT+CHST=?\r", "\r\n+CHST:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.13 - HSCSD transparent call configuration */ - {"AT+CHSU=?\r", "\r\n+CHSU:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.17 - HSCSD automatic user initiated upgrading */ - {"AT+CHUP=?\r", "\r\n+CHUP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.5 - Hangup call */ - {"AT+CIMI=?\r", "\r\n+CIMI:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.6 - Request international mobile subscriber identity */ - {"AT+CIND=?\r", "\r\n+CIND:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.9 - Indicator control */ - {"AT+CKPD=?\r", "\r\n+CKPD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.7 - Keypad control */ - {"AT+CLAC=?\r", "\r\n+CLAC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.37 - List all available AT commands */ - {"AT+CLAE=?\r", "\r\n+CLAE:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.31 - Language Event */ - {"AT+CLAN=?\r", "\r\n+CLAN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.30 - Set Language */ - {"AT+CLCC=?\r", "\r\n+CLCC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.18 - List current calls */ - {"AT+CLCK=?\r", "\r\n+CLCK:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.4 - Facility lock */ - {"AT+CLIP=?\r", "\r\n+CLIP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.6 - Calling line identification presentation */ - {"AT+CLIR=?\r", "\r\n+CLIR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.7 - Calling line identification restriction */ - {"AT+CLVL=?\r", "\r\n+CLVL:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.23 - Loudspeaker volume level */ - {"AT+CMAR=?\r", "\r\n+CMAR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.36 - Master Reset */ - {"AT+CMEC=?\r", "\r\n+CMEC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.6 - Mobile Termination control mode */ - {"AT+CMER=?\r", "\r\n+CMER:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.10 - Mobile Termination event reporting */ - {"AT+CMOD=?\r", "\r\n+CMOD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.4 - Call mode */ - {"AT+CMUT=?\r", "\r\n+CMUT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.24 - Mute control */ - {"AT+CMUX=?\r", "\r\n+CMUX:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.7 - Multiplexing mode */ - {"AT+CNUM=?\r", "\r\n+CNUM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.1 - Subscriber number */ - {"AT+COLP=?\r", "\r\n+COLP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.8 - Connected line identification presentation */ - {"AT+COPN=?\r", "\r\n+COPN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.21 - Read operator names */ - {"AT+COPS=?\r", "\r\n+COPS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.3 - PLMN selection */ - {"AT+COTDI=?\r", "\r\n+COTDI:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 11.1.9 - Originator to Dispatcher Information */ - {"AT+CPAS=?\r", "\r\n+CPAS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.1 - Phone activity status */ - {"AT+CPBF=?\r", "\r\n+CPBF:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.13 - Find phonebook entries */ - {"AT+CPBR=?\r", "\r\n+CPBR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.12 - Read phonebook entries */ - {"AT+CPBS=?\r", "\r\n+CPBS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.11 - Select phonebook memory storage */ - {"AT+CPBW=?\r", "\r\n+CPBW:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.14 - Write phonebook entry */ - {"AT+CPIN=?\r", "\r\n+CPIN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.3 - Enter PIN */ - {"AT+CPLS=?\r", "\r\n+CPLS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.20 - Selection of preferred PLMN list */ - {"AT+CPOL=?\r", "\r\n+CPOL:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.19 - Preferred PLMN list */ - {"AT+CPPS=?\r", "\r\n+CPPS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.23 - eMLPP subscriptions */ - {"AT+CPROT=?\r", "\r\n+CPROT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.42 - Enter protocol mode */ - {"AT+CPUC=?\r", "\r\n+CPUC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.27 - Price per unit and currency table */ - {"AT+CPWC=?\r", "\r\n+CPWC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.29 - Power class */ - {"AT+CPWD=?\r", "\r\n+CPWD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.5 - Change password */ - {"AT+CR=?\r", "\r\n+CR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.9 - Service reporting control */ - {"AT+CRC=?\r", "\r\n+CRC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.11 - Cellular result codes */ - {"AT+CREG=?\r", "\r\n+CREG:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.2 - Network registration */ - {"AT+CRLP=?\r", "\r\n+CRLP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.8 - Radio link protocol */ - {"AT+CRMC=?\r", "\r\n+CRMC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.34 - Ring Melody Control */ - {"AT+CRMP=?\r", "\r\n+CRMP:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.35 - Ring Melody Playback */ - {"AT+CRSL=?\r", "\r\n+CRSL:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.21 - Ringer sound level */ - {"AT+CRSM=?\r", "\r\n+CRSM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.18 - Restricted SIM access */ - {"AT+CSCC=?\r", "\r\n+CSCC:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.19 - Secure control command */ - {"AT+CSCS=?\r", "\r\n+CSCS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 5.5 - Select TE character set */ - {"AT+CSDF=?\r", "\r\n+CSDF:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.22 - Settings date format */ - {"AT+CSGT=?\r", "\r\n+CSGT:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.32 - Set Greeting Text */ - {"AT+CSIL=?\r", "\r\n+CSIL:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.23 - Silence Command */ - {"AT+CSIM=?\r", "\r\n+CSIM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.17 - Generic SIM access */ - {"AT+CSNS=?\r", "\r\n+CSNS:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.19 - Single numbering scheme */ - {"AT+CSQ=?\r", "\r\n+CSQ:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.5 - Signal quality */ - {"AT+CSSN=?\r", "\r\n+CSSN:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.17 - Supplementary service notifications */ - {"AT+CSTA=?\r", "\r\n+CSTA:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.1 - Select type of address */ - {"AT+CSTF=?\r", "\r\n+CSTF:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.24 - Settings time format */ - {"AT+CSVM=?\r", "\r\n+CSVM:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.33 - Set Voice Mail Number */ - {"AT+CTFR=?\r", "\r\n+CTFR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.14 - Call deflection */ - {"AT+CTZR=?\r", "\r\n+CTZR:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.41 - Time Zone Reporting */ - {"AT+CTZU=?\r", "\r\n+CTZU:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.40 - Automatic Time Zone Update */ - {"AT+CUSD=?\r", "\r\n+CUSD:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.15 - Unstructured supplementary service data */ - {"AT+CUUS1=?\r", "\r\n+CUUS1:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 7.26 - User to User Signalling Service 1 */ - {"AT+CV120=?\r", "\r\n+CV120:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.21 - V.120 rate adaption protocol */ - {"AT+CVHU=?\r", "\r\n+CVHU:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 6.20 - Voice Hangup Control */ - {"AT+CVIB=?\r", "\r\n+CVIB:\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 8.22 - Vibrator mode */ - {"AT+DR=?\r", "\r\n+DR:\r\n\r\nOK\r\n"}, /* V.250 6.6.2 - Data compression reporting */ - {"AT+DS=?\r", "\r\n+DS:\r\n\r\nOK\r\n"}, /* V.250 6.6.1 - Data compression */ - {"AT+EB=?\r", "\r\n+EB:\r\n\r\nOK\r\n"}, /* V.250 6.5.2 - Break handling in error control operation */ - {"AT+EFCS=?\r", "\r\n+EFCS:(0-2)\r\n\r\nOK\r\n"}, /* V.250 6.5.4 - 32-bit frame check sequence */ - {"AT+EFCS?\r", "\r\n+EFCS:0\r\n\r\nOK\r\n"}, - {"AT+EFRAM=?\r", "\r\n+EFRAM:(1-65535),(1-65535)\r\n\r\nOK\r\n"}, - /* V.250 6.5.8 - Frame length */ - {"AT+ER=?\r", "\r\n+ER:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.5.5 - Error control reporting */ - {"AT+ES=?\r", "\r\n+ES:(0-7),(0-4),(0-9)\r\n\r\nOK\r\n"}, /* V.250 6.5.1 - Error control selection */ - {"AT+ES?\r", "\r\n+ES:0,0,0\r\n\r\nOK\r\n"}, - {"AT+ESA=?\r", "\r\n+ESA:(0-2),(0-1),(0-1),(0-1),(0-2),(0-1),(0-255),(0-255)\r\n\r\nOK\r\n"}, - /* V.80 8.2 - Synchronous access mode configuration */ - {"AT+ESA?\r", "\r\n+ESA:0,0,0,0,0,0,0,0\r\n\r\nOK\r\n"}, - {"AT+ESR\r", "\r\nOK\r\n"}, /* V.250 6.5.3 - Selective repeat */ - {"AT+ETBM=?\r", "\r\n+ETBM:(0-2),(0-2),(0-30)\r\n\r\nOK\r\n"}, /* T.31 8.5.1 - Adaptive reception control */ - {"AT+ETBM?\r", "\r\n+ETBM:0,0\r\n\r\nOK\r\n"}, - {"AT+EWIND=?\r", "\r\n+EWIND:(1-127),(1-127)\r\n\r\nOK\r\n"}, /* V.250 6.5.7 - Window size */ - {"AT+EWIND?\r", "\r\n+EWIND:0,0\r\n\r\nOK\r\n"}, - {"AT+F34=?\r", "\r\n+F34:(0-14),(0-14),(0-2),(0-14),(0-14)\r\n\r\nOK\r\n"}, - /* T.31 B.6.1 - Initial V.34 rate controls for FAX */ - {"AT+F34?\r", "\r\n+F34:0,0,0,0,0\r\n\r\nOK\r\n"}, - {"AT+FAR=?\r", "\r\n0,1\r\n\r\nOK\r\n"}, /* T.31 8.5.1 - Adaptive reception control */ - {"AT+FAR?\r", "\r\n0\r\n\r\nOK\r\n"}, - {"AT+FCL=?\r", "\r\n(0-255)\r\n\r\nOK\r\n"}, /* T.31 8.5.2 - Carrier loss timeout */ - {"AT+FCLASS=?\r", "\r\n0,1,1.0\r\n\r\nOK\r\n"}, /* T.31 8.2 - Capabilities identification and control */ - {"AT+FCLASS?\r", "\r\n1\r\n\r\nOK\r\n"}, - {"AT+FDD=?\r", "\r\n(0,1)\r\n\r\nOK\r\n"}, /* T.31 8.5.3 - Double escape character replacement */ - {"AT+FDD?\r", "\r\n0\r\n\r\nOK\r\n"}, - {"AT+FIT=?\r", "\r\n+FIT:(0-255),(0-1)\r\n\r\nOK\r\n"}, /* T.31 8.5.4 - DTE inactivity timeout */ - {"AT+FIT?\r", "\r\n+FIT:0,0\r\n\r\nOK\r\n"}, - {"AT+FLO=?\r", "\r\n+FLO:(0-2)\r\n\r\nOK\r\n"}, /* T.31 says to implement something similar to +IFC */ - {"AT+FLO?\r", "\r\n+FLO:2\r\n\r\nOK\r\n"}, - {"AT+FMI?\r", "\r\n" MANUFACTURER "\r\n\r\nOK\r\n"}, /* T.31 says to duplicate +GMI */ - {"AT+FMM?\r", "\r\n" PACKAGE "\r\n\r\nOK\r\n"}, /* T.31 says to duplicate +GMM */ - {"AT+FMR?\r", "\r\n" VERSION "\r\n\r\nOK\r\n"}, /* T.31 says to duplicate +GMR */ - {"AT+FPR=?\r", "\r\n115200\r\n\r\nOK\r\n"}, /* T.31 says to implement something similar to +IPR */ - {"AT+FPR?\r", "\r\n0\r\n\r\nOK\r\n"}, - {"AT+FRH=?\r", "\r\n3\r\n\r\nOK\r\n"}, /* T.31 8.3.6 - HDLC receive */ - {"AT+FRH?\r", "\r\n-1\r\n\r\nOK\r\n"}, - {"AT+FRM=?\r", "\r\n24,48,72,73,74,96,97,98,121,122,145,146\r\n\r\nOK\r\n"}, /* T.31 8.3.4 - Facsimile receive */ - {"AT+FRM?\r", "\r\n-1\r\n\r\nOK\r\n"}, - {"AT+FRS=?\r", "\r\n0-255\r\n\r\nOK\r\n"}, /* T.31 8.3.2 - Receive silence */ - {"AT+FRS?\r", "\r\n-1\r\n\r\nOK\r\n"}, - {"AT+FTH=?\r", "\r\n3\r\n\r\nOK\r\n"}, /* T.31 8.3.5 - HDLC transmit */ - {"AT+FTH?\r", "\r\n-1\r\n\r\nOK\r\n"}, - {"AT+FTM=?\r", "\r\n24,48,72,73,74,96,97,98,121,122,145,146\r\n\r\nOK\r\n"}, /* T.31 8.3.3 - Facsimile transmit */ - {"AT+FTM?\r", "\r\n-1\r\n\r\nOK\r\n"}, - {"AT+FTS=?\r", "\r\n0-255\r\n\r\nOK\r\n"}, /* T.31 8.3.1 - Transmit silence */ - {"AT+FTS?\r", "\r\n-1\r\n\r\nOK\r\n"}, - {"AT+GCAP\r", "\r\nOK\r\n"}, /* V.250 6.1.9 - Request complete capabilities list */ - {"AT+GCI=?\r", "\r\n+GCI:(00-FF)\r\n\r\nOK\r\n"}, /* V.250 6.1.10 - Country of installation, */ - {"AT+GCI?\r", "\r\n+GCI:00\r\n\r\nOK\r\n"}, - {"AT+GMI?\r", "\r\n" MANUFACTURER "\r\n\r\nOK\r\n"}, /* V.250 6.1.4 - Request manufacturer identification */ - {"AT+GMM?\r", "\r\n" PACKAGE "\r\n\r\nOK\r\n"}, /* V.250 6.1.5 - Request model identification */ - {"AT+GMR?\r", "\r\n" VERSION "\r\n\r\nOK\r\n"}, /* V.250 6.1.6 - Request revision identification */ - {"AT+GOI\r", "\r\nOK\r\n"}, /* V.250 6.1.8 - Request global object identification */ - {"AT+GSN?\r", "\r\n42\r\n\r\nOK\r\n"}, /* V.250 6.1.7 - Request product serial number identification */ - {"AT+IBC=?\r", "\r\n+IBC:(0-2),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0.1),(0,1)\r\n\r\nOK\r\n"}, - /* V.80 7.9 - Control of in-band control */ - {"AT+IBC?\r", "\r\n+IBC:0,0,0,0,0,0,0,0,0,0,0,0,0\r\n\r\nOK\r\n"}, - {"AT+IBM=?\r", "\r\n+IBM:(0-7),(0-255),(0-255)\r\n\r\nOK\r\n"}, /* V.80 7.10 - In-band MARK idle reporting control */ - {"AT+IBM?\r", "\r\n+IBM:0,0,0\r\n\r\nOK\r\n"}, - {"AT+ICF?\r", "\r\n+ICF:0,0\r\n\r\nOK\r\n"}, /* V.250 6.2.11 - DTE-DCE character framing */ - {"AT+ICLOK?\r", "\r\n+ICLOK:0\r\n\r\nOK\r\n"}, /* V.250 6.2.14 - Select sync transmit clock source */ - {"AT+IDSR?\r", "\r\n+IDSR:0\r\n\r\nOK\r\n"}, /* V.250 6.2.16 - Select data set ready option */ - {"AT+IFC=?\r", "\r\n+IFC:(0-2),(0-2)\r\n\r\nOK\r\n"}, /* V.250 6.2.12 - DTE-DCE local flow control */ - {"AT+IFC?\r", "\r\n+IFC:2,2\r\n\r\nOK\r\n"}, - {"AT+ILRR\r", "\r\nOK\r\n"}, /* V.250 6.2.13 - DTE-DCE local rate reporting */ - {"AT+ILSD=?\r", "\r\n+ILSD:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.2.15 - Select long space disconnect option */ - {"AT+ILSD?\r", "\r\n+ILSD:0\r\n\r\nOK\r\n"}, - {"AT+IPR=?\r", "\r\n+IPR:(115200),(115200)\r\n\r\nOK\r\n"}, /* V.250 6.2.10 - Fixed DTE rate */ - {"AT+IPR?\r", "\r\n+IPR:0\r\n\r\nOK\r\n"}, - {"AT+IRTS=?\r", "\r\n+IRTS:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.2.17 - Select synchronous mode RTS option */ - {"AT+IRTS?\r", "\r\n+IRTS:0\r\n\r\nOK\r\n"}, - {"AT+MA\r", "\r\nOK\r\n"}, /* V.250 6.4.2 - Modulation automode control */ - {"AT+MR=?\r", "\r\n+MR:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.4.3 - Modulation reporting control */ - {"AT+MR?\r", "\r\n+MR:0\r\n\r\nOK\r\n"}, - {"AT+MS\r", "\r\nOK\r\n"}, /* V.250 6.4.1 - Modulation selection */ - {"AT+MSC=?\r", "\r\n+MSC:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.4.8 - Seamless rate change enable */ - {"AT+MSC?\r", "\r\n+MSC:0\r\n\r\nOK\r\n"}, - {"AT+MV18AM\r", "\r\nOK\r\n"}, /* V.250 6.4.6 - V.18 answering message editing */ - {"AT+MV18P=?\r", "\r\n+MV18P:(2-7)\r\n\r\nOK\r\n"}, /* V.250 6.4.7 - Order of probes */ - {"AT+MV18P?\r", "\r\n+MV18P:0\r\n\r\nOK\r\n"}, - {"AT+MV18R=?\r", "\r\n+MV18R:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.4.5 - V.18 reporting control */ - {"AT+MV18R?\r", "\r\n+MV18R:0\r\n\r\nOK\r\n"}, - {"AT+MV18S\r", "\r\nOK\r\n"}, /* V.250 6.4.4 - V.18 selection */ - {"AT+TADR\r", "\r\nOK\r\n"}, /* V.250 6.7.2.9 - Local V.54 address */ - {"AT+TAL=?\r", "\r\n+TAL:(0,1),(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.15 - Local analogue loop */ - {"AT+TAL?\r", "\r\n+TAL:0,0\r\n\r\nOK\r\n"}, - {"AT+TALS=?\r", "\r\n+TALS:(0-3)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.6 - Analogue loop status */ - {"AT+TALS?\r", "\r\n+TALS:0\r\n\r\nOK\r\n"}, - {"AT+TDLS=?\r", "\r\n+TDLS:(0-4)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.7 - Local digital loop status */ - {"AT+TDLS?\r", "\r\n+TDLS:0\r\n\r\nOK\r\n"}, - {"AT+TE140=?\r", "\r\n+TE140:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.1 - Enable ckt 140 */ - {"AT+TE140?\r", "\r\n+TE140:0\r\n\r\nOK\r\n"}, - {"AT+TE141=?\r", "\r\n+TE141:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.2 - Enable ckt 141 */ - {"AT+TE141?\r", "\r\n+TE141:0\r\n\r\nOK\r\n"}, - {"AT+TEPAL=?\r", "\r\n+TEPAL:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.5 - Enable front panel analogue loop */ - {"AT+TEPAL?\r", "\r\n+TEPAL:0\r\n\r\nOK\r\n"}, - {"AT+TEPDL=?\r", "\r\n+TEPDL:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.4 - Enable front panel RDL */ - {"AT+TEPDL?\r", "\r\n+TEPDL:0\r\n\r\nOK\r\n"}, - {"AT+TERDL=?\r", "\r\n+TERDL:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.3 - Enable RDL from remote */ - {"AT+TERDL?\r", "\r\n+TERDL:0\r\n\r\nOK\r\n"}, - {"AT+TLDL=?\r", "\r\n+TLDL:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.13 - Local digital loop */ - {"AT+TLDL?\r", "\r\n+TLDL:0\r\n\r\nOK\r\n"}, - {"AT+TMODE=?\r", "\r\n+TMODE:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.10 - Set V.54 mode */ - {"AT+TMODE?\r", "\r\n+TMODE:0\r\n\r\nOK\r\n"}, - {"AT+TNUM\r", "\r\nOK\r\n"}, /* V.250 6.7.2.12 - Errored bit and block counts */ - {"AT+TRDL=?\r", "\r\n+TRDL:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.14 - Request remote digital loop */ - {"AT+TRDL?\r", "\r\n+TRDL:0\r\n\r\nOK\r\n"}, - {"AT+TRDLS\r", "\r\nOK\r\n"}, /* V.250 6.7.2.8 - Remote digital loop status */ - {"AT+TRES=?\r", "\r\n+TRES:(0-2)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.17 - Self test result */ - {"AT+TRES?\r", "\r\n+TRES:0\r\n\r\nOK\r\n"}, - {"AT+TSELF=?\r", "\r\n+TSELF:(0,1)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.16 - Self test */ - {"AT+TSELF?\r", "\r\n+TSELF:0\r\n\r\nOK\r\n"}, - {"AT+TTER=?\r", "\r\n+TTER:(0-65535),(0-65535)\r\n\r\nOK\r\n"}, /* V.250 6.7.2.11 - Test error rate */ - {"AT+TTER?\r", "\r\n+TTER:0,0\r\n\r\nOK\r\n"}, - {"AT+VBT\r", "\r\nOK\r\n"}, /* 3GPP TS 27.007 C.2.2 - Buffer threshold setting */ - {"AT+VCID=?\r", "\r\n0,1\r\n\r\nOK\r\n"}, /* 3GPP TS 27.007 C.2.3 - Calling number ID presentation */ - {"AT+VCID?\r", "\r\n0\r\n\r\nOK\r\n"}, - {"AT+VDR\r", "\r\nOK\r\n"}, /* V.253 10.3.1 - Distinctive ring (ring cadence reporting) */ - {"AT+VDT\r", "\r\nOK\r\n"}, /* V.253 10.3.2 - Control tone cadence reporting */ - {"AT+VDX\r", "\r\nOK\r\n"}, /* V.253 10.5.6 - Speakerphone duplex mode */ - {"AT+VEM\r", "\r\nOK\r\n"}, /* V.253 10.5.7 - Deliver event reports */ - {"AT+VGM\r", "\r\nOK\r\n"}, /* V.253 10.5.2 - Microphone gain */ - {"AT+VGR\r", "\r\nOK\r\n"}, /* V.253 10.2.1 - Receive gain selection */ - {"AT+VGS\r", "\r\nOK\r\n"}, /* V.253 10.5.3 - Speaker gain */ - {"AT+VGT\r", "\r\nOK\r\n"}, /* V.253 10.2.2 - Volume selection */ - {"AT+VIP\r", "\r\nOK\r\n"}, /* V.253 10.1.1 - Initialize voice parameters */ - {"AT+VIT\r", "\r\nOK\r\n"}, /* V.253 10.2.3 - DTE/DCE inactivity timer */ - {"AT+VLS\r", "\r\nOK\r\n"}, /* V.253 10.2.4 - Analogue source/destination selection */ - {"AT+VPP\r", "\r\nOK\r\n"}, /* V.253 10.4.2 - Voice packet protocol */ - {"AT+VRA\r", "\r\nOK\r\n"}, /* V.253 10.2.5 - Ringing tone goes away timer */ - {"AT+VRID?\r", "\r\n0\r\n\r\nOK\r\n"}, /* Extension - Find the originating and destination numbers */ - {"AT+VRL\r", "\r\nOK\r\n"}, /* V.253 10.1.2 - Ring local phone */ - {"AT+VRN\r", "\r\nOK\r\n"}, /* V.253 10.2.6 - Ringing tone never appeared timer */ - {"AT+VRX\r", "\r\nOK\r\n"}, /* V.253 10.1.3 - Voice receive state */ - {"AT+VSD\r", "\r\nOK\r\n"}, /* V.253 10.2.7 - Silence detection (QUIET and SILENCE) */ - {"AT+VSID=12345\r", "\r\nOK\r\n"}, /* Extension - Set the originating number */ - {"AT+VSID?\r", "\r\n12345\r\n\r\nOK\r\n"}, - {"AT+VSM\r", "\r\nOK\r\n"}, /* V.253 10.2.8 - Compression method selection */ - {"AT+VSP\r", "\r\nOK\r\n"}, /* V.253 10.5.1 - Voice speakerphone state */ - {"AT+VTA\r", "\r\nOK\r\n"}, /* V.253 10.5.4 - Train acoustic echo-canceller */ - {"AT+VTD\r", "\r\nOK\r\n"}, /* V.253 10.2.9 - Beep tone duration timer */ - {"AT+VTH\r", "\r\nOK\r\n"}, /* V.253 10.5.5 - Train line echo-canceller */ - {"AT+VTR\r", "\r\nOK\r\n"}, /* V.253 10.1.4 - Voice duplex state */ - {"AT+VTS\r", "\r\nOK\r\n"}, /* V.253 10.1.5 - DTMF and tone generation in voice */ - {"AT+VTX\r", "\r\nOK\r\n"}, /* V.253 10.1.6 - Transmit data state */ - {"AT+WS46\r", "\r\nOK\r\n"}, /* 3GPP TS 27.007 5.9 - PCCA STD-101 [17] select wireless network */ - {"ATA\r", "\r\nERROR\r\n"}, /* V.250 6.3.5 - Answer */ - {"ATDT -1234567890ABCDPSTW*#+,!@\r;", ""}, /* V.250 6.3.1 - Dial */ - {"ATE1\r", "\r\nOK\r\n"}, /* V.250 6.2.4 - Command echo */ - {"ATE0\r", "ATE0\r\r\nOK\r\n"}, /* V.250 6.2.4 - Command echo */ - {"ATH\r", "\r\nOK\r\n"}, /* V.250 6.3.6 - Hook control */ - {"ATI\r", "\r\n" PACKAGE "\r\n\r\nOK\r\n"}, /* V.250 6.1.3 - Request identification information */ - {"ATL\r", "\r\nOK\r\n"}, /* V.250 6.3.13 - Monitor speaker loudness */ - {"ATM\r", "\r\nOK\r\n"}, /* V.250 6.3.14 - Monitor speaker mode */ - {"ATO\r", "\r\nCONNECT\r\n\r\nOK\r\n"}, /* V.250 6.3.7 - Return to online data state */ - {"ATP\r", "\r\nOK\r\n"}, /* V.250 6.3.3 - Select pulse dialling (command) */ - {"ATQ\r", "\r\nOK\r\n"}, /* V.250 6.2.5 - Result code suppression */ - {"ATS0=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.3.8 - Automatic answer */ - {"ATS0?\r", "\r\n000\r\n\r\nOK\r\n"}, - {"ATS10=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.3.12 - Automatic disconnect delay */ - {"ATS10?\r", "\r\n000\r\n\r\nOK\r\n"}, - {"ATS3=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.2.1 - Command line termination character */ - {"ATS3?\r", "\r\n013\r\n\r\nOK\r\n"}, - {"ATS4=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.2.2 - Response formatting character */ - {"ATS4?\r", "\r\n010\r\n\r\nOK\r\n"}, - {"ATS5=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.2.3 - Command line editing character */ - {"ATS5?\r", "\r\n008\r\n\r\nOK\r\n"}, - {"ATS6=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.3.9 - Pause before blind dialling */ - {"ATS6?\r", "\r\n001\r\n\r\nOK\r\n"}, - {"ATS7=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.3.10 - Connection completion timeout */ - {"ATS7?\r", "\r\n060\r\n\r\nOK\r\n"}, - {"ATS8=?\r", "\r\n000\r\n\r\nOK\r\n"}, /* V.250 6.3.11 - Comma dial modifier time */ - {"ATS8?\r", "\r\n005\r\n\r\nOK\r\n"}, - {"ATT\r", "\r\nOK\r\n"}, /* V.250 6.3.2 - Select tone dialling (command) */ - {"ATV0\r", "0\r"}, /* V.250 6.2.6 - DCE response format */ - {"ATV1\r", "\r\nOK\r\n"}, - {"ATX4\r", "\r\nOK\r\n"}, /* V.250 6.2.7 - Result code selection and call progress monitoring control */ - {"ATZ\r", "\r\nOK\r\n"}, /* V.250 6.1.1 - Reset to default configuration */ - {"", ""} -}; - -char *decode_test_file = NULL; -int countdown = 0; -int command_response_test_step = -1; -char response_buf[1000]; -int response_buf_ptr = 0; - -static int at_rx(at_state_t *s, const char *t, int len) -{ - at_interpreter(s, t, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int at_send(at_state_t *s, const char *t) -{ - printf("%s", t); - at_rx(s, t, strlen(t)); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -static int at_send_at(at_state_t *s, const char *t) -{ - uint8_t buf[500]; - - sprintf((char *) buf, "AT%s\r", t); - printf("%s", t); - at_rx(s, t, strlen(t)); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int at_expect(at_state_t *s, const char *t) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int at_send_hdlc(at_state_t *s, uint8_t *t, int len) -{ - uint8_t buf[100]; - int i; - int j; - - for (i = 0, j = 0; i < len; i++) - { - if (*t == DLE) - buf[j++] = DLE; - buf[j++] = *t++; - } - buf[j++] = DLE; - buf[j++] = ETX; - at_rx(s, (char *) buf, j); - return 0; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static int general_test(at_state_t *s) -{ - int i; - - for (i = 0; general_test_seq[i].command[0]; i++) - { - response_buf_ptr = 0; - response_buf[0] = '\0'; - command_response_test_step = i; - at_send(s, general_test_seq[i].command); - if (strcmp(general_test_seq[command_response_test_step].response, response_buf) != 0) - { - printf("Incorrect response\n"); - printf("Expected: '%s'\n", general_test_seq[command_response_test_step].response); - printf("Received: '%s'\n", response_buf); - return -1; - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int modem_call_control(void *user_data, int op, const char *num) -{ - switch (op) - { - case AT_MODEM_CONTROL_CALL: - printf("\nModem control - Dialing '%s'\n", num); - break; - case AT_MODEM_CONTROL_ANSWER: - printf("\nModem control - Answering\n"); - /* Force an error response, so we get something well defined for the test. */ - return -1; - case AT_MODEM_CONTROL_HANGUP: - printf("\nModem control - Hanging up\n"); - break; - case AT_MODEM_CONTROL_OFFHOOK: - printf("\nModem control - Going off hook\n"); - break; - case AT_MODEM_CONTROL_ONHOOK: - printf("\nModem control - Going on hook\n"); - break; - case AT_MODEM_CONTROL_DTR: - printf("\nModem control - DTR %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RTS: - printf("\nModem control - RTS %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CTS: - printf("\nModem control - CTS %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CAR: - printf("\nModem control - CAR %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RNG: - printf("\nModem control - RNG %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DSR: - printf("\nModem control - DSR %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_SETID: - printf("\nModem control - Set ID '%s'\n", num); - break; - case AT_MODEM_CONTROL_RESTART: - printf("\nModem control - Restart %d\n", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - printf("\nModem control - Set DTE timeout %d\n", (int) (intptr_t) num); - break; - default: - printf("\nModem control - operation %d\n", op); - break; - } - /*endswitch*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int at_tx_handler(void *user_data, const uint8_t *buf, size_t len) -{ - int i; - - for (i = 0; i < len; i++) - { - response_buf[response_buf_ptr++] = buf[i]; - putchar(buf[i]); - } - response_buf[response_buf_ptr] = '\0'; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - at_state_t *at_state; - - if ((at_state = at_init(NULL, at_tx_handler, NULL, modem_call_control, NULL)) == NULL) - { - fprintf(stderr, "Cannot start the AT interpreter\n"); - exit(2); - } - if (general_test(at_state)) - { - printf("Tests failed.\n"); - exit(2); - } - printf("Tests passed.\n"); - at_free(at_state); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/awgn_tests.c b/libs/spandsp/tests/awgn_tests.c deleted file mode 100644 index 09e7884e33..0000000000 --- a/libs/spandsp/tests/awgn_tests.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * awgn_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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. - */ - -/*! \page awgn_tests_page AWGN tests -\section awgn_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#if !defined(M_PI) -# define M_PI 3.14159265358979323846 /* pi */ -#endif - -#define OUT_FILE_NAME "awgn.wav" - -/* Some simple sanity tests for the Gaussian noise generation routines */ - -int main(int argc, char *argv[]) -{ - int i; - int j; - int clip_high; - int clip_low; - int total_samples; - int idum = 1234567; - int16_t value; - double total; - double x; - double p; - double o; - double error; - int bins[65536]; - awgn_state_t *noise_source; - - /* Generate noise at several RMS levels between -50dBm and 0dBm. Noise is - generated for a large number of samples (1,000,000), and the RMS value - of the noise is calculated along the way. If the resulting level is - close to the requested RMS level, at least the scaling of the noise - should be Ok. At high level some clipping may distort the result a - little. */ - for (j = -50; j <= 0; j += 5) - { - clip_high = 0; - clip_low = 0; - total = 0.0; - if ((noise_source = awgn_init_dbm0(NULL, idum, (float) j)) == NULL) - { - printf("Failed to allocate AWGN source\n"); - exit(2); - } - total_samples = 1000000; - for (i = 0; i < total_samples; i++) - { - value = awgn(noise_source); - if (value == 32767) - clip_high++; - else if (value == -32768) - clip_low++; - total += ((double) value)*((double) value); - } - error = 100.0*(1.0 - sqrt(total/total_samples)/noise_source->rms); - printf("RMS = %.3f (expected %d) %.2f%% error [clipped samples %d+%d]\n", - 10.0*log10((total/total_samples)/(32768.0*32768.0) + 1.0e-10) + DBM0_MAX_POWER, - j, - error, - clip_low, - clip_high); - /* We don't check the result at 0dBm0, as there will definitely be a lot of error due to clipping */ - if (j < 0 && fabs(error) > 0.2) - { - printf("Test failed.\n"); - exit(2); - } - awgn_free(noise_source); - } - /* Now look at the statistical spread of the results, by collecting data in - bins from a large number of samples. Use a fairly high noise level, but - low enough to avoid significant clipping. Use the Gaussian model to - predict the real probability, and present the results for graphing. */ - memset(bins, 0, sizeof(bins)); - clip_high = 0; - clip_low = 0; - if ((noise_source = awgn_init_dbm0(NULL, idum, -15.0)) == NULL) - { - printf("Failed to allocate AWGN source\n"); - exit(2); - } - total_samples = 10000000; - for (i = 0; i < total_samples; i++) - { - value = awgn(noise_source); - if (value == 32767) - clip_high++; - else if (value == -32768) - clip_low++; - bins[value + 32768]++; - } - o = noise_source->rms; - for (i = 0; i < 65536 - 10; i++) - { - x = i - 32768; - /* Find the real probability for this bin */ - p = (1.0/(o*sqrt(2.0*M_PI)))*exp(-(x*x)/(2.0*o*o)); - /* Now do a little smoothing on the real data to get a reasonably - steady answer */ - x = 0; - for (j = 0; j < 10; j++) - x += bins[i + j]; - x /= 10.0; - x /= total_samples; - /* Now send it out for graphing. */ - printf("%6d %.7f %.7f\n", i - 32768, x, p); - } - awgn_free(noise_source); - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/bell_mf_rx_tests.c b/libs/spandsp/tests/bell_mf_rx_tests.c deleted file mode 100644 index 3160c6d765..0000000000 --- a/libs/spandsp/tests/bell_mf_rx_tests.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bell_mf_tests.c - Test the Bell MF detector against the spec., whatever the - * spec. may be :) - * - * 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 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 bell_mf_tests_page Bell MF tone generation and detection tests -\section bell_mf_tests_page_sec_1 What does it do? -These tests are fashioned after those on the CM7291 test tape from -Mitel. Those tests are for DTMF, rather than Bell MF, but make a -fair starting point for a set of meaningful tests of Bell MF. - -These tests include conversion to and from A-law. It is assumed the -distortion this produces is comparable to u-law, so it should be -a fair test of performance in a real PSTN channel. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -/* Basic Bell MF specs: - * - * Signal generation: - * Tone on time = KP: 100+-7ms. All other signals: 68+-7ms - * Tone off time (between digits) = 68+-7ms - * Frequency tolerance +- 1.5% - * Signal level -7+-1dBm per frequency - * - * Signal reception: - * Frequency tolerance +- 1.5% +-10Hz - * Signal level -14dBm to 0dBm - * Perform a "two and only two tones present" test. - * Twist <= 6dB accepted - * Receiver sensitive to signals above -22dBm per frequency - * Test for a minimum of 55ms if KP, or 30ms of other signals. - * Signals to be recognised if the two tones arrive within 8ms of each other. - * Invalid signals result in the return of the re-order tone. - */ - -#define MF_DURATION (68*8) -#define MF_PAUSE (68*8) -#define MF_CYCLE (MF_DURATION + MF_PAUSE) - -#define SAMPLES_PER_CHUNK 160 - -/*! - MF tone descriptor for tests. -*/ -typedef struct -{ - float f1; /* First freq */ - float f2; /* Second freq */ - int8_t level1; /* Level of the first freq (dB) */ - int8_t level2; /* Level of the second freq (dB) */ - uint8_t on_time; /* Tone on time (ms) */ - uint8_t off_time; /* Minimum post tone silence (ms) */ -} mf_digit_tones_t; - -static const mf_digit_tones_t bell_mf_tones[] = -{ - { 700.0, 900.0, -7, -7, 68, 68}, - { 700.0, 1100.0, -7, -7, 68, 68}, - { 900.0, 1100.0, -7, -7, 68, 68}, - { 700.0, 1300.0, -7, -7, 68, 68}, - { 900.0, 1300.0, -7, -7, 68, 68}, - {1100.0, 1300.0, -7, -7, 68, 68}, - { 700.0, 1500.0, -7, -7, 68, 68}, - { 900.0, 1500.0, -7, -7, 68, 68}, - {1100.0, 1500.0, -7, -7, 68, 68}, - {1300.0, 1500.0, -7, -7, 68, 68}, - { 700.0, 1700.0, -7, -7, 68, 68}, /* ST''' - use 'C' */ - { 900.0, 1700.0, -7, -7, 68, 68}, /* ST' - use 'A' */ - {1100.0, 1700.0, -7, -7, 100, 68}, /* KP - use '*' */ - {1300.0, 1700.0, -7, -7, 68, 68}, /* ST'' - use 'B' */ - {1500.0, 1700.0, -7, -7, 68, 68}, /* ST - use '#' */ - {0.0, 0.0, 0, 0, 0, 0} -}; - -static tone_gen_descriptor_t my_mf_digit_tones[16]; - -static char bell_mf_tone_codes[] = "1234567890CA*B#"; - -bool callback_ok; -int callback_roll; - -codec_munge_state_t *munge = NULL; - -char *decode_test_file = NULL; - -static void my_mf_gen_init(float low_fudge, - int low_level, - float high_fudge, - int high_level, - int duration, - int gap) -{ - int i; - - /* The fiddle factor on the tone duration is to make KP consistently - 50% longer than the other digits, as the digit durations are varied - for the tests. This is an approximation, as the real scaling should - be 100/68 */ - for (i = 0; i < 15; i++) - { - tone_gen_descriptor_init(&my_mf_digit_tones[i], - bell_mf_tones[i].f1*(1.0 + low_fudge), - low_level, - bell_mf_tones[i].f2*(1.0 + high_fudge), - high_level, - (i == 12) ? 3*duration/2 : duration, - gap, - 0, - 0, - false); - } -} -/*- End of function --------------------------------------------------------*/ - -static int my_mf_generate(int16_t amp[], const char *digits) -{ - int len; - char *cp; - tone_gen_state_t tone; - - len = 0; - while (*digits) - { - if ((cp = strchr(bell_mf_tone_codes, *digits))) - { - tone_gen_init(&tone, &my_mf_digit_tones[cp - bell_mf_tone_codes]); - len += tone_gen(&tone, amp + len, 9999); - } - digits++; - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -#define ALL_POSSIBLE_DIGITS "1234567890CA*B#" - -static void digit_delivery(void *data, const char *digits, int len) -{ - int i; - int seg; - const char *s = ALL_POSSIBLE_DIGITS; - const char *t; - - if (data != (void *) 0x12345678) - { - callback_ok = false; - return; - } - callback_ok = true; - t = s + callback_roll; - seg = 15 - callback_roll; - for (i = 0; i < len; i += seg, seg = 15) - { - if (i + seg > len) - seg = len - i; - if (memcmp(digits + i, t, seg)) - { - callback_ok = false; - printf("Fail at %d %d\n", i, seg); - break; - } - t = s; - callback_roll = (callback_roll + seg)%15; - } -} -/*- End of function --------------------------------------------------------*/ - -static int16_t amp[1000000]; - -static int test_tone_set(void) -{ - int i; - int j; - int len; - int sample; - const char *s; - char digit[2]; - char buf[MAX_BELL_MF_DIGITS + 1]; - int actual; - int nplus; - int nminus; - float rrb; - float rcfo; - bell_mf_rx_state_t *mf_state; - awgn_state_t noise_source; - - mf_state = bell_mf_rx_init(NULL, NULL, NULL); - - /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step, - which has no meaning here. */ - printf("Test 1: Calibration\n"); - printf(" Passed\n"); - - /* Test 2: Decode check - This is a sanity check, that all digits are reliably detected - under ideal conditions. Each possible digit is repeated 10 times, - with 68ms bursts. The level of each tone is about 6dB down from clip */ - printf("Test 2: Decode check\n"); - my_mf_gen_init(0.0, -3, 0.0, -3, 68, 68); - s = ALL_POSSIBLE_DIGITS; - digit[1] = '\0'; - while (*s) - { - digit[0] = *s++; - for (i = 0; i < 10; i++) - { - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - actual = bell_mf_rx_get(mf_state, buf, 128); - if (actual != 1 || buf[0] != digit[0]) - { - printf(" Sent '%s'\n", digit); - printf(" Received '%s' [%d]\n", buf, actual); - printf(" Failed\n"); - exit(2); - } - } - } - printf(" Passed\n"); - - /* Test 3: Recognition bandwidth and channel centre frequency check. - Use all digits. Each digit types requires four tests to complete - the check. Each section contains 40 pulses of 68ms duration, - with an amplitude of -20dB from clip per frequency. - - Four sections covering the tests for one tone (1 digit) are: - a. H frequency at 0% deviation from center, L frequency at +0.1%. - L frequency is then increments in +01.% steps up to +4%. The - number of tone bursts is noted and designated N+. - b. H frequency at 0% deviation, L frequency at -0.1%. L frequency - is then incremental in -0.1% steps, up to -4%. The number of - tone bursts is noted and designated N-. - c. The test in (a) is repeated with the L frequency at 0% and the - H frequency varied up to +4%. - d. The test in (b) is repeated with the L frequency and 0% and the - H frequency varied to -4%. - - Receiver Recognition Bandwidth (RRB) is calculated as follows: - RRB% = (N+ + N-)/10 - Receiver Center Frequency Offset (RCFO) is calculated as follows: - RCFO% = X + (N+ - N-)/20 - - Note that this test doesn't test what it says it is testing at all, - and the results are quite inaccurate, if not a downright lie! However, - it follows the Mitel procedure, so how can it be bad? :) - - The spec calls for +-1.5% +-10Hz of bandwidth. - */ - printf("Test 3: Recognition bandwidth and channel centre frequency check\n"); - s = ALL_POSSIBLE_DIGITS; - digit[1] = '\0'; - j = 0; - while (*s) - { - digit[0] = *s++; - for (nplus = 0, i = 1; i <= 60; i++) - { - my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, 68); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - nplus += bell_mf_rx_get(mf_state, buf, 128); - } - for (nminus = 0, i = -1; i >= -60; i--) - { - my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, 68); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - nminus += bell_mf_rx_get(mf_state, buf, 128); - } - rrb = (float) (nplus + nminus)/10.0; - rcfo = (float) (nplus - nminus)/10.0; - printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", - digit[0], - rrb, - rcfo, - (float) nminus/10.0, - (float) nplus/10.0); - - if (rrb < 3.0 + rcfo + (2.0*100.0*10.0/bell_mf_tones[j].f1) || rrb >= 15.0 + rcfo) - { - printf(" Failed\n"); - exit(2); - } - - for (nplus = 0, i = 1; i <= 60; i++) - { - my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, 68); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - nplus += bell_mf_rx_get(mf_state, buf, 128); - } - for (nminus = 0, i = -1; i >= -60; i--) - { - my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, 68); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - nminus += bell_mf_rx_get(mf_state, buf, 128); - } - rrb = (float) (nplus + nminus)/10.0; - rcfo = (float) (nplus - nminus)/10.0; - printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", - digit[0], - rrb, - rcfo, - (float) nminus/10.0, - (float) nplus/10.0); - if (rrb < 3.0 + rcfo + (2.0*100.0*10.0/bell_mf_tones[j].f2) || rrb >= 15.0 + rcfo) - { - printf(" Failed\n"); - exit(2); - } - j++; - } - printf(" Passed\n"); - - /* Test 4: Acceptable amplitude ratio (twist). - Twist all digits in both directions, and check the maximum twist - we can accept. The way this is done is styled after the Mitel DTMF - test, and has good and bad points. */ - - printf("Test 4: Acceptable amplitude ratio (twist)\n"); - s = ALL_POSSIBLE_DIGITS; - digit[1] = '\0'; - while (*s) - { - digit[0] = *s++; - for (nplus = 0, i = -50; i >= -250; i--) - { - my_mf_gen_init(0.0, -5, 0.0, i/10, 68, 68); - - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - nplus += bell_mf_rx_get(mf_state, buf, 128); - } - printf(" %c normal twist = %.2fdB\n", digit[0], (float) nplus/10.0); - if (nplus < 60) - { - printf(" Failed\n"); - exit(2); - } - for (nminus = 0, i = -50; i >= -250; i--) - { - my_mf_gen_init(0.0, i/10, 0.0, -5, 68, 68); - - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - nminus += bell_mf_rx_get(mf_state, buf, 128); - } - printf(" %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0); - if (nminus < 60) - { - printf(" Failed\n"); - exit(2); - } - } - printf(" Passed\n"); - - /* Test 5: Dynamic range - This test sends all possible digits, with gradually increasing - amplitude. We determine the span over which we achieve reliable - detection. The spec says we should detect between -14dBm and 0dBm, - but the tones clip above -3dBm, so this cannot really work. */ - - printf("Test 5: Dynamic range\n"); - for (nplus = nminus = -1000, i = -50; i <= 3; i++) - { - my_mf_gen_init(0.0, i, 0.0, i, 68, 68); - for (j = 0; j < 100; j++) - { - len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - if (bell_mf_rx_get(mf_state, buf, 128) != 15) - break; - if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0) - break; - } - if (j == 100) - { - if (nplus == -1000) - nplus = i; - } - else - { - if (nplus != -1000 && nminus == -1000) - nminus = i; - } - } - printf(" Dynamic range = %ddB to %ddB\n", nplus, nminus - 1); - if (nplus > -22 || nminus <= -3) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - /* Test 6: Guard time - This test sends all possible digits, with a gradually reducing - duration. The spec defines a narrow range of tone duration - times we can expect, so as long as we detect reliably at the - specified minimum we should be OK. However, the spec also says - we should detect on a minimum of 55ms of KP, or 30ms of other - digits. */ - - printf("Test 6: Guard time\n"); - for (i = 30; i < 62; i++) - { - my_mf_gen_init(0.0, -5, 0.0, -3, i, 68); - for (j = 0; j < 500; j++) - { - len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - if (bell_mf_rx_get(mf_state, buf, 128) != 15) - break; - if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0) - break; - } - if (j == 500) - break; - } - printf(" Guard time = %dms\n", i); - if (i > 61) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - /* Test 7: Acceptable signal to noise ratio - We send all possible digits at -6dBm from clip, mixed with AWGN. - We gradually reduce the noise until we get clean detection. */ - - printf("Test 7: Acceptable signal to noise ratio\n"); - my_mf_gen_init(0.0, -3, 0.0, -3, 68, 68); - for (i = -10; i > -50; i--) - { - awgn_init_dbm0(&noise_source, 1234567, (float) i); - for (j = 0; j < 500; j++) - { - len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS); - for (sample = 0; sample < len; sample++) - amp[sample] = sat_add16(amp[sample], awgn(&noise_source)); - codec_munge(munge, amp, len); - bell_mf_rx(mf_state, amp, len); - if (bell_mf_rx_get(mf_state, buf, 128) != 15) - break; - if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0) - break; - } - if (j == 500) - break; - } - printf(" Acceptable S/N ratio is %ddB\n", -3 - i); - if (-3 - i > 26) - { - printf(" Failed\n"); - exit(2); - } - bell_mf_rx_free(mf_state); - printf(" Passed\n"); - - /* The remainder of the Mitel tape is the talk-off test. This is - meaningless for Bell MF. However the decoder's tolerance of - out of band noise is significant. */ - /* TODO: add a OOB tolerance test. */ - - /* Test the callback mode for delivering detected digits */ - - printf("Test: Callback digit delivery mode.\n"); - 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); - for (i = 1; i < 10; i++) - { - len = 0; - for (j = 0; j < i; j++) - len += my_mf_generate(amp + len, ALL_POSSIBLE_DIGITS); - bell_mf_rx(mf_state, amp, len); - if (!callback_ok) - break; - } - if (!callback_ok) - { - printf(" Failed\n"); - exit(2); - } - bell_mf_rx_free(mf_state); - printf(" Passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void digit_delivery_decode(void *data, const char *digits, int len) -{ - int i; - - if (data != (void *) 0x12345678) - { - return; - } - for (i = 0; i < len; i++) - { - printf("Digit '%c'\n", digits[i]); - } -} -/*- End of function --------------------------------------------------------*/ - -static void decode_test(const char *test_file) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - SNDFILE *inhandle; - bell_mf_rx_state_t *mf_state; - int samples; - - mf_state = bell_mf_rx_init(NULL, digit_delivery_decode, (void *) 0x12345678); - - /* We will decode the audio from a file. */ - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - - while ((samples = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK)) > 0) - { - codec_munge(munge, amp, samples); - bell_mf_rx(mf_state, amp, samples); - } -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - time_t now; - time_t duration; - decode_test_file = NULL; - int opt; - - while ((opt = getopt(argc, argv, "d:")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - munge = codec_munge_init(MUNGE_CODEC_ULAW, 0); - if (decode_test_file) - { - decode_test(decode_test_file); - } - else - { - now = time(NULL); - test_tone_set(); - duration = time (NULL) - now; - printf("Tests passed in %lds\n", duration); - } - codec_munge_free(munge); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/bell_mf_tx_tests.c b/libs/spandsp/tests/bell_mf_tx_tests.c deleted file mode 100644 index 6c88f985ff..0000000000 --- a/libs/spandsp/tests/bell_mf_tx_tests.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bell_mf_tx_tests.c - Test the Bell MF generator. - * - * 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 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 bell_mf_tx_tests_page Bell MF generation tests -\section bell_mf_tx_tests_page_sec_1 What does it do? -???. - -\section bell_mf_tx_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "bell_mf.wav" - -int main(int argc, char *argv[]) -{ - bell_mf_tx_state_t *gen; - int16_t amp[16384]; - int len; - SNDFILE *outhandle; - int add_digits; - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - gen = bell_mf_tx_init(NULL); - len = bell_mf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "123", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "456", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "789", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "*#", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - add_digits = 1; - do - { - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - if (add_digits) - { - if (bell_mf_tx_put(gen, "1234567890", -1)) - { - printf("Digit buffer full\n"); - add_digits = 0; - } - } - } - while (len > 0); - - bell_mf_tx_init(gen); - len = bell_mf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "123", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "456", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "789", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "0*#", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (bell_mf_tx_put(gen, "ABC", -1)) - printf("Ooops\n"); - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - add_digits = 1; - do - { - len = bell_mf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - if (add_digits) - { - if (bell_mf_tx_put(gen, "1234567890", -1)) - { - printf("Digit buffer full\n"); - add_digits = 0; - } - } - } - while (len > 0); - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit (2); - } - bell_mf_tx_free(gen); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/bert_tests.c b/libs/spandsp/tests/bert_tests.c deleted file mode 100644 index 214815d6f2..0000000000 --- a/libs/spandsp/tests/bert_tests.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bert_tests.c - Tests for the BER tester. - * - * 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 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 bert_tests_page BERT tests -\section bert_tests_page_sec_1 What does it do? -These tests exercise each of the BERT standards supported by the BERT module. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -/* Use a local random generator, so the results are consistent across platforms */ -static int my_rand(void) -{ - static int rndnum = 1234567; - - return (rndnum = 1664525U*rndnum + 1013904223U); -} -/*- End of function --------------------------------------------------------*/ - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - int channel; - - channel = (int) (intptr_t) user_data; - printf("%d: BERT report '%s' ", channel, bert_event_to_str(reason)); - switch (reason) - { - case BERT_REPORT_REGULAR: - printf("%d bits, %d bad bits, %d resyncs", results->total_bits, results->bad_bits, results->resyncs); - break; - } - printf("\r"); -} -/*- End of function --------------------------------------------------------*/ - -int8_t test[0x800000]; - -int main(int argc, char *argv[]) -{ - bert_state_t *tx_bert; - bert_state_t *rx_bert; - bert_state_t *bert; - bert_results_t bert_results; - int i; - int bit; - int zeros; - int max_zeros; - int failed; - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ZEROS, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ZEROS, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("Zeros: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ONES, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ONES, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("Ones: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_7, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_7, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("1 to 7: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_3, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_3, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("1 to 3: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_1, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_1, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("1 to 1: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_3_TO_1, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_3_TO_1, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("3 to 1: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_7_TO_1, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_7_TO_1, 300, 20); - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("7 to 1: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 950) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O153_9, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O153_9, 300, 20); - for (i = 0; i < 0x200; i++) - test[i] = 0; - max_zeros = 0; - zeros = 0; - for (i = 0; i < 511*2; i++) - { - bit = bert_get_bit(tx_bert); - if (bit) - { - if (zeros > max_zeros) - max_zeros = zeros; - zeros = 0; - } - else - { - zeros++; - } - bert_put_bit(rx_bert, bit); - test[tx_bert->tx.reg]++; - } - failed = false; - if (test[0] != 0) - { - printf("XXX %d %d\n", 0, test[0]); - failed = true; - } - for (i = 1; i < 0x200; i++) - { - if (test[i] != 2) - { - printf("XXX %d %d\n", i, test[i]); - failed = true; - } - } - bert_result(rx_bert, &bert_results); - printf("O.153(9): Bad bits %d/%d, max zeros %d\n", bert_results.bad_bits, bert_results.total_bits, max_zeros); - if (bert_results.bad_bits || bert_results.total_bits != 986 || failed) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O152_11, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O152_11, 300, 20); - for (i = 0; i < 0x800; i++) - test[i] = 0; - max_zeros = 0; - zeros = 0; - for (i = 0; i < 2047*2; i++) - { - bit = bert_get_bit(tx_bert); - if (bit) - { - if (zeros > max_zeros) - max_zeros = zeros; - zeros = 0; - } - else - { - zeros++; - } - bert_put_bit(rx_bert, bit); - test[tx_bert->tx.reg]++; - } - failed = false; - if (test[0] != 0) - { - printf("XXX %d %d\n", 0, test[0]); - failed = true; - } - for (i = 1; i < 0x800; i++) - { - if (test[i] != 2) - { - printf("XXX %d %d\n", i, test[i]); - failed = true; - } - } - bert_result(rx_bert, &bert_results); - printf("O.152(11): Bad bits %d/%d, max zeros %d\n", bert_results.bad_bits, bert_results.total_bits, max_zeros); - if (bert_results.bad_bits || bert_results.total_bits != 4052 || failed) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_15, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_15, 300, 20); - for (i = 0; i < 0x8000; i++) - test[i] = 0; - max_zeros = 0; - zeros = 0; - for (i = 0; i < 32767*2; i++) - { - bit = bert_get_bit(tx_bert); - if (bit) - { - if (zeros > max_zeros) - max_zeros = zeros; - zeros = 0; - } - else - { - zeros++; - } - bert_put_bit(rx_bert, bit); - test[tx_bert->tx.reg]++; - } - failed = false; - if (test[0] != 0) - { - printf("XXX %d %d\n", 0, test[0]); - failed = true; - } - for (i = 1; i < 0x8000; i++) - { - if (test[i] != 2) - { - printf("XXX %d %d\n", i, test[i]); - failed = true; - } - } - bert_result(rx_bert, &bert_results); - printf("O.151(15): Bad bits %d/%d, max zeros %d\n", bert_results.bad_bits, bert_results.total_bits, max_zeros); - if (bert_results.bad_bits || bert_results.total_bits != 65480 || failed) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_20, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_20, 300, 20); - for (i = 0; i < 0x100000; i++) - test[i] = 0; - max_zeros = 0; - zeros = 0; - for (i = 0; i < 1048575*2; i++) - { - bit = bert_get_bit(tx_bert); - if (bit) - { - if (zeros > max_zeros) - max_zeros = zeros; - zeros = 0; - } - else - { - zeros++; - } - bert_put_bit(rx_bert, bit); - test[tx_bert->tx.reg]++; - } - failed = false; - if (test[0] != 0) - { - printf("XXX %d %d\n", 0, test[0]); - failed = true; - } - for (i = 1; i < 0x100000; i++) - { - if (test[i] != 2) - printf("XXX %d %d\n", i, test[i]); - } - bert_result(rx_bert, &bert_results); - printf("O.151(20): Bad bits %d/%d, max zeros %d\n", bert_results.bad_bits, bert_results.total_bits, max_zeros); - if (bert_results.bad_bits || bert_results.total_bits != 2097066 || failed) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_23, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_23, 300, 20); - for (i = 0; i < 0x800000; i++) - test[i] = 0; - max_zeros = 0; - zeros = 0; - for (i = 0; i < 8388607*2; i++) - { - bit = bert_get_bit(tx_bert); - if (bit) - { - if (zeros > max_zeros) - max_zeros = zeros; - zeros = 0; - } - else - { - zeros++; - } - bert_put_bit(rx_bert, bit); - test[tx_bert->tx.reg]++; - } - failed = false; - if (test[0] != 0) - { - printf("XXX %d %d\n", 0, test[0]); - failed = true; - } - for (i = 1; i < 0x800000; i++) - { - if (test[i] != 2) - printf("XXX %d %d\n", i, test[i]); - } - bert_result(rx_bert, &bert_results); - printf("O.151(23): Bad bits %d/%d, max zeros %d\n", bert_results.bad_bits, bert_results.total_bits, max_zeros); - if (bert_results.bad_bits || bert_results.total_bits != 16777136 || failed) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - tx_bert = bert_init(NULL, 0, BERT_PATTERN_QBF, 300, 20); - rx_bert = bert_init(NULL, 0, BERT_PATTERN_QBF, 300, 20); - for (i = 0; i < 100000; i++) - { - bit = bert_get_bit(tx_bert); - bert_put_bit(rx_bert, bit); - } - bert_result(rx_bert, &bert_results); - printf("QBF: Bad bits %d/%d\n", bert_results.bad_bits, bert_results.total_bits); - if (bert_results.bad_bits || bert_results.total_bits != 100000) - { - printf("Test failed.\n"); - exit(2); - } - bert_free(tx_bert); - bert_free(rx_bert); - - /* Test the mechanism for categorising the error rate into <10^x bands */ - /* TODO: The result of this test is not checked automatically */ - bert = bert_init(NULL, 15000000, BERT_PATTERN_ITU_O152_11, 300, 20); - bert_set_report(bert, 100000, reporter, (intptr_t) 0); - for (;;) - { - if ((bit = bert_get_bit(bert)) == SIG_STATUS_END_OF_DATA) - { - bert_result(bert, &bert_results); - printf("Rate test: %d bits, %d bad bits, %d resyncs\n", bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - if (bert_results.total_bits != 15000000 - 42 - || - bert_results.bad_bits != 58 - || - bert_results.resyncs != 0) - { - printf("Tests failed\n"); - exit(2); - } - break; - //bert = bert_init(NULL, 15000000, BERT_PATTERN_ITU_O152_11, 300, 20); - //bert_set_report(bert, 100000, reporter, (intptr_t) 0); - //continue; - } - if ((my_rand() & 0x3FFFF) == 0) - bit ^= 1; - //if ((my_rand() & 0xFFF) == 0) - // bert_put_bit(bert, bit); - bert_put_bit(bert, bit); - } - bert_free(bert); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/bit_operations_tests.c b/libs/spandsp/tests/bit_operations_tests.c deleted file mode 100644 index bb11c8d857..0000000000 --- a/libs/spandsp/tests/bit_operations_tests.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bit_operations_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -/*! \page bit_operations_tests_page Bit operations tests -\section bit_operations_tests_page_sec_1 What does it do? -These tests check the operation of efficient bit manipulation routines, by comparing -their operation with very dumb brute force versions of the same functionality. - -\section bit_operations_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "spandsp.h" - -uint8_t from[1000000]; -uint8_t to[1000000]; - -static __inline__ int top_bit_dumb(unsigned int data) -{ - int i; - - if (data == 0) - return -1; - for (i = 31; i >= 0; i--) - { - if ((data & (1 << i))) - return i; - } - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int bottom_bit_dumb(unsigned int data) -{ - int i; - - if (data == 0) - return -1; - for (i = 0; i < 32; i++) - { - if ((data & (1 << i))) - return i; - } - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint8_t bit_reverse8_dumb(uint8_t data) -{ - int i; - int result; - - result = 0; - for (i = 0; i < 8; i++) - { - result = (result << 1) | (data & 1); - data >>= 1; - } - return result; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint32_t bit_reverse_4bytes_dumb(uint32_t data) -{ - int i; - uint32_t result; - - result = 0; - for (i = 0; i < 8; i++) - { - result = (result << 1) | (data & 0x01010101); - data >>= 1; - } - return result; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint16_t bit_reverse16_dumb(uint16_t data) -{ - int i; - uint16_t result; - - result = 0; - for (i = 0; i < 16; i++) - { - result = (result << 1) | (data & 1); - data >>= 1; - } - return result; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ uint32_t bit_reverse32_dumb(uint32_t data) -{ - int i; - uint32_t result; - - result = 0; - for (i = 0; i < 32; i++) - { - result = (result << 1) | (data & 1); - data >>= 1; - } - return result; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int parity8_dumb(uint8_t x) -{ - uint8_t y; - int i; - - for (y = 0, i = 0; i < 8; i++) - { - y ^= (x & 1); - x >>= 1; - } - return y; -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ int one_bits32_dumb(uint32_t x) -{ - int i; - int bits; - - bits = 0; - for (i = 0; i < 32; i++) - { - if (x & 1) - bits++; - x >>= 1; - } - return bits; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int i; - uint32_t x; - uint8_t ax; - uint8_t bx; - uint16_t ax16; - uint16_t bx16; - uint32_t ax32; - uint32_t bx32; - - for (i = 0, x = 0; i < 100000; i++) - { - ax = top_bit_dumb(x); - bx = top_bit(x); - if (ax != bx) - { - printf("Test failed: top bit mismatch 0x%" PRIx32 " -> %u %u\n", x, ax, bx); - exit(2); - } - ax = bottom_bit_dumb(x); - bx = bottom_bit(x); - if (ax != bx) - { - printf("Test failed: bottom bit mismatch 0x%" PRIx32 " -> %u %u\n", x, ax, bx); - exit(2); - } - x = rand(); - } - for (i = 0; i < 256; i++) - { - ax = bit_reverse8_dumb(i); - bx = bit_reverse8(i); - if (ax != bx) - { - printf("Test failed: bit reverse 8 - %02x %02x %02x\n", i, ax, bx); - exit(2); - } - } - for (i = 0; i < 1000000; i++) - from[i] = rand(); - bit_reverse(to, from, 1000000); - for (i = 0; i < 1000000; i++) - { - if (bit_reverse8_dumb(from[i]) != to[i]) - { - printf("Test failed: bit reverse - at %d, %02x %02x %02x\n", i, from[i], bit_reverse8(from[i]), to[i]); - exit(2); - } - } - for (i = 0; i < 256; i++) - { - x = i | (((i + 1) & 0xFF) << 8) | (((i + 2) & 0xFF) << 16) | (((i + 3) & 0xFF) << 24); - ax32 = bit_reverse_4bytes_dumb(x); - bx32 = bit_reverse_4bytes(x); - if (ax32 != bx32) - { - printf("Test failed: bit reverse 4 bytes - %" PRIx32 " %" PRIx32 " %" PRIx32 "\n", x, ax32, bx32); - exit(2); - } - } - for (i = 0; i < 65536; i++) - { - ax16 = bit_reverse16_dumb(i); - bx16 = bit_reverse16(i); - if (ax16 != bx16) - { - printf("Test failed: bit reverse 16 - %x %x %x\n", i, ax16, bx16); - exit(2); - } - } - for (i = 0; i < 0x7FFFFF00; i += 127) - { - ax32 = bit_reverse32_dumb(i); - bx32 = bit_reverse32(i); - if (ax32 != bx32) - { - printf("Test failed: bit reverse 32 - %d %" PRIx32 " %" PRIx32 "\n", i, ax32, bx32); - exit(2); - } - } - - for (i = 0; i < 256; i++) - { - ax = parity8(i); - bx = parity8_dumb(i); - if (ax != bx) - { - printf("Test failed: parity 8 - %x %x %x\n", i, ax, bx); - exit(2); - } - } - - for (i = -1; i < 32; i++) - { - ax32 = most_significant_one32(1 << i); - if (ax32 != (1 << i)) - { - printf("Test failed: most significant one 32 - %x %" PRIx32 " %x\n", i, ax32, (1 << i)); - exit(2); - } - ax32 = least_significant_one32(1 << i); - if (ax32 != (1 << i)) - { - printf("Test failed: least significant one 32 - %x %" PRIx32 " %x\n", i, ax32, (1 << i)); - exit(2); - } - } - - for (i = 0x80000000; i < 0x800FFFFF; i++) - { - ax = one_bits32_dumb(i); - bx = one_bits32(i); - if (ax != bx) - { - printf("Test failed: one bits - %d, %x %x\n", i, ax, bx); - exit(2); - } - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/bitstream_tests.c b/libs/spandsp/tests/bitstream_tests.c deleted file mode 100644 index 3e7b441a55..0000000000 --- a/libs/spandsp/tests/bitstream_tests.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bitstream_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -/*! \page bitstream_tests_page Bitstream tests -\section bitstream_tests_page_sec_1 What does it do? - -\section bitstream_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -uint8_t buffer[256]; - -#define PATTERN 0x1111111 -#define SEQUENCE_LENGTH 17 - -uint8_t left[] = -{ - 0x28, /* 2 of 4, 3, 2, 1 */ - 0xC8, /* 1 of 6, 5, 2 of 4 */ - 0xAE, /* 3 of 7, 5 of 6 */ - 0x67, /* 4 of 8, 4 of 7 */ - 0x74, /* 4 of 9, 4 of 8 */ - 0x43, /* 3 of 10, 5 of 9 */ - 0x32, /* 1 of 11, 7 of 10 */ - 0xAA, /* 8 of 11 */ - 0xAE, /* 6 of 12, 2 of 11 */ - 0xED, /* 2 of 13, 6 of 12 */ - 0x99, /* 8 of 13 */ - 0x8E, /* 5 of 14, 3 of 13 */ - 0xEE, /* 8 of 14 */ - 0xEE, /* 7 of 15, 1 of 14 */ - 0xEE, /* 8 of 15 */ - 0xFF, /* 8 of 16 */ - 0xFF, /* 8 of 16 */ - 0x88, /* 8 of 17 */ - 0x88, /* 8 of 17 */ - 0x00 /* 1 of 17 */ -}; -uint8_t right[] = -{ - 0xD2, /* 1, 2, 3, 2 of 4 */ - 0x90, /* 2 of 4, 5, 1 of 6 */ - 0xCA, /* 5 of 6, 3 of 7 */ - 0x7C, /* 4 of 7, 4 of 8 */ - 0x87, /* 4 of 8, 4 of 9 */ - 0x28, /* 5 of 9, 3 of 10 */ - 0x33, /* 7 of 10, 1 of 11 */ - 0x55, /* 8 of 11 */ - 0xED, /* 2 of 11, 6 of 12 */ - 0x2E, /* 6 of 12, 2 of 13 */ - 0x33, /* 8 of 13 */ - 0xEB, /* 3 of 13, 5 of 14 */ - 0xEE, /* 8 of 14 */ - 0xDC, /* 1 of 14, 7 of 15 */ - 0xDD, /* 8 of 15 */ - 0xFF, /* 8 of 16 */ - 0xFF, /* 8 of 16 */ - 0x10, /* 8 of 17 */ - 0x11, /* 8 of 17 */ - 0x01 /* 1 of 17 */ -}; - -int main(int argc, char *argv[]) -{ - int i; - bitstream_state_t state; - bitstream_state_t *s; - const uint8_t *r; - uint8_t *w; - uint8_t *cc; - unsigned int x; - int total_bits; - - s = bitstream_init(&state, true); - w = buffer; - total_bits = 0; - for (i = 0; i < SEQUENCE_LENGTH; i++) - { - bitstream_put(s, &w, i*PATTERN, i + 1); - total_bits += (i + 1); - } - bitstream_flush(s, &w); - printf("%d bits written\n", total_bits); - - for (cc = buffer; cc < w; cc++) - printf("%02X ", *cc); - printf("\n"); - for (cc = right; cc < right + sizeof(right); cc++) - printf("%02X ", *cc); - printf("\n"); - - if ((w - buffer) != sizeof(right) || memcmp(buffer, right, sizeof(right))) - { - printf("Test failed\n"); - exit(2); - } - - s = bitstream_init(&state, true); - r = buffer; - for (i = 0; i < SEQUENCE_LENGTH; i++) - { - x = bitstream_get(s, &r, i + 1); - if (x != ((PATTERN*i) & ((1 << (i + 1)) - 1))) - { - printf("Error 0x%X 0x%X\n", x, ((PATTERN*i) & ((1 << (i + 1)) - 1))); - printf("Test failed\n"); - exit(2); - } - } - - s = bitstream_init(&state, false); - w = buffer; - total_bits = 0; - for (i = 0; i < SEQUENCE_LENGTH; i++) - { - bitstream_put(s, &w, PATTERN*i, i + 1); - total_bits += (i + 1); - } - bitstream_flush(s, &w); - printf("%d bits written\n", total_bits); - - for (cc = buffer; cc < w; cc++) - printf("%02X ", *cc); - printf("\n"); - for (cc = left; cc < left + sizeof(left); cc++) - printf("%02X ", *cc); - printf("\n"); - - if ((w - buffer) != sizeof(left) || memcmp(buffer, left, sizeof(left))) - { - printf("Test failed\n"); - exit(2); - } - - s = bitstream_init(&state, false); - r = buffer; - for (i = 0; i < SEQUENCE_LENGTH; i++) - { - x = bitstream_get(s, &r, i + 1); - if (x != ((PATTERN*i) & ((1 << (i + 1)) - 1))) - { - printf("Error 0x%X 0x%X\n", x, ((PATTERN*i) & ((1 << (i + 1)) - 1))); - printf("Test failed\n"); - exit(2); - } - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/complex_tests.c b/libs/spandsp/tests/complex_tests.c deleted file mode 100644 index 54649f5b4b..0000000000 --- a/libs/spandsp/tests/complex_tests.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex.c - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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. - */ - -/*! \page complex_tests_page Complex arithmetic tests -\section complex_tests_page_sec_1 What does it do? - -\section complex_tests_page_sec_2 How is it used? -*/ - -#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 -#include "floating_fudge.h" -#include - -#include "spandsp.h" - -int main(int argc, char *argv[]) -{ - complexf_t fa; - complexf_t fb; - complexf_t fz; - complexi16_t i16a; - complexi16_t i16b; - complexi16_t i16z; -#if 0 - complexi32_t i32a; - complexi32_t i32b; - complexi32_t i32z; -#endif - - fa = complex_setf(0.5f, 0.25f); - fb = complex_setf(0.25f, 0.5f); - fz = complex_mulf(&fa, &fb); - printf("(%f, %f) * (%f, %f) => (%f, %f)\n", fa.re, fa.im, fb.re, fb.im, fz.re, fz.im); - - i16a = complex_seti16(16383, 8191); - i16b = complex_seti16(8191, 16383); - i16z = complex_mul_q1_15(&i16a, &i16b); - printf("(%f, %f) * (%f, %f) => (%f, %f)\n", i16a.re/32768.0, i16a.im/32768.0, i16b.re/32768.0, i16b.im/32768.0, i16z.re/32768.0, i16z.im/32768.0); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/complex_vector_float_tests.c b/libs/spandsp/tests/complex_vector_float_tests.c deleted file mode 100644 index e32ac07591..0000000000 --- a/libs/spandsp/tests/complex_vector_float_tests.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_float_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006,2008 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" - -static void cvec_mulf_dumb(complexf_t z[], const complexf_t x[], const complexf_t y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - { - z[i].re = x[i].re*y[i].re - x[i].im*y[i].im; - z[i].im = x[i].re*y[i].im + x[i].im*y[i].re; - } -} -/*- End of function --------------------------------------------------------*/ - -static int test_cvec_mulf(void) -{ - int i; - complexf_t x[100]; - complexf_t y[100]; - complexf_t za[100]; - complexf_t zb[100]; - complexf_t ratio; - - for (i = 0; i < 99; i++) - { - x[i].re = rand(); - x[i].im = rand(); - y[i].re = rand(); - y[i].im = rand(); - } - cvec_mulf(za, x, y, 99); - cvec_mulf_dumb(zb, x, y, 99); - for (i = 0; i < 99; i++) - printf("(%f,%f) (%f,%f) (%f,%f)\n", za[i].re, za[i].im, x[i].re, x[i].im, y[i].re, y[i].im); - for (i = 0; i < 99; i++) - { - ratio.re = za[i].re/zb[i].re; - ratio.im = za[i].im/zb[i].im; - if ((ratio.re < 0.9999 || ratio.re > 1.0001) - || - (ratio.im < 0.9999 || ratio.im > 1.0001)) - { - printf("cvec_mulf() - (%f,%f) (%f,%f)\n", za[i].re, za[i].im, zb[i].re, zb[i].im); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static complexf_t cvec_dot_prodf_dumb(const complexf_t x[], const complexf_t y[], int n) -{ - int i; - complexf_t z; - complexf_t z1; - - z = complex_setf(0.0f, 0.0f); - for (i = 0; i < n; i++) - { - z1 = complex_mulf(&x[i], &y[i]); - z = complex_addf(&z, &z1); - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -static int test_cvec_dot_prodf(void) -{ - int i; - complexf_t x[100]; - complexf_t y[100]; - complexf_t zsa; - complexf_t zsb; - complexf_t ratio; - - for (i = 0; i < 99; i++) - { - x[i].re = rand(); - x[i].im = rand(); - y[i].re = rand(); - y[i].im = rand(); - } - for (i = 1; i < 99; i++) - { - zsa = cvec_dot_prodf(x, y, i); - zsb = cvec_dot_prodf_dumb(x, y, i); - ratio.re = zsa.re/zsb.re; - ratio.im = zsa.im/zsb.im; - if ((ratio.re < 0.9999 || ratio.re > 1.0001) - || - (ratio.im < 0.9999 || ratio.im > 1.0001)) - { - printf("cvec_dot_prodf() - (%f,%f) (%f,%f)\n", zsa.re, zsa.im, zsb.re, zsb.im); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - test_cvec_mulf(); - test_cvec_dot_prodf(); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/complex_vector_int_tests.c b/libs/spandsp/tests/complex_vector_int_tests.c deleted file mode 100644 index 57fa7a6a58..0000000000 --- a/libs/spandsp/tests/complex_vector_int_tests.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_int_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" - -static complexi32_t cvec_dot_prodi16_dumb(const complexi16_t x[], const complexi16_t y[], int n) -{ - complexi32_t z; - int i; - - z = complex_seti32(0, 0); - for (i = 0; i < n; i++) - { - z.re += ((int32_t) x[i].re*(int32_t) y[i].re - (int32_t) x[i].im*(int32_t) y[i].im); - z.im += ((int32_t) x[i].re*(int32_t) y[i].im + (int32_t) x[i].im*(int32_t) y[i].re); - } - return z; -} -/*- End of function --------------------------------------------------------*/ - -static int test_cvec_dot_prodi16(void) -{ - int i; - complexi32_t za; - complexi32_t zb; - complexi16_t x[99]; - complexi16_t y[99]; - - for (i = 0; i < 99; i++) - { - x[i].re = rand(); - x[i].im = rand(); - y[i].re = rand(); - y[i].im = rand(); - } - - for (i = 1; i < 99; i++) - { - za = cvec_dot_prodi16(x, y, i); - zb = cvec_dot_prodi16_dumb(x, y, i); - if (za.re != zb.re || za.im != zb.im) - { - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int test_cvec_circular_dot_prodi16(void) -{ - int i; - int j; - int pos; - int len; - complexi32_t za; - complexi32_t zb; - complexi16_t x[99]; - complexi16_t y[99]; - - /* Verify that we can do circular sample buffer "dot" linear coefficient buffer - operations properly, by doing two sub-dot products. */ - for (i = 0; i < 99; i++) - { - x[i].re = rand(); - x[i].im = rand(); - y[i].re = rand(); - y[i].im = rand(); - } - - len = 95; - for (pos = 0; pos < len; pos++) - { - za = cvec_circular_dot_prodi16(x, y, len, pos); - zb = complex_seti32(0, 0); - for (i = 0; i < len; i++) - { - j = (pos + i) % len; - zb.re += ((int32_t) x[j].re*(int32_t) y[i].re - (int32_t) x[j].im*(int32_t) y[i].im); - zb.im += ((int32_t) x[j].re*(int32_t) y[i].im + (int32_t) x[j].im*(int32_t) y[i].re); - } - - if (za.re != zb.re || za.im != zb.im) - { - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - test_cvec_dot_prodi16(); - test_cvec_circular_dot_prodi16(); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/crc_tests.c b/libs/spandsp/tests/crc_tests.c deleted file mode 100644 index 3cb9221055..0000000000 --- a/libs/spandsp/tests/crc_tests.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * crc_tests.c - * - * 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 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 crc_tests_page CRC tests -\section crc_tests_page_sec_1 What does it do? -The CRC tests exercise the ITU-16 and ITU-32 CRC module, and verifies -correct operation. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#include "spandsp.h" - -int ref_len; -uint8_t buf[1000]; - -/* Use a local random generator, so the results are consistent across platforms. We have hard coded - correct results for a message sequence generated by this particular PRNG. */ -static int my_rand(void) -{ - static int rndnum = 1234567; - - return (rndnum = 1664525U*rndnum + 1013904223U) >> 8; -} -/*- End of function --------------------------------------------------------*/ - -static int cook_up_msg(uint8_t *buf) -{ - int i; - int len; - - /* Use medium length messages, with some randomised length variation. */ - /* TODO: this doesn't exercise extremely short or long messages. */ - len = (my_rand() & 0x3F) + 100; - for (i = 0; i < len; i++) - buf[i] = my_rand(); - return len; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int i; - int j; - int len; - uint16_t crc16a; - uint16_t crc16b; - - printf("CRC module tests\n"); - - /* TODO: This doesn't check every function in the module */ - - /* Try a few random messages through the CRC logic. */ - printf("Testing the CRC-16 routines\n"); - for (i = 0; i < 100; i++) - { - ref_len = cook_up_msg(buf); - len = crc_itu16_append(buf, ref_len); - if (!crc_itu16_check(buf, len)) - { - printf("CRC-16 failure\n"); - exit(2); - } - } - printf("Test passed.\n\n"); - - printf("Testing the CRC-16 byte by byte and bit by bit routines\n"); - for (i = 0; i < 100; i++) - { - ref_len = cook_up_msg(buf); - crc16a = 0xFFFF; - crc16a = crc_itu16_calc(buf, ref_len, crc16a); - - crc16b = 0xFFFF; - for (j = 0; j < ref_len; j++) - crc16b = crc_itu16_bits(buf[j], 8, crc16b); - if (crc16a != crc16b) - { - printf("CRC-16 failure\n"); - exit(2); - } - } - printf("Test passed.\n\n"); - - printf("Testing the CRC-32 routines\n"); - for (i = 0; i < 100; i++) - { - ref_len = cook_up_msg(buf); - len = crc_itu32_append(buf, ref_len); - if (!crc_itu32_check(buf, len)) - { - printf("CRC-32 failure\n"); - exit(2); - } - } - printf("Test passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/data_modems_tests.c b/libs/spandsp/tests/data_modems_tests.c deleted file mode 100644 index e156f2d3e5..0000000000 --- a/libs/spandsp/tests/data_modems_tests.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * data_modems_tests.c - Tests for data_modems. - * - * 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 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 data_modems_tests_page Data modems tests -\section data_modems_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif - -#define INPUT_FILE_NAME "../test-data/itu/fax/itu1.tif" -#define OUTPUT_FILE_NAME "t31.tif" -#define OUTPUT_WAVE_FILE_NAME "data_modems.wav" - -#define SAMPLES_PER_CHUNK 160 - -struct command_response_s -{ - const char *command; - int len_command; - const char *response; - int len_response; -}; - -char *decode_test_file = NULL; -int countdown = 0; -int command_response_test_step = -1; -char response_buf[1000]; -int response_buf_ptr = 0; -bool answered = false; -bool done = false; -bool sequence_terminated = false; - -data_modems_state_t *data_modems_state[2]; - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - int channel; - - channel = (int) (intptr_t) user_data; - switch (reason) - { - case BERT_REPORT_SYNCED: - fprintf(stderr, "%d: BERT report synced\n", channel); - break; - case BERT_REPORT_UNSYNCED: - fprintf(stderr, "%d: BERT report unsync'ed\n", channel); - break; - case BERT_REPORT_REGULAR: - fprintf(stderr, "%d: BERT report regular - %d bits, %d bad bits, %d resyncs\n", channel, results->total_bits, results->bad_bits, results->resyncs); - break; - case BERT_REPORT_GT_10_2: - fprintf(stderr, "%d: BERT report > 1 in 10^2\n", channel); - break; - case BERT_REPORT_LT_10_2: - fprintf(stderr, "%d: BERT report < 1 in 10^2\n", channel); - break; - case BERT_REPORT_LT_10_3: - fprintf(stderr, "%d: BERT report < 1 in 10^3\n", channel); - break; - case BERT_REPORT_LT_10_4: - fprintf(stderr, "%d: BERT report < 1 in 10^4\n", channel); - break; - case BERT_REPORT_LT_10_5: - fprintf(stderr, "%d: BERT report < 1 in 10^5\n", channel); - break; - case BERT_REPORT_LT_10_6: - fprintf(stderr, "%d: BERT report < 1 in 10^6\n", channel); - break; - case BERT_REPORT_LT_10_7: - fprintf(stderr, "%d: BERT report < 1 in 10^7\n", channel); - break; - default: - fprintf(stderr, "%d: BERT report reason %d\n", channel, reason); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int get_msg(void *user_data, uint8_t msg[], int len) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void put_msg(void *user_data, const uint8_t msg[], int len) -{ - if (len < 0) - printf("Status %s\n", signal_status_to_str(len)); -} -/*- End of function --------------------------------------------------------*/ - -static int modem_tests(int use_gui, int log_audio, int test_sending) -{ - int mdm_len; - int16_t mdm_amp[SAMPLES_PER_CHUNK]; - //int use_tep; - //logging_state_t *logging; - int outframes; - int16_t silence[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - SNDFILE *wave_handle; - SNDFILE *in_handle; - int i; - int k; - int calling_party; - logging_state_t *logging; - bert_state_t *bert[2]; - - /* Test a pair of modems against each other */ - - /* Set up the test environment */ - //use_tep = false; - - wave_handle = NULL; - if (log_audio) - { - if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - in_handle = NULL; - if (decode_test_file) - { - if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", decode_test_file); - exit(2); - } - } - - memset(silence, 0, sizeof(silence)); - memset(mdm_amp, 0, sizeof(mdm_amp)); - mdm_len = 0; - - /* Now set up and run the modems */ - calling_party = true; - for (i = 0; i < 2; i++) - { - bert[i] = bert_init(NULL, 1000000, BERT_PATTERN_ITU_O152_11, 2400, 20); - bert_set_report(bert[i], 100000, reporter, (void *) (intptr_t) i); - if ((data_modems_state[i] = data_modems_init(NULL, - calling_party, - NULL, - NULL, - NULL, - NULL, - put_msg, - get_msg, - NULL)) == NULL) - { - fprintf(stderr, " Cannot start the data modem\n"); - exit(2); - } - logging = data_modems_get_logging_state(data_modems_state[i]); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "Modem"); - calling_party = false; - } - -#if defined(ENABLE_GUI) - if (use_gui) - start_media_monitor(); -#endif - while (!done) - { - for (i = 0; i < 2; i++) - { - /* The receive side always expects a full block of samples, but the - transmit side may not be sending any when it doesn't need to. We - may need to pad with some silence. */ - mdm_len = data_modems_tx(data_modems_state[i], mdm_amp, SAMPLES_PER_CHUNK); - if (mdm_len < SAMPLES_PER_CHUNK) - { - vec_zeroi16(mdm_amp + mdm_len, SAMPLES_PER_CHUNK - mdm_len); - mdm_len = SAMPLES_PER_CHUNK; - } - if (log_audio) - { - for (k = 0; k < mdm_len; k++) - out_amp[2*k + i] = mdm_amp[k]; - } - if (data_modems_rx(data_modems_state[i ^ 1], mdm_amp, mdm_len)) - break; - } - - if (log_audio) - { - outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - break; - } - } - - if (decode_test_file) - { - if (sf_close_telephony(in_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - if (!done || !sequence_terminated) - { - printf("Tests failed\n"); - return 2; - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int log_audio; - int test_sending; - int use_gui; - int opt; - - decode_test_file = NULL; - log_audio = false; - test_sending = false; - use_gui = false; - while ((opt = getopt(argc, argv, "d:glrs")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - case 'r': - test_sending = false; - break; - case 's': - test_sending = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - modem_tests(use_gui, log_audio, test_sending); - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/dc_restore_tests.c b/libs/spandsp/tests/dc_restore_tests.c deleted file mode 100644 index 0150aa02ad..0000000000 --- a/libs/spandsp/tests/dc_restore_tests.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dc_restore_tests.c - Tests for the dc_restore functions. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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. - */ - -/*! \page dc_restore_tests_page DC restoration tests -\section dc_restore_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" - -int main (int argc, char *argv[]) -{ - awgn_state_t *noise_source; - dc_restore_state_t dc_state; - int i; - int idum = 1234567; - int16_t dirty; - int estimate; - int min; - int max; - int dc_offset; - - dc_offset = 5000; - noise_source = awgn_init_dbm0(NULL, idum, -10.0); - dc_restore_init(&dc_state); - for (i = 0; i < 100000; i++) - { - dirty = awgn(noise_source) + dc_offset; - dc_restore(&dc_state, dirty); - if ((i % 1000) == 0) - { - printf("Sample %6d: %d (expect %d)\n", - i, - dc_restore_estimate(&dc_state), - dc_offset); - } - } - /* We should have settled by now. Look at the variation we get */ - min = 99999; - max = -99999; - for (i = 0; i < 100000; i++) - { - dirty = awgn(noise_source) + dc_offset; - dc_restore(&dc_state, dirty); - estimate = dc_restore_estimate(&dc_state); - if (estimate < min) - min = estimate; - if (estimate > max) - max = estimate; - } - printf("Spread of DC estimate for an offset of %d was %d to %d\n", dc_offset, min, max); - if (min < dc_offset - 50 || max > dc_offset + 50) - { - printf("Test failed.\n"); - exit(2); - } - awgn_free(noise_source); - printf("Test passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/dds_tests.c b/libs/spandsp/tests/dds_tests.c deleted file mode 100644 index 27095b6108..0000000000 --- a/libs/spandsp/tests/dds_tests.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dds_tests.c - * - * 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 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 dds_tests_page Direct digital synthesis tests -\section dds_tests_page_sec_1 What does it do? -???. - -\section dds_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "dds.wav" -#define OUTPUT_FILE_NAME_COMPLEX "complex_dds.wav" - -#define SAMPLES_PER_CHUNK 8000 - -int main(int argc, char *argv[]) -{ - int i; - uint32_t phase; - int32_t phase_inc; - int outframes; - complexf_t camp; - int16_t buf[2*SAMPLES_PER_CHUNK]; - SNDFILE *outhandle; - power_meter_t meter; - power_meter_t meter_i; - power_meter_t meter_q; - int scale; - - power_meter_init(&meter, 10); - - printf("Non-complex DDS tests.\n"); - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - phase = 0; - - printf("Test with 123.456789Hz.\n"); - phase_inc = dds_phase_rate(123.456789f); - scale = dds_scaling_dbm0(-10.0f); - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - { - buf[i] = alaw_to_linear(linear_to_alaw((dds(&phase, phase_inc)*scale) >> 15)); - power_meter_update(&meter, buf[i]); - } - outframes = sf_writef_short(outhandle, buf, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - printf("Level is %fdBOv/%fdBm0\n", power_meter_current_dbov(&meter), power_meter_current_dbm0(&meter)); - if (fabs(power_meter_current_dbm0(&meter) + 10.0f) > 0.1f) - { - printf("Test failed.\n"); - exit(2); - } - - printf("Test with 12.3456789Hz.\n"); - phase_inc = dds_phase_rate(12.3456789f); - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - { - buf[i] = alaw_to_linear(linear_to_alaw(dds(&phase, phase_inc))); - power_meter_update(&meter, buf[i]); - } - outframes = sf_writef_short(outhandle, buf, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - printf("Level is %fdBOv/%fdBm0\n", power_meter_current_dbov(&meter), power_meter_current_dbm0(&meter)); - /* Use a wider tolerance for this very low frequency - the power meter will ripple */ - if (fabs(power_meter_current_dbov(&meter) + 3.02f) > 0.2f) - { - printf("Test failed.\n"); - exit(2); - } - - printf("Test with 2345.6789Hz.\n"); - phase_inc = dds_phase_rate(2345.6789f); - scale = dds_scaling_dbov(-10.0f); - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - { - buf[i] = alaw_to_linear(linear_to_alaw((dds(&phase, phase_inc)*scale) >> 15)); - power_meter_update(&meter, buf[i]); - } - outframes = sf_writef_short(outhandle, buf, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - printf("Level is %fdBOv/%fdBm0\n", power_meter_current_dbov(&meter), power_meter_current_dbm0(&meter)); - if (fabs(power_meter_current_dbov(&meter) + 10.0f) > 0.1f) - { - printf("Test failed.\n"); - exit(2); - } - - printf("Test with 3456.789Hz.\n"); - phase_inc = dds_phase_rate(3456.789f); - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - { - buf[i] = alaw_to_linear(linear_to_alaw(dds(&phase, phase_inc))); - power_meter_update(&meter, buf[i]); - } - outframes = sf_writef_short(outhandle, buf, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - printf("Level is %fdBOv/%fdBm0\n", power_meter_current_dbov(&meter), power_meter_current_dbm0(&meter)); - if (fabs(power_meter_current_dbov(&meter) + 3.02f) > 0.05f) - { - printf("Test failed.\n"); - exit(2); - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - printf("Complex DDS tests,\n"); - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME_COMPLEX, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME_COMPLEX); - exit(2); - } - - power_meter_init(&meter_i, 7); - power_meter_init(&meter_q, 7); - - phase = 0; - phase_inc = dds_phase_ratef(123.456789f); - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - { - camp = dds_complexf(&phase, phase_inc); - buf[2*i] = camp.re*10000.0f; - buf[2*i + 1] = camp.im*10000.0f; - power_meter_update(&meter_i, buf[2*i]); - power_meter_update(&meter_q, buf[2*i]); - } - outframes = sf_writef_short(outhandle, buf, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - printf("Level is %fdBOv/%fdBm0, %fdBOv/%fdBm0\n", - power_meter_current_dbov(&meter_i), - power_meter_current_dbm0(&meter_i), - power_meter_current_dbov(&meter_q), - power_meter_current_dbm0(&meter_q)); - if (fabs(power_meter_current_dbov(&meter_i) + 13.42f) > 0.05f - || - fabs(power_meter_current_dbov(&meter_q) + 13.42f) > 0.05f) - { - printf("Test failed.\n"); - exit(2); - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME_COMPLEX); - exit(2); - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/dtmf_rx_tests.c b/libs/spandsp/tests/dtmf_rx_tests.c deleted file mode 100644 index d0fa87a3b1..0000000000 --- a/libs/spandsp/tests/dtmf_rx_tests.c +++ /dev/null @@ -1,926 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dtmf_rx_tests.c - Test the DTMF detector against the spec., whatever the spec. - * may be :) - * - * Written by Steve Underwood - * - * Copyright (C) 2001, 2006 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. - */ - -/* - * These tests include conversion to and from A-law. I assume the - * distortion this produces is comparable to u-law, so it should be - * a fair test. - * - * These tests mirror those on the CM7291 test tape from Mitel. - * Many of these tests are highly questionable, but they are a - * well accepted industry standard. - * - * However standard these tests might be, Mitel appears to have stopped - * selling copies of their tape. - * - * For the talk-off test the Bellcore tapes may be used. However, they are - * copyright material, so the test data files produced from the Bellcore - * tapes cannot be distributed as a part of this package. - * - */ - -/*! \page dtmf_rx_tests_page DTMF receiver tests -\section dtmf_rx_tests_page_sec_1 What does it do? - -The DTMF detection test suite performs similar tests to the Mitel test tape, -traditionally used for testing DTMF receivers. Mitel seem to have discontinued -this product, but all it not lost. - -The first side of the Mitel tape consists of a number of tone and tone+noise -based tests. The test suite synthesizes equivalent test data. Being digitally -generated, this data is rather more predictable than the test data on the nasty -old stretchy cassette tapes which Mitel sold. - -The second side of the Mitel tape contains fragments of real speech from real -phone calls captured from the North American telephone network. These are -considered troublesome for DTMF detectors. A good detector is expected to -achieve a reasonably low number of false detections on this data. Fresh clean -copies of this seem to be unobtainable. However, Bellcore produce a much more -aggressive set of three cassette tapes. All six side (about 30 minutes each) are -filled with much tougher fragments of real speech from the North American -telephone network. If you can do well in this test, nobody cares about your -results against the Mitel test tape. - -A fresh set of tapes was purchased for these tests, and digitised, producing 6 -wave files of 16 bit signed PCM data, sampled at 8kHz. They were transcribed -using a speed adjustable cassette player. The test tone at the start of the -tapes is pretty accurate, and the new tapes should not have had much opportunity -to stretch. It is believed these transcriptions are about as good as the source -material permits. - -PLEASE NOTE - -These transcriptions may be freely used by anyone who has a legitimate copy of -the original tapes. However, if you don't have a legitimate copy of those tapes, -you also have no right to use this data. The original tapes are the copyright -material of BellCore, and they charge over US$200 for a set. I doubt they sell -enough copies to consider this much of a business. However, it is their data, -and it is their right to do as they wish with it. Currently I see no indication -they wish to give it away for free. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -/* Basic DTMF specs: - * - * Minimum tone on = 40ms - * Minimum tone off = 50ms - * Maximum digit rate = 10 per second - * Normal twist <= 8dB accepted - * Reverse twist <= 4dB accepted - * S/N >= 15dB will detect OK - * Attenuation <= 26dB will detect OK - * Frequency tolerance +- 1.5% will detect, +-3.5% will reject - */ - -#define DEFAULT_DTMF_TX_LEVEL -10 -#define DEFAULT_DTMF_TX_ON_TIME 50 -#define DEFAULT_DTMF_TX_OFF_TIME 50 - -#define SAMPLES_PER_CHUNK 160 - -#define ALL_POSSIBLE_DIGITS "123A456B789C*0#D" - -#define MITEL_DIR "../test-data/mitel/" -#define BELLCORE_DIR "../test-data/bellcore/" - -const char *bellcore_files[] = -{ - MITEL_DIR "mitel-cm7291-talkoff.wav", - BELLCORE_DIR "tr-tsy-00763-1.wav", - BELLCORE_DIR "tr-tsy-00763-2.wav", - BELLCORE_DIR "tr-tsy-00763-3.wav", - BELLCORE_DIR "tr-tsy-00763-4.wav", - BELLCORE_DIR "tr-tsy-00763-5.wav", - BELLCORE_DIR "tr-tsy-00763-6.wav", - "" -}; - -static tone_gen_descriptor_t my_dtmf_digit_tones[16]; - -float dtmf_row[] = -{ - 697.0f, 770.0f, 852.0f, 941.0f -}; -float dtmf_col[] = -{ - 1209.0f, 1336.0f, 1477.0f, 1633.0f -}; - -char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; - -bool callback_hit; -bool callback_ok; -int callback_roll; -int step; - -float max_forward_twist; -float max_reverse_twist; - -bool use_dialtone_filter = false; - -char *decode_test_file = NULL; - -static int16_t amp[1000000]; -static int16_t amp2[1000000]; - -codec_munge_state_t *munge = NULL; - -static void my_dtmf_gen_init(float low_fudge, - int low_level, - float high_fudge, - int high_level, - int duration, - int gap) -{ - int row; - int col; - - for (row = 0; row < 4; row++) - { - for (col = 0; col < 4; col++) - { - tone_gen_descriptor_init(&my_dtmf_digit_tones[row*4 + col], - dtmf_row[row]*(1.0f + low_fudge), - low_level, - dtmf_col[col]*(1.0f + high_fudge), - high_level, - duration, - gap, - 0, - 0, - false); - } - } -} -/*- End of function --------------------------------------------------------*/ - -static int my_dtmf_generate(int16_t amp[], const char *digits) -{ - int len; - char *cp; - tone_gen_state_t tone; - - len = 0; - while (*digits) - { - cp = strchr(dtmf_positions, *digits); - if (cp) - { - tone_gen_init(&tone, &my_dtmf_digit_tones[cp - dtmf_positions]); - len += tone_gen(&tone, amp + len, 1000); - } - digits++; - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void digit_delivery(void *data, const char *digits, int len) -{ - int i; - int seg; - const char *s = ALL_POSSIBLE_DIGITS; - const char *t; - - callback_hit = true; - if (data == (void *) 0x12345678) - { - t = s + callback_roll; - seg = 16 - callback_roll; - for (i = 0; i < len; i += seg, seg = 16) - { - if (i + seg > len) - seg = len - i; - if (memcmp(digits + i, t, seg)) - { - callback_ok = false; - printf("Fail at %d %d\n", i, seg); - break; - } - t = s; - callback_roll = (callback_roll + seg)%16; - } - } - else - { - callback_ok = false; - } -} -/*- End of function --------------------------------------------------------*/ - -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; - - //printf("Digit status %d %d %d\n", signal, level, delay); - callback_hit = true; - len = step - last_step; - if (data == (void *) 0x12345678) - { - if (len < 320 || len > 480) - { - if (first) - { - /* At the beginning the apparent duration is expected to be wrong */ - first = false; - } - else - { - printf("Failed for signal %s length %d at %d\n", (callback_roll & 1) ? "on" : "off", len, step); - callback_ok = false; - } - } - if (callback_roll & 1) - { - if (signal != 0) - { - printf("Failed for signal 0x%X instead of 0\n", signal); - callback_ok = false; - } - } - else - { - 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; - } - 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; - } - } - if (++callback_roll >= 32) - callback_roll = 0; - } - else - { - callback_ok = false; - } - last_step = step; -} -/*- End of function --------------------------------------------------------*/ - -static void mitel_cm7291_side_1_tests(void) -{ - int i; - int j; - int len; - int sample; - const char *s; - char digit[2]; - char buf[128 + 1]; - int actual; - int nplus; - int nminus; - float rrb; - float rcfo; - dtmf_rx_state_t *dtmf_state; - awgn_state_t noise_source; - logging_state_t *logging; - - dtmf_state = dtmf_rx_init(NULL, NULL, NULL); - if (use_dialtone_filter || max_forward_twist >= 0.0f || max_reverse_twist >= 0.0f) - dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f); - logging = dtmf_rx_get_logging_state(dtmf_state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "DTMF-rx"); - - /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step, - which has no meaning here. */ - printf("Test 1: Calibration\n"); - printf(" Passed\n"); - - /* Test 2: Decode check - This is a sanity check, that all digits are reliably detected - under ideal conditions. Each possible digit repeated 10 times, - with 50ms bursts. The level of each tone is about 6dB down from clip. - 6dB down actually causes trouble with G.726, so we use 7dB down. */ - printf("Test 2: Decode check\n"); - my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50); - s = ALL_POSSIBLE_DIGITS; - digit[1] = '\0'; - while (*s) - { - digit[0] = *s++; - for (i = 0; i < 10; i++) - { - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - - actual = dtmf_rx_get(dtmf_state, buf, 128); - - if (actual != 1 || buf[0] != digit[0]) - { - printf(" Sent '%s'\n", digit); - printf(" Received '%s'\n", buf); - printf(" Failed\n"); - exit(2); - } - } - } - printf(" Passed\n"); - - /* Test 3: Recognition bandwidth and channel centre frequency check. - Use only the diagonal pairs of tones (digits 1, 5, 9 and D). Each - tone pair requires four test to complete the check, making 16 - sections overall. Each section contains 40 pulses of - 50ms duration, with an amplitude of -20dB from clip per - frequency. - - Four sections covering the tests for one tone (1 digit) are: - a. H frequency at 0% deviation from center, L frequency at +0.1%. - L frequency is then increments in +01.% steps up to +4%. The - number of tone bursts is noted and designated N+. - b. H frequency at 0% deviation, L frequency at -0.1%. L frequency - is then incremental in -0.1% steps, up to -4%. The number of - tone bursts is noted and designated N-. - c. The test in (a) is repeated with the L frequency at 0% and the - H frequency varied up to +4%. - d. The test in (b) is repeated with the L frequency and 0% and the - H frequency varied to -4%. - - Receiver Recognition Bandwidth (RRB) is calculated as follows: - RRB% = (N+ + N-)/10 - Receiver Center Frequency Offset (RCFO) is calculated as follows: - RCFO% = X + (N+ - N-)/20 - - Note that this test doesn't test what it says it is testing at all, - and the results are quite inaccurate, if not a downright lie! However, - it follows the Mitel procedure, so how can it be bad? :) - */ - printf("Test 3: Recognition bandwidth and channel centre frequency check\n"); - s = "159D"; - digit[1] = '\0'; - while (*s) - { - digit[0] = *s++; - for (nplus = 0, i = 1; i <= 60; i++) - { - my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50); - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nplus += dtmf_rx_get(dtmf_state, buf, 128); - } - for (nminus = 0, i = -1; i >= -60; i--) - { - my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50); - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nminus += dtmf_rx_get(dtmf_state, buf, 128); - } - rrb = (float) (nplus + nminus)/10.0f; - rcfo = (float) (nplus - nminus)/10.0f; - printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", - digit[0], - rrb, - rcfo, - (float) nminus/10.0f, - (float) nplus/10.0f); - if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo) - { - printf(" Failed\n"); - exit(2); - } - - for (nplus = 0, i = 1; i <= 60; i++) - { - my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50); - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nplus += dtmf_rx_get(dtmf_state, buf, 128); - } - for (nminus = 0, i = -1; i >= -60; i--) - { - my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50); - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nminus += dtmf_rx_get(dtmf_state, buf, 128); - } - rrb = (float) (nplus + nminus)/10.0f; - rcfo = (float) (nplus - nminus)/10.0f; - printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", - digit[0], - rrb, - rcfo, - (float) nminus/10.0f, - (float) nplus/10.0f); - if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo) - { - printf(" Failed\n"); - exit(2); - } - } - printf(" Passed\n"); - - /* Test 4: Acceptable amplitude ratio (twist). - Use only the diagonal pairs of tones (digits 1, 5, 9 and D). - There are eight sections to the test. Each section contains 200 - pulses with a 50ms duration for each pulse. Initially the amplitude - of both tones is 6dB down from clip. The two sections to test one - tone pair are: - - a. Standard Twist: H tone amplitude is maintained at -6dB from clip, - L tone amplitude is attenuated gradually until the amplitude ratio - L/H is -20dB. Note the number of responses from the receiver. - b. Reverse Twist: L tone amplitude is maintained at -6dB from clip, - H tone amplitude is attenuated gradually until the amplitude ratio - is 20dB. Note the number of responses from the receiver. - - All tone bursts are of 50ms duration. - - The Acceptable Amplitude Ratio in dB is equal to the number of - responses registered in (a) or (b), divided by 10. - - TODO: This is supposed to work in 1/10dB steps, but here I used 1dB - steps, as the current tone generator has its amplitude set in - 1dB steps. - */ - printf("Test 4: Acceptable amplitude ratio (twist)\n"); - s = "159D"; - digit[1] = '\0'; - while (*s) - { - digit[0] = *s++; - for (nplus = 0, i = -30; i >= -230; i--) - { - my_dtmf_gen_init(0.0f, -3, 0.0f, i/10, 50, 50); - - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nplus += dtmf_rx_get(dtmf_state, buf, 128); - } - printf(" %c normal twist = %.2fdB\n", digit[0], (float) nplus/10.0); - if (nplus < 80) - { - printf(" Failed\n"); - exit(2); - } - for (nminus = 0, i = -30; i >= -230; i--) - { - my_dtmf_gen_init(0.0f, i/10, 0.0f, -3, 50, 50); - - len = my_dtmf_generate(amp, digit); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nminus += dtmf_rx_get(dtmf_state, buf, 128); - } - printf(" %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0); - if (nminus < 40) - { - printf(" Failed\n"); - exit(2); - } - } - printf(" Passed\n"); - - /* Test 5: Dynamic range - This test utilizes tone pair L1 H1 (digit 1). Thirty-five tone pair - pulses are transmitted, with both frequencies stating at -6dB from - clip. The amplitude of each is gradually attenuated by -35dB at a - rate of 1dB per pulse. The Dynamic Range in dB is equal to the - number of responses from the receiver during the test. - - Well not really, but that is the Mitel test. Lets sweep a bit further, - and see what the real range is */ - printf("Test 5: Dynamic range\n"); - for (nplus = 0, i = +3; i >= -50; i--) - { - my_dtmf_gen_init(0.0f, i, 0.0f, i, 50, 50); - - len = my_dtmf_generate(amp, "1"); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nplus += dtmf_rx_get(dtmf_state, buf, 128); - } - printf(" Dynamic range = %ddB\n", nplus); - /* We ought to set some pass/fail condition, even if Mitel did not. If - we don't, regression testing is weakened. */ - if (nplus < 35) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - /* Test 6: Guard time - This test utilizes tone pair L1 H1 (digit 1). Four hundred pulses - are transmitted at an amplitude of -6dB from clip per frequency. - Pulse duration starts at 49ms and is gradually reduced to 10ms. - Guard time in ms is equal to (500 - number of responses)/10. - - That is the Mitel test, and we will follow it. Its totally bogus, - though. Just what the heck is a pass or fail here? */ - - printf("Test 6: Guard time\n"); - for (nplus = 0, i = 490; i >= 100; i--) - { - my_dtmf_gen_init(0.0f, -3, 0.0f, -3, i/10, 50); - - len = my_dtmf_generate(amp, "1"); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - nplus += dtmf_rx_get(dtmf_state, buf, 128); - } - printf(" Guard time = %dms\n", (500 - nplus)/10); - printf(" Passed\n"); - - /* Test 7: Acceptable signal to noise ratio - This test utilizes tone pair L1 H1, transmitted on a noise background. - The test consists of three sections in which the tone pair is - transmitted 1000 times at an amplitude -6dB from clip per frequency, - but with a different white noise level for each section. The first - level is -24dBV, the second -18dBV and the third -12dBV.. The - acceptable signal to noise ratio is the lowest ratio of signal - to noise in the test where the receiver responds to all 1000 pulses. - - Well, that is the Mitel test, but it doesn't tell you what the - decoder can really do. Lets do a more comprehensive test */ - - printf("Test 7: Acceptable signal to noise ratio\n"); - my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50); - - for (j = -13; j > -50; j--) - { - awgn_init_dbm0(&noise_source, 1234567, (float) j); - for (i = 0; i < 1000; i++) - { - len = my_dtmf_generate(amp, "1"); - - // TODO: Clip - for (sample = 0; sample < len; sample++) - amp[sample] = sat_add16(amp[sample], awgn(&noise_source)); - - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - - if (dtmf_rx_get(dtmf_state, buf, 128) != 1) - break; - } - if (i == 1000) - break; - } - printf(" Acceptable S/N ratio is %ddB\n", -4 - j); - if (-4 - j > 26) - { - printf(" Failed\n"); - exit(2); - } - dtmf_rx_free(dtmf_state); - printf(" Passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void mitel_cm7291_side_2_and_bellcore_tests(void) -{ - int i; - int j; - int len; - int hits; - int hit_types[256]; - char buf[128 + 1]; - SNDFILE *inhandle; - int frames; - dtmf_rx_state_t *dtmf_state; - logging_state_t *logging; - - dtmf_state = dtmf_rx_init(NULL, NULL, NULL); - if (use_dialtone_filter || max_forward_twist >= 0.0f || max_reverse_twist >= 0.0f) - dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f); - logging = dtmf_rx_get_logging_state(dtmf_state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "DTMF-rx"); - - /* The remainder of the Mitel tape is the talk-off test */ - /* Here we use the Bellcore test tapes (much tougher), in six - files - 1 from each side of the original 3 cassette tapes */ - /* Bellcore say you should get no more than 470 false detections with - a good receiver. Dialogic claim 20. Of course, we can do better than - that, eh? */ - printf("Test 8: Talk-off test\n"); - memset(hit_types, '\0', sizeof(hit_types)); - for (j = 0; bellcore_files[j][0]; j++) - { - if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) - { - printf(" Cannot open speech file '%s'\n", bellcore_files[j]); - exit(2); - } - hits = 0; - while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE))) - { - dtmf_rx(dtmf_state, amp, frames); - len = dtmf_rx_get(dtmf_state, buf, 128); - if (len > 0) - { - for (i = 0; i < len; i++) - hit_types[(int) buf[i]]++; - hits += len; - } - } - if (sf_close_telephony(inhandle)) - { - printf(" Cannot close speech file '%s'\n", bellcore_files[j]); - exit(2); - } - printf(" File %d gave %d false hits.\n", j + 1, hits); - } - for (i = 0, j = 0; i < 256; i++) - { - if (hit_types[i]) - { - printf(" Digit %c had %d false hits.\n", i, hit_types[i]); - j += hit_types[i]; - } - } - printf(" %d false hits in total.\n", j); - if (j > 470) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - dtmf_rx_free(dtmf_state); -} -/*- End of function --------------------------------------------------------*/ - -static void dial_tone_tolerance_tests(void) -{ - int i; - int j; - int len; - int sample; - char buf[128 + 1]; - dtmf_rx_state_t *dtmf_state; - tone_gen_descriptor_t dial_tone_desc; - tone_gen_state_t dial_tone; - logging_state_t *logging; - - dtmf_state = dtmf_rx_init(NULL, NULL, NULL); - if (use_dialtone_filter || max_forward_twist >= 0.0f || max_reverse_twist >= 0.0f) - dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f); - logging = dtmf_rx_get_logging_state(dtmf_state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "DTMF-rx"); - - /* Test dial tone tolerance */ - printf("Test: Dial tone tolerance.\n"); - my_dtmf_gen_init(0.0f, -15, 0.0f, -15, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME); - - for (j = -30; j < -3; j++) - { - 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++) - { - len = my_dtmf_generate(amp, ALL_POSSIBLE_DIGITS); - tone_gen(&dial_tone, amp2, len); - - for (sample = 0; sample < len; sample++) - amp[sample] = sat_add16(amp[sample], amp2[sample]); - codec_munge(munge, amp, len); - dtmf_rx(dtmf_state, amp, len); - - if (dtmf_rx_get(dtmf_state, buf, 128) != strlen(ALL_POSSIBLE_DIGITS)) - break; - } - if (i != 10) - break; - } - printf(" Acceptable signal to dial tone ratio is %ddB\n", -15 - j); - if ((use_dialtone_filter && (-15 - j) > -12) - || - (!use_dialtone_filter && (-15 - j) > 10)) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - dtmf_rx_free(dtmf_state); -} -/*- End of function --------------------------------------------------------*/ - -static void callback_function_tests(void) -{ - int i; - int j; - int len; - int sample; - dtmf_rx_state_t *dtmf_state; - logging_state_t *logging; - - /* Test the callback mode for delivering detected digits */ - printf("Test: Callback digit delivery mode.\n"); - 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) - dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f); - logging = dtmf_rx_get_logging_state(dtmf_state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "DTMF-rx"); - - my_dtmf_gen_init(0.0f, DEFAULT_DTMF_TX_LEVEL, 0.0f, DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME); - for (i = 1; i < 10; i++) - { - len = 0; - for (j = 0; j < i; j++) - len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS); - dtmf_rx(dtmf_state, amp, len); - if (!callback_hit || !callback_ok) - break; - } - if (!callback_hit || !callback_ok) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - /* Test the realtime callback mode for reporting detected digits */ - printf("Test: Realtime callback digit delivery mode.\n"); - 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); - if (use_dialtone_filter || max_forward_twist >= 0.0f || max_reverse_twist >= 0.0f) - dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f); - logging = dtmf_rx_get_logging_state(dtmf_state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "DTMF-rx"); - - my_dtmf_gen_init(0.0f, DEFAULT_DTMF_TX_LEVEL, 0.0f, DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME); - step = 0; - for (i = 1; i < 10; i++) - { - len = 0; - for (j = 0; j < i; j++) - len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS); - for (sample = 0, j = SAMPLES_PER_CHUNK; sample < len; sample += SAMPLES_PER_CHUNK, j = ((len - sample) >= SAMPLES_PER_CHUNK) ? SAMPLES_PER_CHUNK : (len - sample)) - { - dtmf_rx(dtmf_state, &[sample], j); - if (!callback_ok) - break; - step += j; - } - if (!callback_hit || !callback_ok) - break; - } - if (!callback_hit || !callback_ok) - { - printf(" Failed\n"); - exit(2); - } - dtmf_rx_free(dtmf_state); -} -/*- End of function --------------------------------------------------------*/ - -static void decode_test(const char *test_file) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - SNDFILE *inhandle; - dtmf_rx_state_t *dtmf_state; - char buf[128 + 1]; - int actual; - int samples; - int total; - logging_state_t *logging; - - dtmf_state = dtmf_rx_init(NULL, NULL, NULL); - if (use_dialtone_filter || max_forward_twist >= 0.0f || max_reverse_twist >= 0.0f) - dtmf_rx_parms(dtmf_state, use_dialtone_filter, max_forward_twist, max_reverse_twist, -99.0f); - logging = dtmf_rx_get_logging_state(dtmf_state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "DTMF-rx"); - - /* We will decode the audio from a file. */ - - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - - total = 0; - while ((samples = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK)) > 0) - { - codec_munge(munge, amp, samples); - dtmf_rx(dtmf_state, amp, samples); - //printf("Status 0x%X\n", dtmf_rx_status(dtmf_state)); - if ((actual = dtmf_rx_get(dtmf_state, buf, 128)) > 0) - printf("Received '%s'\n", buf); - total += actual; - } - printf("%d digits received\n", total); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int duration; - time_t now; - int channel_codec; - int opt; - - use_dialtone_filter = false; - channel_codec = MUNGE_CODEC_NONE; - decode_test_file = NULL; - max_forward_twist = -1.0f; - max_reverse_twist = -1.0f; - while ((opt = getopt(argc, argv, "c:d:F:fR:")) != -1) - { - switch (opt) - { - case 'c': - channel_codec = atoi(optarg); - break; - case 'd': - decode_test_file = optarg; - break; - case 'F': - max_forward_twist = atof(optarg); - break; - case 'f': - use_dialtone_filter = true; - break; - case 'R': - max_reverse_twist = atof(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - munge = codec_munge_init(channel_codec, 0); - - if (decode_test_file) - { - decode_test(decode_test_file); - } - else - { - time(&now); - mitel_cm7291_side_1_tests(); - mitel_cm7291_side_2_and_bellcore_tests(); - dial_tone_tolerance_tests(); - callback_function_tests(); - printf(" Passed\n"); - duration = time(NULL) - now; - printf("Tests passed in %ds\n", duration); - } - - codec_munge_free(munge); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/dtmf_tx_tests.c b/libs/spandsp/tests/dtmf_tx_tests.c deleted file mode 100644 index 1d0ad29178..0000000000 --- a/libs/spandsp/tests/dtmf_tx_tests.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dtmf_tx_tests.c - Test the DTMF generator. - * - * 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 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 dtmf_tx_tests_page DTMF generation tests -\section dtmf_tx_tests_page_sec_1 What does it do? -???. - -\section dtmf_tx_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "dtmf.wav" - -int main(int argc, char *argv[]) -{ - dtmf_tx_state_t *gen; - int16_t amp[16384]; - int len; - SNDFILE *outhandle; - int add_digits; - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - gen = dtmf_tx_init(NULL, NULL, NULL); - len = dtmf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "123", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "456", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "789", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "*#", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - add_digits = 1; - do - { - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - if (add_digits) - { - if (dtmf_tx_put(gen, "1234567890", -1)) - { - printf("Digit buffer full\n"); - add_digits = 0; - } - } - } - while (len > 0); - - dtmf_tx_init(gen, NULL, NULL); - len = dtmf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "123", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 16384); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "456", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "789", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "0*#", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - if (dtmf_tx_put(gen, "ABCD", -1)) - { - printf("Ooops\n"); - exit(2); - } - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - sf_writef_short(outhandle, amp, len); - - /* Try modifying the level and length of the digits */ - printf("Try different levels and timing\n"); - dtmf_tx_set_level(gen, -20, 5); - dtmf_tx_set_timing(gen, 100, 200); - if (dtmf_tx_put(gen, "123", -1)) - { - printf("Ooops\n"); - exit(2); - } - do - { - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - } - while (len > 0); - printf("Restore normal levels and timing\n"); - dtmf_tx_set_level(gen, -10, 0); - dtmf_tx_set_timing(gen, 50, 55); - if (dtmf_tx_put(gen, "A", -1)) - { - printf("Ooops\n"); - exit(2); - } - - add_digits = true; - do - { - len = dtmf_tx(gen, amp, 160); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - if (add_digits) - { - if (dtmf_tx_put(gen, "1234567890", -1)) - { - printf("Digit buffer full\n"); - add_digits = false; - } - } - } - while (len > 0); - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - dtmf_tx_free(gen); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/dummy_modems_tests.c b/libs/spandsp/tests/dummy_modems_tests.c deleted file mode 100644 index 45d559aab6..0000000000 --- a/libs/spandsp/tests/dummy_modems_tests.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * dummy_modems_tests.c - Tests for data_modems connected together by sockets. - * - * 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 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 dummy_modems_tests_page Dummy data modems tests -\section dummy_modems_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -//#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -#include "pseudo_terminals.h" -#include "socket_harness.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif - -#define OUTPUT_WAVE_FILE_NAME "dummy_modems.wav" - -#define SAMPLES_PER_CHUNK 160 - -SNDFILE *wave_handle = NULL; -int16_t wave_buffer[4096]; - -data_modems_state_t *data_modem_state; - -int answered = false; -int done = false; - -static int modem_call_control(data_modems_state_t *s, void *user_data, int op, const char *num) -{ - printf("\nModem control - %s", at_modem_control_to_str(op)); - switch (op) - { - case AT_MODEM_CONTROL_CALL: - printf(" %s", num); - data_modems_call_event(s, AT_CALL_EVENT_CONNECTED); - break; - case AT_MODEM_CONTROL_ANSWER: - answered = true; - data_modems_call_event(s, AT_CALL_EVENT_ANSWERED); - break; - case AT_MODEM_CONTROL_HANGUP: - done = true; - break; - case AT_MODEM_CONTROL_OFFHOOK: - break; - case AT_MODEM_CONTROL_DTR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RTS: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CTS: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CAR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RNG: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DSR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_SETID: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RESTART: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - printf(" %d", (int) (intptr_t) num); - break; - } - /*endswitch*/ - printf("\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int get_msg(void *user_data, uint8_t msg[], int len) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void put_msg(void *user_data, const uint8_t msg[], int len) -{ - if (len < 0) - printf("Status %s\n", signal_status_to_str(len)); - else - printf("Put %d '%s'\n", len, msg); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void terminal_callback(void *user_data, const uint8_t msg[], int len) -{ - data_modems_state_t *s; - int i; - - s = (data_modems_state_t *) user_data; - printf("terminal callback %d\n", len); - for (i = 0; i < len; i++) - { - printf("0x%x ", msg[i]); - } - printf("\n"); - at_interpreter(&s->at_state, (const char *) msg, len); -} -/*- End of function --------------------------------------------------------*/ - -static int termios_callback(void *user_data, struct termios *termios) -{ - data_modems_state_t *s; - - s = (data_modems_state_t *) user_data; - printf("termios callback\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void hangup_callback(void *user_data, int status) -{ -} -/*- End of function --------------------------------------------------------*/ - -static int terminal_free_space_callback(void *user_data) -{ - return 42; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_callback(void *user_data, const int16_t amp[], int samples) -{ - int i; - int out_samples; - - out_samples = data_modems_rx((data_modems_state_t *) user_data, amp, samples); - if (wave_handle) - { - for (i = 0; i < samples; i++) - wave_buffer[2*i] = amp[i]; - /*endfor*/ - } - /*endif*/ - return out_samples; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_fillin_callback(void *user_data, int samples) -{ - return data_modems_rx_fillin((data_modems_state_t *) user_data, samples); -} -/*- End of function --------------------------------------------------------*/ - -static int tx_callback(void *user_data, int16_t amp[], int samples) -{ - int i; - int out_samples; - - out_samples = data_modems_tx((data_modems_state_t *) user_data, amp, samples); - if (wave_handle) - { - if (out_samples < samples) - memset(&[out_samples], 0, (samples - out_samples)*2); - /*endif*/ - for (i = 0; i < samples; i++) - wave_buffer[2*i + 1] = amp[i]; - /*endfor*/ - sf_writef_short(wave_handle, wave_buffer, samples); - } - /*endif*/ - return samples; -} -/*- End of function --------------------------------------------------------*/ - -static int modem_tests(int use_gui, int log_audio, bool calling_party) -{ - logging_state_t *logging; - socket_harness_state_t *s; - - /* Now set up and run the modems */ - if ((data_modem_state = data_modems_init(NULL, - calling_party, - terminal_write, - NULL, - modem_call_control, - NULL, - put_msg, - get_msg, - NULL)) == NULL) - { - fprintf(stderr, " Cannot start the data modem\n"); - exit(2); - } - /*endif*/ - logging = data_modems_get_logging_state(data_modem_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_DATE); - span_log_set_tag(logging, "Modem"); - - if ((s = socket_harness_init(NULL, - "/tmp/modemsocket", - "modemA", - calling_party, - terminal_callback, - termios_callback, - hangup_callback, - terminal_free_space_callback, - rx_callback, - rx_fillin_callback, - tx_callback, - data_modem_state)) == NULL) - { - fprintf(stderr, " Cannot start the socket harness\n"); - exit(2); - } - /*endif*/ - - data_modems_set_at_tx_handler(data_modem_state, terminal_write, s); - - wave_handle = NULL; - if (log_audio) - { - if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - /*endif*/ - } - /*endif*/ - - socket_harness_run(s, calling_party); - - if (log_audio) - { - if (sf_close_telephony(wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - /*endif*/ - } - /*endif*/ - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int log_audio; - int use_gui; - int opt; - bool calling_party; - - log_audio = false; - calling_party = false; - use_gui = false; - while ((opt = getopt(argc, argv, "acgl")) != -1) - { - switch (opt) - { - case 'a': - calling_party = false; - break; - case 'c': - calling_party = true; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - default: - //usage(); - exit(2); - break; - } - /*endswitch*/ - } - /*endwhile*/ - - if (modem_tests(use_gui, log_audio, calling_party)) - exit(2); - /*endif*/ - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/echo_monitor.cpp b/libs/spandsp/tests/echo_monitor.cpp deleted file mode 100644 index ecea0f6b7b..0000000000 --- a/libs/spandsp/tests/echo_monitor.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * echo_monitor.cpp - Display echo canceller status, using the FLTK toolkit. - * - * 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 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) - -#define __STDC_LIMIT_MACROS - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_FFTW3_H) -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "echo_monitor.h" - -struct line_model_monitor_s -{ - Fl_Double_Window *w; - - Fl_Audio_Meter *audio_meter; - Fl_Group *c_spec; - Fl_Group *c_right; - Fl_Group *c_can; - Fl_Group *c_line_model; - - Ca_Canvas *canvas_spec; - Ca_X_Axis *spec_freq; - Ca_Y_Axis *spec_amp; - Ca_Line *spec_re; - double spec_re_plot[2*512]; - - Ca_Canvas *canvas_can; - Ca_X_Axis *can_x; - Ca_Y_Axis *can_y; - Ca_Line *can_re; - double can_re_plot[512]; - - Ca_Canvas *canvas_line_model; - Ca_X_Axis *line_model_x; - Ca_Y_Axis *line_model_y; - Ca_Line *line_model_re; - double line_model_re_plot[512]; - - int in_ptr; -#if defined(HAVE_FFTW3_H) - double in[1024][2]; - double out[1024][2]; -#else - fftw_complex in[1024]; - fftw_complex out[1024]; -#endif - fftw_plan p; -}; - - -static int skip = 0; -static struct line_model_monitor_s echo; -static struct line_model_monitor_s *s = &echo; - -int echo_can_monitor_can_update(const int16_t *coeffs, int len) -{ - int i; - float min; - float max; - - if (s->can_re) - delete s->can_re; - - s->canvas_can->current(s->canvas_can); - i = 0; - min = coeffs[i]; - max = coeffs[i]; - for (i = 0; i < len; i++) - { - s->can_re_plot[2*i] = i; - s->can_re_plot[2*i + 1] = coeffs[i]; - if (min > coeffs[i]) - min = coeffs[i]; - if (max < coeffs[i]) - max = coeffs[i]; - } - s->can_y->maximum((max == min) ? max + 0.2 : max); - s->can_y->minimum(min); - s->can_re = new Ca_Line(len, s->can_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - if (++skip >= 100) - { - skip = 0; - Fl::check(); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int echo_can_monitor_line_model_update(const int32_t *coeffs, int len) -{ - int i; - float min; - float max; - - if (s->line_model_re) - delete s->line_model_re; - - s->canvas_line_model->current(s->canvas_line_model); - i = 0; - min = coeffs[i]; - max = coeffs[i]; - for (i = 0; i < len; i++) - { - s->line_model_re_plot[2*i] = i; - s->line_model_re_plot[2*i + 1] = coeffs[i]; - if (min > coeffs[i]) - min = coeffs[i]; - if (max < coeffs[i]) - max = coeffs[i]; - } - s->line_model_y->maximum((max == min) ? max + 0.2 : max); - s->line_model_y->minimum(min); - s->line_model_re = new Ca_Line(len, s->line_model_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - if (++skip >= 100) - { - skip = 0; - Fl::check(); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int echo_can_monitor_line_spectrum_update(const int16_t amp[], int len) -{ - int i; - int x; - - for (i = 0; i < len; i++) - s->audio_meter->sample(amp[i]/32768.0); - - if (s->in_ptr + len < 512) - { - /* Just add this fragment to the buffer. */ - for (i = 0; i < len; i++) -#if defined(HAVE_FFTW3_H) - s->in[s->in_ptr + i][0] = amp[i]; -#else - s->in[s->in_ptr + i].re = amp[i]; -#endif - s->in_ptr += len; - return 0; - } - if (len >= 512) - { - /* We have enough for a whole block. Use the last 512 samples - we have. */ - x = len - 512; - for (i = 0; i < 512; i++) -#if defined(HAVE_FFTW3_H) - s->in[i][0] = amp[x + i]; -#else - s->in[i].re = amp[x + i]; -#endif - } - else - { - /* We want the last 512 samples. */ - x = 512 - len; - for (i = 0; i < x; i++) -#if defined(HAVE_FFTW3_H) - s->in[i][0] = s->in[s->in_ptr - x + i][0]; -#else - s->in[i].re = s->in[s->in_ptr - x + i].re; -#endif - for (i = x; i < 512; i++) -#if defined(HAVE_FFTW3_H) - s->in[i][0] = amp[i - x]; -#else - s->in[i].re = amp[i - x]; -#endif - } - s->in_ptr = 0; -#if defined(HAVE_FFTW3_H) - fftw_execute(s->p); -#else - fftw_one(s->p, s->in, s->out); -#endif - if (s->spec_re) - delete s->spec_re; - s->canvas_spec->current(s->canvas_spec); - for (i = 0; i < 512; i++) - { - s->spec_re_plot[2*i] = i*4000.0/512.0; -#if defined(HAVE_FFTW3_H) - s->spec_re_plot[2*i + 1] = 10.0*log10((s->out[i][0]*s->out[i][0] + s->out[i][1]*s->out[i][1])/(256.0*32768*256.0*32768) + 1.0e-10) + 3.14; -#else - s->spec_re_plot[2*i + 1] = 10.0*log10((s->out[i].re*s->out[i].re + s->out[i].im*s->out[i].im)/(256.0*32768*256.0*32768) + 1.0e-10) + 3.14; -#endif - } - s->spec_re = new Ca_Line(512, s->spec_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int start_echo_can_monitor(int len) -{ - char buf[132 + 1]; - float x; - float y; - int i; - - s->w = new Fl_Double_Window(850, 400, "Echo canceller monitor"); - - s->c_spec = new Fl_Group(0, 0, 380, 400); - s->c_spec->box(FL_DOWN_BOX); - s->c_spec->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - - s->canvas_spec = new Ca_Canvas(60, 30, 300, 300, "Spectrum"); - s->canvas_spec->box(FL_PLASTIC_DOWN_BOX); - s->canvas_spec->color(7); - s->canvas_spec->align(FL_ALIGN_TOP); - s->canvas_spec->border(15); - - s->spec_freq = new Ca_X_Axis(65, 330, 290, 30, "Freq (Hz)"); - s->spec_freq->align(FL_ALIGN_BOTTOM); - s->spec_freq->minimum(0); - s->spec_freq->maximum(4000); - s->spec_freq->label_format("%g"); - s->spec_freq->minor_grid_color(fl_gray_ramp(20)); - s->spec_freq->major_grid_color(fl_gray_ramp(15)); - s->spec_freq->label_grid_color(fl_gray_ramp(10)); - s->spec_freq->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->spec_freq->minor_grid_style(FL_DOT); - s->spec_freq->major_step(5); - s->spec_freq->label_step(1); - s->spec_freq->axis_color(FL_BLACK); - s->spec_freq->axis_align(CA_BOTTOM | CA_LINE); - - s->spec_amp = new Ca_Y_Axis(20, 35, 40, 290, "Amp (dBmO)"); - s->spec_amp->align(FL_ALIGN_LEFT); - s->spec_amp->minimum(-80.0); - s->spec_amp->maximum(10.0); - s->spec_amp->minor_grid_color(fl_gray_ramp(20)); - s->spec_amp->major_grid_color(fl_gray_ramp(15)); - s->spec_amp->label_grid_color(fl_gray_ramp(10)); - //s->spec_amp->grid_visible(CA_MINOR_TICK | CA_MAJOR_TICK | CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->spec_amp->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->spec_amp->minor_grid_style(FL_DOT); - s->spec_amp->major_step(5); - s->spec_amp->label_step(1); - s->spec_amp->axis_color(FL_BLACK); - - s->spec_amp->current(); - s->spec_re = NULL; - - s->c_spec->end(); - - s->c_right = new Fl_Group(440, 0, 465, 405); - - s->c_can = new Fl_Group(380, 0, 415, 200); - s->c_can->box(FL_DOWN_BOX); - s->c_can->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_can->current(); - - s->canvas_can = new Ca_Canvas(460, 35, 300, 100, "Canceller coefficients"); - s->canvas_can->box(FL_PLASTIC_DOWN_BOX); - s->canvas_can->color(7); - s->canvas_can->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_can); - s->canvas_can->border(15); - - s->can_x = new Ca_X_Axis(465, 135, 290, 30, "Tap"); - s->can_x->align(FL_ALIGN_BOTTOM); - s->can_x->minimum(0.0); - s->can_x->maximum((float) len); - s->can_x->label_format("%g"); - s->can_x->minor_grid_color(fl_gray_ramp(20)); - s->can_x->major_grid_color(fl_gray_ramp(15)); - s->can_x->label_grid_color(fl_gray_ramp(10)); - s->can_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->can_x->minor_grid_style(FL_DOT); - s->can_x->major_step(5); - s->can_x->label_step(1); - s->can_x->axis_align(CA_BOTTOM | CA_LINE); - s->can_x->axis_color(FL_BLACK); - s->can_x->current(); - - s->can_y = new Ca_Y_Axis(420, 40, 40, 90, "Amp"); - s->can_y->align(FL_ALIGN_LEFT); - s->can_y->minimum(-0.1); - s->can_y->maximum(0.1); - s->can_y->minor_grid_color(fl_gray_ramp(20)); - s->can_y->major_grid_color(fl_gray_ramp(15)); - s->can_y->label_grid_color(fl_gray_ramp(10)); - s->can_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->can_y->minor_grid_style(FL_DOT); - s->can_y->major_step(5); - s->can_y->label_step(1); - s->can_y->axis_color(FL_BLACK); - s->can_y->current(); - - s->c_can->end(); - s->can_re = NULL; - - s->c_line_model = new Fl_Group(380, 200, 415, 200); - s->c_line_model->box(FL_DOWN_BOX); - s->c_line_model->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_line_model->current(); - - s->canvas_line_model = new Ca_Canvas(460, 235, 300, 100, "Line impulse response model"); - s->canvas_line_model->box(FL_PLASTIC_DOWN_BOX); - s->canvas_line_model->color(7); - s->canvas_line_model->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_line_model); - s->canvas_line_model->border(15); - - s->line_model_x = new Ca_X_Axis(465, 335, 290, 30, "Tap"); - s->line_model_x->align(FL_ALIGN_BOTTOM); - s->line_model_x->minimum(0.0); - s->line_model_x->maximum((float) len); - s->line_model_x->label_format("%g"); - s->line_model_x->minor_grid_color(fl_gray_ramp(20)); - s->line_model_x->major_grid_color(fl_gray_ramp(15)); - s->line_model_x->label_grid_color(fl_gray_ramp(10)); - s->line_model_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->line_model_x->minor_grid_style(FL_DOT); - s->line_model_x->major_step(5); - s->line_model_x->label_step(1); - s->line_model_x->axis_align(CA_BOTTOM | CA_LINE); - s->line_model_x->axis_color(FL_BLACK); - s->line_model_x->current(); - - s->line_model_y = new Ca_Y_Axis(420, 240, 40, 90, "Amp"); - s->line_model_y->align(FL_ALIGN_LEFT); - s->line_model_y->minimum(-0.1); - s->line_model_y->maximum(0.1); - s->line_model_y->minor_grid_color(fl_gray_ramp(20)); - s->line_model_y->major_grid_color(fl_gray_ramp(15)); - s->line_model_y->label_grid_color(fl_gray_ramp(10)); - s->line_model_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->line_model_y->minor_grid_style(FL_DOT); - s->line_model_y->major_step(5); - s->line_model_y->label_step(1); - s->line_model_y->axis_color(FL_BLACK); - s->line_model_y->current(); - - s->c_line_model->end(); - s->line_model_re = NULL; - - s->audio_meter = new Fl_Audio_Meter(810, 40, 10, 250, ""); - s->audio_meter->box(FL_PLASTIC_UP_BOX); - s->audio_meter->type(FL_VERT_AUDIO_METER); - - s->c_right->end(); - - Fl_Group::current()->resizable(s->c_right); - s->w->end(); - s->w->show(); - -#if defined(HAVE_FFTW3_H) - s->p = fftw_plan_dft_1d(1024, s->in, s->out, FFTW_BACKWARD, FFTW_ESTIMATE); - for (i = 0; i < 1024; i++) - { - s->in[i][0] = 0.0; - s->in[i][1] = 0.0; - } -#else - s->p = fftw_create_plan(1024, FFTW_BACKWARD, FFTW_ESTIMATE); - for (i = 0; i < 1024; i++) - { - s->in[i].re = 0.0; - s->in[i].im = 0.0; - } -#endif - s->in_ptr = 0; - - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -void echo_can_monitor_wait_to_end(void) -{ - fd_set rfds; - int res; - struct timeval tv; - - fprintf(stderr, "Processing complete. Press the key to end\n"); - do - { - usleep(100000); - Fl::check(); - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_usec = 100000; - tv.tv_sec = 0; - res = select(1, &rfds, NULL, NULL, &tv); - } - while (res <= 0); -} -/*- End of function --------------------------------------------------------*/ - -void echo_can_monitor_update_display(void) -{ - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); -} -/*- End of function --------------------------------------------------------*/ -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/echo_monitor.h b/libs/spandsp/tests/echo_monitor.h deleted file mode 100644 index 72bc718fb4..0000000000 --- a/libs/spandsp/tests/echo_monitor.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * echo_monitor.h - Display echo canceller status, using the FLTK toolkit. - * - * 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 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. - */ - -/*! \page echo_monitor_page Echo canceller performance monitoring -\section echo_monitor_page_sec_1 What does it do? -This code controls a GUI window, which provides monitoring of the internal status -of a time domain echo canceller. It shows, graphically: - - - the spectrum of the received signal. - - the line model in use (when a known line model is being used). - - the adapted coefficients of the canceller. - -\section echo_monitor_page_sec_2 How does it work? -This code uses the FLTK cross platform GUI toolkit. It works on X11 and Windows platforms. -In addition to the basic FLTK toolkit, fltk_cartesian is also required. -*/ - -#if !defined(_ECHO_MONITOR_H_) -#define _ECHO_MONITOR_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -int start_echo_can_monitor(int len); -int echo_can_monitor_can_update(const int16_t *coeffs, int len); -int echo_can_monitor_line_model_update(const int32_t *coeffs, int len); -int echo_can_monitor_line_spectrum_update(const int16_t amp[], int len); -void echo_can_monitor_wait_to_end(void); -void echo_can_monitor_update_display(void); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/echo_tests.c b/libs/spandsp/tests/echo_tests.c deleted file mode 100644 index bbb8c41512..0000000000 --- a/libs/spandsp/tests/echo_tests.c +++ /dev/null @@ -1,1722 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * echo_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2001 Steve Underwood - * - * Based on a bit from here, a bit from there, eye of toad, - * ear of bat, etc - plus, of course, my own 2 cents. - * - * 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. - */ - -/*! \page echo_can_tests_page Line echo cancellation for voice tests - -\section echo_can_tests_page_sec_1 What does it do? -The echo cancellation tests test the echo cancellor against the G.168 spec. Not -all the tests in G.168 are fully implemented at this time. - -\section echo_can_tests_page_sec_2 How does it work? - -\section echo_can_tests_page_sec_2 How do I use it? - -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include - -#define GEN_CONST -#include - -#include "spandsp.h" -#include "spandsp/g168models.h" -#include "spandsp-sim.h" -#if defined(ENABLE_GUI) -#include "echo_monitor.h" -#endif - -#if !defined(NULL) -#define NULL (void *) 0 -#endif - -#define TEST_EC_TAPS 256 - -#define RESIDUE_FILE_NAME "residue_sound.wav" - -/* - The key signal names, as defined in G.168 - - +--------------+ +------------+ - | | Sin | | -Sgen -->--| Echoey |--->---| Echo |-->-- Sout - | | | | - | World | Rout | Canceller | - --<--| |---<---| |--<-- Rin - | | | | - +--------------+ +------------+ - - Echoey world model. Munge means linear->PCM->linear distortion. - +-------------------------+ - | | Sin -Sgen -->--|-->munge--->sum-->munge--|--->--- - | +--> | - | FIR | Rout - --<--|--------+--------munge<--|---<--- - | | - +-------------------------+ -*/ - -typedef struct -{ - const char *name; - int max; - int cur; - float gain; - SNDFILE *handle; - int16_t signal[SAMPLE_RATE]; -} signal_source_t; - -/* Level measurement device, specified in G.168 section 6.4.1.2.1 */ -typedef struct -{ - int type; - fir_float_state_t *fir; - float history[35*8]; - int pos; - float factor; - float power; - float peak; -} level_measurement_device_t; - -typedef struct -{ - int model_no; - float erl; - fir32_state_t impulse; - float gain; - int munging_codec; -} channel_model_state_t; - -channel_model_state_t chan_model; - -signal_source_t local_css; -signal_source_t far_css; -awgn_state_t local_noise_source; -awgn_state_t far_noise_source; - -SNDFILE *residue_handle; -int16_t residue_sound[SAMPLE_RATE]; -int residue_cur = 0; - -level_measurement_device_t *power_meter_1; -level_measurement_device_t *power_meter_2; - -int line_model_no; -int supp_line_model_no; -int munger; - -level_measurement_device_t *rin_power_meter; /* Also known as Lrin */ -level_measurement_device_t *rout_power_meter; -level_measurement_device_t *sin_power_meter; -level_measurement_device_t *sout_power_meter; /* Also known as Lret (pre NLP value is known as Lres) */ -level_measurement_device_t *sgen_power_meter; - -#define RESULT_CHANNELS 7 -SNDFILE *result_handle; -int16_t result_sound[SAMPLE_RATE*RESULT_CHANNELS]; -int result_cur; - -const char *test_name; -int quiet; -int use_gui; - -float erl; - -/* Dump estimated echo response */ -static void dump_ec_state(echo_can_state_t *ctx) -{ - int i; - FILE *f; - - if ((f = fopen("echo_tests_state.txt", "wt")) == NULL) - return; - for (i = 0; i < TEST_EC_TAPS; i++) - fprintf(f, "%f\n", (float) ctx->fir_taps16[0][i]/(1 << 15)); - fclose(f); -} -/*- End of function --------------------------------------------------------*/ - -static inline void put_residue(int16_t amp) -{ - int outframes; - - residue_sound[residue_cur++] = amp; - if (residue_cur >= SAMPLE_RATE) - { - outframes = sf_writef_short(residue_handle, residue_sound, residue_cur); - if (outframes != residue_cur) - { - fprintf(stderr, " Error writing residue sound\n"); - exit(2); - } - residue_cur = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_load(signal_source_t *sig, const char *name) -{ - sig->handle = sf_open_telephony_read(name, 1); - sig->name = name; - sig->max = sf_readf_short(sig->handle, sig->signal, SAMPLE_RATE); - if (sig->max < 0) - { - fprintf(stderr, " Error reading sound file '%s'\n", sig->name); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_free(signal_source_t *sig) -{ - if (sf_close_telephony(sig->handle)) - { - fprintf(stderr, " Cannot close sound file '%s'\n", sig->name); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_restart(signal_source_t *sig, float gain) -{ - sig->cur = 0; - sig->gain = powf(10.0f, gain/20.0f); -} -/*- End of function --------------------------------------------------------*/ - -static int16_t signal_amp(signal_source_t *sig) -{ - int16_t tx; - - tx = sig->signal[sig->cur++]*sig->gain; - if (sig->cur >= sig->max) - sig->cur = 0; - return tx; -} -/*- End of function --------------------------------------------------------*/ - -static level_measurement_device_t *level_measurement_device_create(int type) -{ - level_measurement_device_t *dev; - int i; - - dev = (level_measurement_device_t *) malloc(sizeof(level_measurement_device_t)); - dev->fir = (fir_float_state_t *) malloc(sizeof(fir_float_state_t)); - fir_float_create(dev->fir, - level_measurement_bp_coeffs, - sizeof(level_measurement_bp_coeffs)/sizeof(float)); - for (i = 0; i < 35*8; i++) - dev->history[i] = 0.0f; - dev->pos = 0; - dev->factor = expf(-1.0f/((float) SAMPLE_RATE*0.035f)); - dev->power = 0; - dev->type = type; - return dev; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -static void level_measurement_device_reset(level_measurement_device_t *dev) -{ - int i; - - for (i = 0; i < 35*8; i++) - dev->history[i] = 0.0f; - dev->pos = 0; - dev->power = 0; - dev->peak = 0.0f; -} -/*- End of function --------------------------------------------------------*/ - -static int level_measurement_device_release(level_measurement_device_t *s) -{ - fir_float_free(s->fir); - free(s->fir); - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static float level_measurement_device_get_peak(level_measurement_device_t *dev) -{ - return dev->peak; -} -/*- End of function --------------------------------------------------------*/ - -static float level_measurement_device_reset_peak(level_measurement_device_t *dev) -{ - float power; - - power = dev->peak; - dev->peak = -99.0f; - return power; -} -/*- End of function --------------------------------------------------------*/ - -static float level_measurement_device(level_measurement_device_t *dev, int16_t amp) -{ - float signal; - float power; - - /* Level measurement device(s), specified in G.168 section 6.4.1.2.1 and 6.4.1.2.2 */ - signal = fir_float(dev->fir, amp); - signal *= signal; - if (dev->type == 0) - { - /* Level measurement device, specified in G.168 section 6.4.1.2.1 - - level measurement device. This version uses a single pole - estimator.*/ - dev->power = dev->power*dev->factor + signal*(1.0f - dev->factor); - signal = sqrtf(dev->power); - } - else - { - /* Level measurement device, specified in G.168 section 6.4.1.2.2 - - level measurement device for peaks. This version uses a sliding - window estimator. */ - dev->power += (signal - dev->history[dev->pos]); - dev->history[dev->pos++] = signal; - signal = sqrtf(dev->power/(35.8f*8.0f)); - } - if (signal <= 0.0f) - return -99.0f; - power = DBM0_MAX_POWER + 20.0f*log10f(signal/32767.0f + 1.0e-10f); - if (power > dev->peak) - dev->peak = power; - return power; -} -/*- End of function --------------------------------------------------------*/ - -static void level_measurements_create(int type) -{ - rin_power_meter = level_measurement_device_create(type); - rout_power_meter = level_measurement_device_create(type); - sin_power_meter = level_measurement_device_create(type); - sout_power_meter = level_measurement_device_create(type); - sgen_power_meter = level_measurement_device_create(type); -} -/*- End of function --------------------------------------------------------*/ - -static void level_measurements_update(int16_t rin, int16_t sin, int16_t rout, int16_t sout, int16_t sgen) -{ - level_measurement_device(rin_power_meter, rin); - level_measurement_device(rout_power_meter, rout); - level_measurement_device(sin_power_meter, sin); - level_measurement_device(sout_power_meter, sout); - level_measurement_device(sgen_power_meter, sgen); -} -/*- End of function --------------------------------------------------------*/ - -static void level_measurements_reset_peaks(void) -{ - level_measurement_device_reset_peak(rin_power_meter); - level_measurement_device_reset_peak(rout_power_meter); - level_measurement_device_reset_peak(sin_power_meter); - level_measurement_device_reset_peak(sout_power_meter); - level_measurement_device_reset_peak(sgen_power_meter); -} -/*- End of function --------------------------------------------------------*/ - -static void print_results(void) -{ - if (!quiet) - printf("test model ERL time Max Rin Max Rout Max Sgen Max Sin Max Sout\n"); - printf("%-4s %-1d %-5.1f%6.2fs%9.2f%9.2f%9.2f%9.2f%9.2f\n", - test_name, - chan_model.model_no, - 20.0f*log10f(-chan_model.erl + 1.0e-10f), - 0.0f, //test_clock, - level_measurement_device_get_peak(rin_power_meter), - level_measurement_device_get_peak(rout_power_meter), - level_measurement_device_get_peak(sgen_power_meter), - level_measurement_device_get_peak(sin_power_meter), - level_measurement_device_get_peak(sout_power_meter)); -} -/*- End of function --------------------------------------------------------*/ - -static int channel_model_create(channel_model_state_t *chan, int model, float erl, int codec) -{ - static const int32_t line_model_clear_coeffs[] = - { - 32768 - }; - static const int32_t *line_models[] = - { - line_model_clear_coeffs, - line_model_d2_coeffs, - line_model_d3_coeffs, - line_model_d4_coeffs, - line_model_d5_coeffs, - line_model_d6_coeffs, - line_model_d7_coeffs, - line_model_d8_coeffs, - line_model_d9_coeffs - }; - static const int line_model_sizes[] = - { - sizeof(line_model_clear_coeffs)/sizeof(line_model_clear_coeffs[0]), - sizeof(line_model_d2_coeffs)/sizeof(line_model_d2_coeffs[0]), - sizeof(line_model_d3_coeffs)/sizeof(line_model_d3_coeffs[0]), - sizeof(line_model_d4_coeffs)/sizeof(line_model_d4_coeffs[0]), - sizeof(line_model_d5_coeffs)/sizeof(line_model_d5_coeffs[0]), - sizeof(line_model_d6_coeffs)/sizeof(line_model_d6_coeffs[0]), - sizeof(line_model_d7_coeffs)/sizeof(line_model_d7_coeffs[0]), - sizeof(line_model_d8_coeffs)/sizeof(line_model_d8_coeffs[0]), - sizeof(line_model_d9_coeffs)/sizeof(line_model_d9_coeffs[0]) - }; - static const float ki[] = - { - 3.05e-5f, - LINE_MODEL_D2_GAIN, - LINE_MODEL_D3_GAIN, - LINE_MODEL_D4_GAIN, - LINE_MODEL_D5_GAIN, - LINE_MODEL_D6_GAIN, - LINE_MODEL_D7_GAIN, - LINE_MODEL_D8_GAIN, - LINE_MODEL_D9_GAIN - }; - - if (model < 0 || model >= (int) (sizeof(line_model_sizes)/sizeof(line_model_sizes[0]))) - return -1; - fir32_create(&chan->impulse, line_models[model], line_model_sizes[model]); - chan->gain = 32768.0f*powf(10.0f, erl/20.0f)*ki[model]; - chan->munging_codec = codec; - chan->model_no = model; - chan->erl = erl; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int16_t channel_model(channel_model_state_t *chan, int16_t rout, int16_t sgen) -{ - int16_t echo; - int16_t sin; - - /* Channel modelling is merely simulating the effects of A-law or u-law distortion - and using one of the echo models from G.168. Simulating the codec is very important, - as this is usually the limiting factor in how much echo reduction is achieved. */ - - /* The far end signal will have been through codec munging. */ - switch (chan->munging_codec) - { - case G711_ALAW: - sgen = alaw_to_linear(linear_to_alaw(sgen)); - break; - case G711_ULAW: - sgen = ulaw_to_linear(linear_to_ulaw(sgen)); - break; - } - - /* The local tx signal will usually have gone through codec munging before - it reached the line's analogue area, where the echo occurs. */ - switch (chan->munging_codec) - { - case G711_ALAW: - rout = alaw_to_linear(linear_to_alaw(rout)); - break; - case G711_ULAW: - rout = ulaw_to_linear(linear_to_ulaw(rout)); - break; - } - /* Now we need to model the echo. We only model a single analogue segment, as per - the G.168 spec. However, there will generally be near end and far end analogue/echoey - segments in the real world, unless an end is purely digital. */ - echo = fir32(&chan->impulse, rout*chan->gain); - sin = sat_add16(echo, sgen); - - /* This mixed echo and far end signal will have been through codec munging - when it came back into the digital network. */ - switch (chan->munging_codec) - { - case G711_ALAW: - sin = alaw_to_linear(linear_to_alaw(sin)); - break; - case G711_ULAW: - sin = ulaw_to_linear(linear_to_ulaw(sin)); - break; - } - return sin; -} -/*- End of function --------------------------------------------------------*/ - -static void write_log_files(int16_t rout, int16_t sin) -{ -#if 0 - fprintf(flevel, "%f\t%f\t%f\t%f\n", LRin, LSin, LSout, LSgen); - fprintf(fdump, "%d %d %d", ctx->tx, ctx->rx, ctx->clean); - fprintf(fdump, - " %d %d %d %d %d %d %d %d %d %d\n", - ctx->clean_nlp, - ctx->Ltx, - ctx->Lrx, - ctx->Lclean, - (ctx->nonupdate_dwell > 0), - ctx->adapt, - ctx->Lclean_bg, - ctx->Pstates, - ctx->Lbgn_upper, - ctx->Lbgn); -#endif -} -/*- End of function --------------------------------------------------------*/ - -static int16_t silence(void) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int16_t local_css_signal(void) -{ - return signal_amp(&local_css); -} -/*- End of function --------------------------------------------------------*/ - -static int16_t far_css_signal(void) -{ - return signal_amp(&far_css); -} -/*- End of function --------------------------------------------------------*/ - -static int16_t local_noise_signal(void) -{ - return awgn(&local_noise_source); -} -/*- End of function --------------------------------------------------------*/ - -static int16_t far_noise_signal(void) -{ - return awgn(&far_noise_source); -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -static int16_t local_hoth_noise_signal(void) -{ - static float hoth_noise = 0.0; - - hoth_noise = hoth_noise*0.625 + awgn(&local_noise_source)*0.375; - return (int16_t) hoth_noise; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static int16_t far_hoth_noise_signal(void) -{ - static float hoth_noise = 0.0; - - hoth_noise = hoth_noise*0.625 + awgn(&far_noise_source)*0.375; - return (int16_t) hoth_noise; -} -/*- End of function --------------------------------------------------------*/ - -static void run_test(echo_can_state_t *ctx, int16_t (*tx_source)(void), int16_t (*rx_source)(void), int period) -{ - int i; - int16_t rin; - int16_t rout; - int16_t sin; - int16_t sout; - int16_t sgen; - int outframes; - - for (i = 0; i < period*SAMPLE_RATE/1000; i++) - { - rin = tx_source(); - sgen = rx_source(); - - rout = echo_can_hpf_tx(ctx, rin); - sin = channel_model(&chan_model, rout, sgen); - sout = echo_can_update(ctx, rout, sin); - - level_measurements_update(rin, sin, rout, sout, sgen); - //residue = 100.0f*pp1/pp2; - //put_residue(residue); - - //put_residue(clean - rx); -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); -#endif - result_sound[result_cur++] = rin; - result_sound[result_cur++] = sgen; - result_sound[result_cur++] = sin; - result_sound[result_cur++] = rout; - result_sound[result_cur++] = sout; - result_sound[result_cur++] = sout - sgen; - result_sound[result_cur++] = 0; // TODO: insert the EC's internal status here - if (result_cur >= RESULT_CHANNELS*SAMPLE_RATE) - { - outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS); - if (outframes != result_cur/RESULT_CHANNELS) - { - fprintf(stderr, " Error writing result sound\n"); - exit(2); - } - result_cur = 0; - } - } -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); -#endif - if (result_cur >= 0) - { - outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS); - if (outframes != result_cur/RESULT_CHANNELS) - { - fprintf(stderr, " Error writing result sound\n"); - exit(2); - } - result_cur = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void print_test_title(const char *title) -{ - if (quiet == false) - printf("%s", title); -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_sanity(void) -{ - echo_can_state_t *ctx; - int i; - int16_t rx; - int16_t tx; - int16_t clean; - int far_tx; - //int16_t far_sound[SAMPLE_RATE]; - int16_t result_sound[64000]; - int result_cur; - int outframes; - //int local_cur; - //int far_cur; - //int32_t coeffs[200][128]; - //int coeff_index; - - print_test_title("Performing basic sanity test\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - //local_cur = 0; - //far_cur = 0; - result_cur = 0; - - echo_can_flush(ctx); - /* Converge the canceller */ - signal_restart(&local_css, 0.0f); - run_test(ctx, silence, silence, 200); - run_test(ctx, local_css_signal, silence, 5000); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CNG); - run_test(ctx, local_css_signal, silence, 5000); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - for (i = 0; i < SAMPLE_RATE*10; i++) - { - tx = local_css_signal(); -#if 0 - if ((i/10000)%10 == 9) - { - /* Inject a burst of far sound */ - if (far_cur >= far_max) - { - far_max = sf_readf_short(farhandle, far_sound, SAMPLE_RATE); - if (far_max < 0) - { - fprintf(stderr, " Error reading far sound\n"); - exit(2); - } - if (far_max == 0) - break; - far_cur = 0; - } - far_tx = far_sound[far_cur++]; - } - else - { - far_tx = 0; - } -#else - //far_sound[0] = 0; - far_tx = 0; -#endif - rx = channel_model(&chan_model, tx, far_tx); - //rx += awgn(&far_noise_source); - //tx += awgn(&far_noise_source); - clean = echo_can_update(ctx, tx, rx); - -#if defined(XYZZY) - if (i%SAMPLE_RATE == 0) - { - if (coeff_index < 200) - { - for (j = 0; j < ctx->taps; j++) - coeffs[coeff_index][j] = ctx->fir_taps32[j]; - coeff_index++; - } - } -#endif - result_sound[result_cur++] = tx; - result_sound[result_cur++] = rx; - result_sound[result_cur++] = clean - far_tx; - //result_sound[result_cur++] = ctx->tx_power[2]; - //result_sound[result_cur++] = ctx->tx_power[1]; - ////result_sound[result_cur++] = (ctx->tx_power[1] > 64) ? SAMPLE_RATE : -SAMPLE_RATE; - //result_sound[result_cur++] = ctx->tap_set*SAMPLE_RATE; - //result_sound[result_cur++] = (ctx->nonupdate_dwell > 0) ? SAMPLE_RATE : -SAMPLE_RATE; - //result_sound[result_cur++] = ctx->latest_correction >> 8; - //result_sound[result_cur++] = level_measurement_device(tx)/(16.0*65536.0); - //result_sound[result_cur++] = level_measurement_device(tx)/4096.0; - ////result_sound[result_cur++] = (ctx->tx_power[1] > ctx->rx_power[0]) ? SAMPLE_RATE : -SAMPLE_RATE; - //result_sound[result_cur++] = (ctx->tx_power[1] > ctx->rx_power[0]) ? SAMPLE_RATE : -SAMPLE_RATE; - //result_sound[result_cur++] = (ctx->narrowband_score)*5; // ? SAMPLE_RATE : -SAMPLE_RATE; - //result_sound[result_cur++] = ctx->tap_rotate_counter*10; - ////result_sound[result_cur++] = ctx->vad; - - put_residue(clean - far_tx); - if (result_cur >= RESULT_CHANNELS*SAMPLE_RATE) - { - outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS); - if (outframes != result_cur/RESULT_CHANNELS) - { - fprintf(stderr, " Error writing result sound\n"); - exit(2); - } - result_cur = 0; - } - } - if (result_cur > 0) - { - outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS); - if (outframes != result_cur/RESULT_CHANNELS) - { - fprintf(stderr, " Error writing result sound\n"); - exit(2); - } - } -#if defined(XYZZY) - for (j = 0; j < ctx->taps; j++) - { - for (i = 0; i < coeff_index; i++) - fprintf(stderr, "%d ", coeffs[i][j]); - fprintf(stderr, "\n"); - } -#endif - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_2a(void) -{ - echo_can_state_t *ctx; - - /* Test 2 - Convergence and steady state residual and returned echo level test */ - /* Test 2A - Convergence and reconvergence test with NLP enabled */ - print_test_title("Performing test 2A - Convergence and reconvergence test with NLP enabled\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP); - - /* Test 2A (a) - Convergence test with NLP enabled */ - - /* Converge the canceller. */ - run_test(ctx, silence, silence, 200); - signal_restart(&local_css, 0.0f); - run_test(ctx, local_css_signal, silence, 1000); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 9000); - print_results(); - if (level_measurement_device_get_peak(sout_power_meter) > -65.0f) - printf("Test failed\n"); - else - printf("Test passed\n"); - - /* Test 2A (b) - Reconvergence test with NLP enabled */ - - /* Make an abrupt change of channel characteristic, to another of the channel echo models. */ - if (channel_model_create(&chan_model, supp_line_model_no, erl, munger)) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - signal_restart(&local_css, 0.0f); - run_test(ctx, local_css_signal, silence, 1000); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 9000); - print_results(); - if (level_measurement_device_get_peak(sout_power_meter) > -65.0f) - printf("Test failed\n"); - else - printf("Test passed\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_2b(void) -{ - echo_can_state_t *ctx; - - /* Test 2 - Convergence and steady state residual and returned echo level test */ - /* Test 2B - Convergence and reconverge with NLP disabled */ - print_test_title("Performing test 2B - Convergence and reconverge with NLP disabled\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - signal_restart(&local_css, 0.0f); - - /* Test 2B (a) - Convergence test with NLP disabled */ - - /* Converge the canceller */ - run_test(ctx, silence, silence, 200); - run_test(ctx, local_css_signal, silence, 1000); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 9000); - print_results(); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 170000); - print_results(); - if (level_measurement_device_get_peak(sout_power_meter) > -65.0) - printf("Test failed\n"); - else - printf("Test passed\n"); - - /* Test 2B (b) - Reconvergence test with NLP disabled */ - - /* Make an abrupt change of channel characteristic, to another of the channel echo models. */ - if (channel_model_create(&chan_model, supp_line_model_no, erl, munger)) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - run_test(ctx, local_css_signal, silence, 1000); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 9000); - print_results(); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 170000); - print_results(); - if (level_measurement_device_get_peak(sout_power_meter) > -65.0) - printf("Test failed\n"); - else - printf("Test passed\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_2ca(void) -{ - echo_can_state_t *ctx; - - /* Test 2 - Convergence and steady state residual and returned echo level test */ - /* Test 2C(a) - Convergence with background noise present */ - print_test_title("Performing test 2C(a) - Convergence with background noise present\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - awgn_init_dbm0(&far_noise_source, 7162534, -50.0f); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - /* Converge a canceller */ - signal_restart(&local_css, 0.0f); - run_test(ctx, silence, silence, 200); - - awgn_init_dbm0(&far_noise_source, 7162534, -40.0f); - run_test(ctx, local_css_signal, far_hoth_noise_signal, 5000); - - /* Now freeze adaption, and measure the echo. */ - echo_can_adaption_mode(ctx, 0); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 5000); - print_results(); - if (level_measurement_device_get_peak(sout_power_meter) > level_measurement_device_get_peak(sgen_power_meter)) - printf("Test failed\n"); - else - printf("Test passed\n"); - - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_3a(void) -{ - echo_can_state_t *ctx; - - /* Test 3 - Performance under double talk conditions */ - /* Test 3A - Double talk test with low cancelled-end levels */ - print_test_title("Performing test 3A - Double talk test with low cancelled-end levels\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - run_test(ctx, silence, silence, 200); - signal_restart(&local_css, 0.0f); - signal_restart(&far_css, -20.0f); - - /* Apply double talk, with a weak far end signal */ - run_test(ctx, local_css_signal, far_css_signal, 5000); - - /* Now freeze adaption. */ - echo_can_adaption_mode(ctx, 0); - run_test(ctx, local_css_signal, silence, 500); - - /* Now measure the echo */ - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 5000); - print_results(); - if (level_measurement_device_get_peak(sout_power_meter) > level_measurement_device_get_peak(sgen_power_meter)) - printf("Test failed\n"); - else - printf("Test passed\n"); - - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_3ba(void) -{ - echo_can_state_t *ctx; - - /* Test 3 - Performance under double talk conditions */ - /* Test 3B(a) - Double talk stability test with high cancelled-end levels */ - print_test_title("Performing test 3B(b) - Double talk stability test with high cancelled-end levels\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - run_test(ctx, silence, silence, 200); - signal_restart(&local_css, 0.0f); - signal_restart(&far_css, 0.0f); - - /* Converge the canceller */ - run_test(ctx, local_css_signal, silence, 5000); - - /* Apply double talk */ - run_test(ctx, local_css_signal, far_css_signal, 5000); - - /* Now freeze adaption. */ - echo_can_adaption_mode(ctx, 0); - run_test(ctx, local_css_signal, far_css_signal, 1000); - - /* Turn off the double talk. */ - run_test(ctx, local_css_signal, silence, 500); - - /* Now measure the echo */ - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 5000); - print_results(); - - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_3bb(void) -{ - echo_can_state_t *ctx; - - /* Test 3 - Performance under double talk conditions */ - /* Test 3B(b) - Double talk stability test with low cancelled-end levels */ - print_test_title("Performing test 3B(b) - Double talk stability test with low cancelled-end levels\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - run_test(ctx, silence, silence, 200); - signal_restart(&local_css, 0.0f); - signal_restart(&far_css, -15.0f); - - /* Converge the canceller */ - run_test(ctx, local_css_signal, silence, 5000); - - /* Apply double talk */ - run_test(ctx, local_css_signal, far_css_signal, 5000); - - /* Now freeze adaption. */ - echo_can_adaption_mode(ctx, 0); - run_test(ctx, local_css_signal, silence, 1000); - - /* Turn off the double talk. */ - run_test(ctx, local_css_signal, silence, 500); - - /* Now measure the echo */ - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 5000); - print_results(); - - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_3c(void) -{ - echo_can_state_t *ctx; - - /* Test 3 - Performance under double talk conditions */ - /* Test 3C - Double talk test with simulated conversation */ - print_test_title("Performing test 3C - Double talk test with simulated conversation\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - run_test(ctx, silence, silence, 200); - - signal_restart(&local_css, 0.0f); - signal_restart(&far_css, -15.0f); - - /* Apply double talk */ - run_test(ctx, local_css_signal, far_css_signal, 5600); - - /* Stop the far signal, and measure the echo. */ - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 1400); - print_results(); - - /* Continue measuring the resulting echo */ - run_test(ctx, local_css_signal, silence, 5000); - - /* Reapply double talk */ - signal_restart(&far_css, 0.0f); - run_test(ctx, local_css_signal, far_css_signal, 5600); - - /* Now the far signal only */ - run_test(ctx, silence, far_css_signal, 5600); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_4(void) -{ - echo_can_state_t *ctx; - - /* Test 4 - Leak rate test */ - print_test_title("Performing test 4 - Leak rate test\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - run_test(ctx, silence, silence, 200); - - /* Converge the canceller */ - signal_restart(&local_css, 0.0f); - run_test(ctx, local_css_signal, silence, 5000); - - /* Put 2 minutes of silence through it */ - run_test(ctx, silence, silence, 120000); - - /* Now freeze it, and check if it is still well adapted. */ - echo_can_adaption_mode(ctx, 0); - level_measurements_reset_peaks(); - run_test(ctx, local_css_signal, silence, 5000); - print_results(); - - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_5(void) -{ - echo_can_state_t *ctx; - - /* Test 5 - Infinite return loss convergence test */ - print_test_title("Performing test 5 - Infinite return loss convergence test\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - /* Converge the canceller */ - signal_restart(&local_css, 0.0f); - run_test(ctx, local_css_signal, silence, 5000); - - /* Now stop echoing, and see we don't do anything unpleasant as the - echo path is open looped. */ - run_test(ctx, local_css_signal, silence, 5000); - print_results(); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_6(void) -{ - echo_can_state_t *ctx; - int i; - int j; - int k; - int16_t rx; - int16_t tx; - int16_t clean; - tone_gen_descriptor_t tone_desc; - tone_gen_state_t tone_state; - int16_t local_sound[40000]; - - /* Test 6 - Non-divergence on narrow-band signals */ - print_test_title("Performing test 6 - Non-divergence on narrow-band signals\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - - /* Converge the canceller */ - signal_restart(&local_css, 0.0f); - run_test(ctx, local_css_signal, silence, 5000); - - /* Now put 5s bursts of a list of tones through the converged canceller, and check - that nothing unpleasant happens. */ - for (k = 0; tones_6_4_2_7[k][0]; k++) - { - tone_gen_descriptor_init(&tone_desc, - tones_6_4_2_7[k][0], - -11, - tones_6_4_2_7[k][1], - -9, - 1, - 0, - 0, - 0, - 1); - tone_gen_init(&tone_state, &tone_desc); - j = 0; - for (i = 0; i < 5; i++) - { - tone_gen(&tone_state, local_sound, SAMPLE_RATE); - for (j = 0; j < SAMPLE_RATE; j++) - { - tx = local_sound[j]; - rx = channel_model(&chan_model, tx, 0); - clean = echo_can_update(ctx, tx, rx); - put_residue(clean); - } -#if defined(ENABLE_GUI) - if (use_gui) - { - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); - echo_can_monitor_update_display(); - usleep(100000); - } -#endif - } - } -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); -#endif - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_7(void) -{ - echo_can_state_t *ctx; - int i; - int j; - int16_t rx; - int16_t tx; - int16_t clean; - tone_gen_descriptor_t tone_desc; - tone_gen_state_t tone_state; - int16_t local_sound[40000]; - - /* Test 7 - Stability */ - print_test_title("Performing test 7 - Stability\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - /* Put tones through an unconverged canceller, and check nothing unpleasant - happens. */ - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); - tone_gen_descriptor_init(&tone_desc, - tones_6_4_2_7[0][0], - -11, - tones_6_4_2_7[0][1], - -9, - 1, - 0, - 0, - 0, - 1); - tone_gen_init(&tone_state, &tone_desc); - j = 0; - for (i = 0; i < 120; i++) - { - tone_gen(&tone_state, local_sound, SAMPLE_RATE); - for (j = 0; j < SAMPLE_RATE; j++) - { - tx = local_sound[j]; - rx = channel_model(&chan_model, tx, 0); - clean = echo_can_update(ctx, tx, rx); - put_residue(clean); - } -#if defined(ENABLE_GUI) - if (use_gui) - { - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); - echo_can_monitor_update_display(); - usleep(100000); - } -#endif - } -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); -#endif - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_8(void) -{ - echo_can_state_t *ctx; - - /* Test 8 - Non-convergence on No 5, 6, and 7 in-band signalling */ - print_test_title("Performing test 8 - Non-convergence on No 5, 6, and 7 in-band signalling\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 8 not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_9(void) -{ - echo_can_state_t *ctx; - awgn_state_t local_noise_source; - awgn_state_t far_noise_source; - - /* Test 9 - Comfort noise test */ - print_test_title("Performing test 9 - Comfort noise test\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - awgn_init_dbm0(&far_noise_source, 7162534, -50.0f); - - echo_can_flush(ctx); - echo_can_adaption_mode(ctx, - ECHO_CAN_USE_ADAPTION - | ECHO_CAN_USE_NLP - | ECHO_CAN_USE_CNG); - - /* Test 9 part 1 - matching */ - /* Converge the canceller */ - signal_restart(&local_css, 0.0f); - run_test(ctx, local_css_signal, silence, 5000); - - echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CNG); - awgn_init_dbm0(&far_noise_source, 7162534, -45.0f); - run_test(ctx, silence, far_noise_signal, 30000); - - awgn_init_dbm0(&local_noise_source, 1234567, -10.0f); - run_test(ctx, local_noise_signal, far_noise_signal, 2000); - - /* Test 9 part 2 - adjust down */ - awgn_init_dbm0(&far_noise_source, 7162534, -55.0f); - run_test(ctx, silence, far_noise_signal, 10000); - run_test(ctx, local_noise_signal, far_noise_signal, 2000); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_10a(void) -{ - echo_can_state_t *ctx; - - /* Test 10 - FAX test during call establishment phase */ - /* Test 10A - Canceller operation on the calling station side */ - print_test_title("Performing test 10A - Canceller operation on the calling station side\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 10A not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_10b(void) -{ - echo_can_state_t *ctx; - - /* Test 10 - FAX test during call establishment phase */ - /* Test 10B - Canceller operation on the called station side */ - print_test_title("Performing test 10B - Canceller operation on the called station side\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 10B not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_10c(void) -{ - echo_can_state_t *ctx; - - /* Test 10 - FAX test during call establishment phase */ - /* Test 10C - Canceller operation on the calling station side during page - transmission and page breaks (for further study) */ - print_test_title("Performing test 10C - Canceller operation on the calling station side during page\n" - "transmission and page breaks (for further study)\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 10C not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_11(void) -{ - echo_can_state_t *ctx; - - /* Test 11 - Tandem echo canceller test (for further study) */ - print_test_title("Performing test 11 - Tandem echo canceller test (for further study)\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 11 not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_12(void) -{ - echo_can_state_t *ctx; - - /* Test 12 - Residual acoustic echo test (for further study) */ - print_test_title("Performing test 12 - Residual acoustic echo test (for further study)\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 12 not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_13(void) -{ - echo_can_state_t *ctx; - - /* Test 13 - Performance with ITU-T low-bit rate coders in echo path - (Optional, under study) */ - print_test_title("Performing test 13 - Performance with ITU-T low-bit rate coders in echo path (Optional, under study)\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 13 not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_14(void) -{ - echo_can_state_t *ctx; - - /* Test 14 - Performance with V-series low-speed data modems */ - print_test_title("Performing test 14 - Performance with V-series low-speed data modems\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 14 not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_test_15(void) -{ - echo_can_state_t *ctx; - - /* Test 15 - PCM offset test (Optional) */ - print_test_title("Performing test 15 - PCM offset test (Optional)\n"); - ctx = echo_can_init(TEST_EC_TAPS, 0); - - fprintf(stderr, "Test 15 not yet implemented\n"); - - echo_can_free(ctx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int match_test_name(const char *name) -{ - const struct - { - const char *name; - int (*func)(void); - } tests[] = - { - {"sanity", perform_test_sanity}, - {"2a", perform_test_2a}, - {"2b", perform_test_2b}, - {"2ca", perform_test_2ca}, - {"3a", perform_test_3a}, - {"3ba", perform_test_3ba}, - {"3bb", perform_test_3bb}, - {"3c", perform_test_3c}, - {"4", perform_test_4}, - {"5", perform_test_5}, - {"6", perform_test_6}, - {"7", perform_test_7}, - {"8", perform_test_8}, - {"9", perform_test_9}, - {"10a", perform_test_10a}, - {"10b", perform_test_10b}, - {"10c", perform_test_10c}, - {"11", perform_test_11}, - {"12", perform_test_12}, - {"13", perform_test_13}, - {"14", perform_test_14}, - {"15", perform_test_15}, - {NULL, NULL} - }; - int i; - - for (i = 0; tests[i].name; i++) - { - if (strcasecmp(name, tests[i].name) == 0) - { - test_name = name; - tests[i].func(); - return 0; - } - } - printf("Unknown test name '%s' specified. The known test names are ", name); - for (i = 0; tests[i].name; i++) - { - printf("%s", tests[i].name); - if (tests[i + 1].name) - printf(", "); - } - printf("\n"); - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static void simulate_ec(char *argv[], int two_channel_file, int mode) -{ - echo_can_state_t *ctx; - SNDFILE *txfile; - SNDFILE *rxfile; - SNDFILE *rxtxfile; - SNDFILE *ecfile; - int ntx; - int nrx; - int nec; - int16_t buf[2]; - int16_t rin; - int16_t rout; - int16_t sin; - int16_t sout; - - mode |= ECHO_CAN_USE_ADAPTION; - txfile = NULL; - rxfile = NULL; - rxtxfile = NULL; - ecfile = NULL; - if (two_channel_file) - { - txfile = sf_open_telephony_read(argv[0], 1); - rxfile = sf_open_telephony_read(argv[1], 1); - ecfile = sf_open_telephony_write(argv[2], 1); - } - else - { - rxtxfile = sf_open_telephony_read(argv[0], 2); - ecfile = sf_open_telephony_write(argv[1], 1); - } - - ctx = echo_can_init(TEST_EC_TAPS, 0); - echo_can_adaption_mode(ctx, mode); - do - { - if (two_channel_file) - { - if ((ntx = sf_readf_short(rxtxfile, buf, 1)) < 0) - { - fprintf(stderr, " Error reading tx sound file\n"); - exit(2); - } - rin = buf[0]; - sin = buf[1]; - nrx = ntx; - } - else - { - if ((ntx = sf_readf_short(txfile, &rin, 1)) < 0) - { - fprintf(stderr, " Error reading tx sound file\n"); - exit(2); - } - if ((nrx = sf_readf_short(rxfile, &sin, 1)) < 0) - { - fprintf(stderr, " Error reading rx sound file\n"); - exit(2); - } - } - rout = echo_can_hpf_tx(ctx, rin); - sout = echo_can_update(ctx, rout, sin); - - if ((nec = sf_writef_short(ecfile, &sout, 1)) != 1) - { - fprintf(stderr, " Error writing ec sound file\n"); - exit(2); - } - level_measurements_update(rin, sin, rout, sout, 0); - write_log_files(rin, sin); -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS); -#endif - } - while (ntx && nrx); - dump_ec_state(ctx); - - echo_can_free(ctx); - - if (two_channel_file) - { - sf_close_telephony(rxtxfile); - } - else - { - sf_close_telephony(txfile); - sf_close_telephony(rxfile); - } - sf_close_telephony(ecfile); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int i; - time_t now; - int simulate; - 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; - munger = -1; - two_channel_file = false; - erl = -12.0f; - - while ((opt = getopt(argc, argv, "2ace:ghm:M:su")) != -1) - { - switch (opt) - { - case '2': - two_channel_file = true; - break; - case 'a': - munger = G711_ALAW; - break; - case 'c': - cng = true; - break; - case 'e': - /* Allow for ERL being entered as x or -x */ - erl = -fabs(atof(optarg)); - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'h': - hpf = true; - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'M': - supp_line_model_no = atoi(optarg); - break; - case 's': - simulate = true; - break; - case 'u': - munger = G711_ULAW; - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - -#if defined(ENABLE_GUI) - if (use_gui) - start_echo_can_monitor(TEST_EC_TAPS); -#endif - if (simulate) - { - /* Process a pair of transmitted and received audio files, and produce - an echo cancelled audio file. */ - if (argc < ((two_channel_file) ? 2 : 3)) - { - printf("not enough arguments for a simulation\n"); - exit(2); - } - mode = ECHO_CAN_USE_NLP; - mode |= ((cng) ? ECHO_CAN_USE_CNG : ECHO_CAN_USE_CLIP); - if (hpf) - { - mode |= ECHO_CAN_USE_TX_HPF; - mode |= ECHO_CAN_USE_RX_HPF; - } - simulate_ec(argv, two_channel_file, mode); - } - else - { - /* Run some G.168 tests */ -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_line_model_update(chan_model.impulse.coeffs, chan_model.impulse.taps); -#endif - signal_load(&local_css, "sound_c1_8k.wav"); - signal_load(&far_css, "sound_c3_8k.wav"); - - if ((residue_handle = sf_open_telephony_write(RESIDUE_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Failed to open '%s'\n", RESIDUE_FILE_NAME); - exit(2); - } - if (argc <= 0) - { - printf("No tests specified\n"); - } - else - { - time(&now); - if ((result_handle = sf_open_telephony_write("echo_tests_result.wav", RESULT_CHANNELS)) == NULL) - { - fprintf(stderr, " Failed to open result file\n"); - exit(2); - } - result_cur = 0; - level_measurements_create(0); - for (i = 0; i < argc; i++) - { - if (channel_model_create(&chan_model, line_model_no, erl, munger)) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - match_test_name(argv[i]); - } - if (sf_close_telephony(result_handle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", "result_sound.wav"); - exit(2); - } - printf("Run time %lds\n", time(NULL) - now); - } - signal_free(&local_css); - signal_free(&far_css); - if (sf_close_telephony(residue_handle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", RESIDUE_FILE_NAME); - exit(2); - } - } -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_wait_to_end(); -#endif - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fax_decode.c b/libs/spandsp/tests/fax_decode.c deleted file mode 100644 index 9f6a474b0d..0000000000 --- a/libs/spandsp/tests/fax_decode.c +++ /dev/null @@ -1,813 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_decode.c - a simple FAX audio decoder - * - * 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 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. - */ - -/*! \page fax_decode_page FAX decoder -\section fax_decode_page_sec_1 What does it do? -???. - -\section fax_decode_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define SAMPLES_PER_CHUNK 160 - -#define DISBIT1 0x01 -#define DISBIT2 0x02 -#define DISBIT3 0x04 -#define DISBIT4 0x08 -#define DISBIT5 0x10 -#define DISBIT6 0x20 -#define DISBIT7 0x40 -#define DISBIT8 0x80 - -enum -{ - FAX_NONE, - FAX_V27TER_RX, - FAX_V29_RX, - FAX_V17_RX -}; - -static const struct -{ - int bit_rate; - int modem_type; - int which; - uint8_t dcs_code; -} fallback_sequence[] = -{ - {14400, T30_MODEM_V17, T30_SUPPORT_V17, DISBIT6}, - {12000, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT4)}, - { 9600, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT3)}, - { 9600, T30_MODEM_V29, T30_SUPPORT_V29, DISBIT3}, - { 7200, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT4 | DISBIT3)}, - { 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} -}; - -bool decode_test = false; -int rx_bits = 0; - -t30_state_t t30_dummy; -t4_rx_state_t t4_rx_state; -bool t4_up = false; - -hdlc_rx_state_t hdlcrx; - -int fast_trained = FAX_NONE; - -uint8_t ecm_data[256][260]; -int16_t ecm_len[256]; - -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; -bool error_correcting_mode = false; -int current_fallback = 0; -bool end_of_page_detected = false; - -static void decode_20digit_msg(const uint8_t *pkt, int len) -{ - int p; - int k; - char msg[T30_MAX_IDENT_LEN + 1]; - - if (len > T30_MAX_IDENT_LEN + 3) - { - fprintf(stderr, "XXX %d %d\n", len, T30_MAX_IDENT_LEN + 1); - msg[0] = '\0'; - return; - } - /*endif*/ - pkt += 2; - p = len - 2; - /* Strip trailing spaces */ - while (p > 1 && pkt[p - 1] == ' ') - p--; - /*endwhile*/ - /* The string is actually backwards in the message */ - k = 0; - while (p > 1) - msg[k++] = pkt[--p]; - /*endwhile*/ - msg[k] = '\0'; - fprintf(stderr, "%s is: \"%s\"\n", t30_frametype(pkt[0]), msg); -} -/*- End of function --------------------------------------------------------*/ - -static void print_frame(const char *io, const uint8_t *fr, int frlen) -{ - int i; - int type; - const char *country; - const char *vendor; - const char *model; - - if (frlen == 0) - { - return; - } - /*endif*/ - fprintf(stderr, "%s %s:", io, t30_frametype(fr[2])); - for (i = 2; i < frlen; i++) - { - fprintf(stderr, " %02x", fr[i]); - } - /*endfor*/ - fprintf(stderr, "\n"); - type = fr[2] & 0xFE; - if (type == T30_DIS || type == T30_DTC || type == T30_DCS) - { - t30_decode_dis_dtc_dcs(&t30_dummy, fr, frlen); - } - /*endif*/ - if (type == T30_CSI || type == T30_TSI || type == T30_PWD || type == T30_SEP || type == T30_SUB || type == T30_SID) - { - decode_20digit_msg(fr, frlen); - } - /*endif*/ - if (type == T30_NSF || type == T30_NSS || type == T30_NSC) - { - if (t35_decode(&fr[3], frlen - 3, &country, &vendor, &model)) - { - if (country) - fprintf(stderr, "The remote was made in '%s'\n", country); - /*endif*/ - if (vendor) - fprintf(stderr, "The remote was made by '%s'\n", vendor); - /*endif*/ - if (model) - fprintf(stderr, "The remote is a '%s'\n", model); - /*endif*/ - } - /*endif*/ - if (type == T30_NSS || type == T30_NSC) - { - fprintf(stderr, "WARNING: The FAX machines may be switching into a proprietary mode, which this software cannot decode\n"); - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -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; - /*endif*/ - } - /*endfor*/ - if (fallback_sequence[i].bit_rate == 0) - return -1; - /*endif*/ - return i; -} -/*- End of function --------------------------------------------------------*/ - -static int check_rx_dcs(const uint8_t *msg, int len) -{ - static const int widths[3][4] = - { - { 864, 1024, 1216, -1}, /* R4 resolution - no longer used in recent versions of T.30 */ - {1728, 2048, 2432, -1}, /* R8 resolution */ - {3456, 4096, 4864, -1} /* R16 resolution */ - }; - uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN]; - - /* Check DCS frame from remote */ - if (len < 6) - { - printf("Short DCS frame\n"); - return -1; - } - /*endif*/ - - /* 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); - /*endif*/ - } - /*endif*/ - - octets_per_ecm_frame = (dcs_frame[6] & DISBIT4) ? 256 : 64; - - if ((dcs_frame[8] & DISBIT1)) - y_resolution = T4_Y_RESOLUTION_SUPERFINE; - else if (dcs_frame[4] & DISBIT7) - y_resolution = T4_Y_RESOLUTION_FINE; - else - y_resolution = T4_Y_RESOLUTION_STANDARD; - /*endif*/ - - if ((dcs_frame[8] & DISBIT3)) - { - x_resolution = T4_X_RESOLUTION_R16; - y_resolution = T4_Y_RESOLUTION_SUPERFINE; - } - else - { - x_resolution = T4_X_RESOLUTION_R8; - } - /*endif*/ - - image_width = widths[(dcs_frame[8] & DISBIT3) ? 2 : 1][dcs_frame[5] & (DISBIT2 | DISBIT1)]; - - /* Check which compression we will use. */ - if ((dcs_frame[12] & DISBIT7)) - line_encoding = T4_COMPRESSION_T85_L0; - else if ((dcs_frame[12] & DISBIT6)) - line_encoding = T4_COMPRESSION_T85; - else if ((dcs_frame[6] & DISBIT7)) - line_encoding = T4_COMPRESSION_T6; - else if ((dcs_frame[4] & DISBIT8)) - line_encoding = T4_COMPRESSION_T4_2D; - else - line_encoding = T4_COMPRESSION_T4_1D; - /*endif*/ - fprintf(stderr, "Selected compression %d\n", line_encoding); - - if ((current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0) - printf("Remote asked for a modem standard we do not support\n"); - /*endif*/ - error_correcting_mode = ((dcs_frame[6] & DISBIT3) != 0); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) -{ - int type; - int frame_no; - int i; - - if (len < 0) - { - /* Special conditions */ - fprintf(stderr, "HDLC status is %s (%d)\n", signal_status_to_str(len), len); - return; - } - /*endif*/ - - if (ok) - { - if (msg[0] != 0xFF || !(msg[1] == 0x03 || msg[1] == 0x13)) - { - fprintf(stderr, "Bad frame header - %02x %02x\n", msg[0], msg[1]); - return; - } - /*endif*/ - print_frame("HDLC: ", msg, len); - type = msg[2] & 0xFE; - switch (type) - { - case T4_FCD: - if (len <= 4 + 256) - { - frame_no = msg[3]; - /* Just store the actual image data, and record its length */ - memcpy(&ecm_data[frame_no][0], &msg[4], len - 4); - ecm_len[frame_no] = (int16_t) (len - 4); - } - /*endif*/ - break; - case T30_DCS: - check_rx_dcs(msg, len); - break; - } - /*endswitch*/ - } - else - { - fprintf(stderr, "Bad HDLC frame "); - for (i = 0; i < len; i++) - fprintf(stderr, " %02x", msg[i]); - /*endfor*/ - fprintf(stderr, "\n"); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void t4_begin(void) -{ - int i; - - //printf("Begin T.4 - %d %d %d %d\n", line_encoding, x_resolution, y_resolution, image_width); - t4_rx_set_rx_encoding(&t4_rx_state, line_encoding); - t4_rx_set_x_resolution(&t4_rx_state, x_resolution); - t4_rx_set_y_resolution(&t4_rx_state, y_resolution); - 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; - - for (i = 0; i < 256; i++) - ecm_len[i] = -1; - /*endfor*/ -} -/*- End of function --------------------------------------------------------*/ - -static void t4_end(void) -{ - t4_stats_t stats; - int i; - - if (!t4_up) - return; - /*endif*/ - if (error_correcting_mode) - { - for (i = 0; i < 256; i++) - { - if (ecm_len[i] > 0) - t4_rx_put(&t4_rx_state, ecm_data[i], ecm_len[i]); - /*endif*/ - fprintf(stderr, "%d", (ecm_len[i] <= 0) ? 0 : 1); - } - /*endfor*/ - fprintf(stderr, "\n"); - } - /*endif*/ - t4_rx_end_page(&t4_rx_state); - t4_rx_get_transfer_statistics(&t4_rx_state, &stats); - fprintf(stderr, "Pages = %d\n", stats.pages_transferred); - fprintf(stderr, "Image size = %dx%d\n", stats.width, stats.length); - 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; -} -/*- End of function --------------------------------------------------------*/ - -static void v21_put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - /* Special conditions */ - fprintf(stderr, "V.21 rx status is %s (%d)\n", signal_status_to_str(bit), bit); - switch (bit) - { - case SIG_STATUS_CARRIER_DOWN: - //t4_end(); - break; - } - /*endswitch*/ - return; - } - /*endif*/ - //fprintf(stderr, "V.21 Rx bit %d - %d\n", rx_bits++, bit); - if (fast_trained == FAX_NONE) - hdlc_rx_put_bit(&hdlcrx, bit); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void v17_put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - /* Special conditions */ - fprintf(stderr, "V.17 rx status is %s (%d)\n", signal_status_to_str(bit), bit); - switch (bit) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - fast_trained = FAX_V17_RX; - t4_begin(); - break; - case SIG_STATUS_CARRIER_DOWN: - t4_end(); - if (fast_trained == FAX_V17_RX) - fast_trained = FAX_NONE; - break; - } - /*endswitch*/ - return; - } - /*endif*/ - if (error_correcting_mode) - { - hdlc_rx_put_bit(&hdlcrx, bit); - } - else - { - if (t4_rx_put_bit(&t4_rx_state, bit)) - { - t4_end(); - if (!end_of_page_detected) - fprintf(stderr, "End of page detected\n"); - /*endif*/ - end_of_page_detected = true; - } - /*endif*/ - } - /*endif*/ - //printf("V.17 Rx bit %d - %d\n", rx_bits++, bit); -} -/*- End of function --------------------------------------------------------*/ - -static void v29_put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - /* Special conditions */ - fprintf(stderr, "V.29 rx status is %s (%d)\n", signal_status_to_str(bit), bit); - switch (bit) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - fast_trained = FAX_V29_RX; - t4_begin(); - break; - case SIG_STATUS_CARRIER_DOWN: - t4_end(); - if (fast_trained == FAX_V29_RX) - fast_trained = FAX_NONE; - break; - } - /*endswitch*/ - return; - } - /*endif*/ - if (error_correcting_mode) - { - hdlc_rx_put_bit(&hdlcrx, bit); - } - else - { - if (t4_rx_put_bit(&t4_rx_state, bit)) - { - t4_end(); - if (!end_of_page_detected) - fprintf(stderr, "End of page detected\n"); - end_of_page_detected = true; - } - /*endif*/ - } - /*endif*/ - //printf("V.29 Rx bit %d - %d\n", rx_bits++, bit); -} -/*- End of function --------------------------------------------------------*/ - -static void v27ter_put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - /* Special conditions */ - fprintf(stderr, "V.27ter rx status is %s (%d)\n", signal_status_to_str(bit), bit); - switch (bit) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - fast_trained = FAX_V27TER_RX; - t4_begin(); - break; - case SIG_STATUS_CARRIER_DOWN: - t4_end(); - if (fast_trained == FAX_V27TER_RX) - fast_trained = FAX_NONE; - break; - } - /*endswitch*/ - return; - } - /*endif*/ - if (error_correcting_mode) - { - hdlc_rx_put_bit(&hdlcrx, bit); - } - else - { - if (t4_rx_put_bit(&t4_rx_state, bit)) - { - t4_end(); - if (!end_of_page_detected) - fprintf(stderr, "End of page detected\n"); - end_of_page_detected = true; - } - /*endif*/ - } - /*endif*/ - //printf("V.27ter Rx bit %d - %d\n", rx_bits++, bit); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - fsk_rx_state_t *fsk; - v17_rx_state_t *v17; - v29_rx_state_t *v29; - v27ter_rx_state_t *v27ter_4800; - v27ter_rx_state_t *v27ter_2400; - int16_t amp[SAMPLES_PER_CHUNK]; - SNDFILE *inhandle; - SF_INFO info; - int len; - const char *filename; - logging_state_t *logging; - int opt; - bool t30_decode_reversed; - bool t30_decode; - int i; - unsigned int hex; - char buf[1024]; - uint8_t bytes[1024]; - - filename = "fax_samp.wav"; - t30_decode_reversed = false; - t30_decode = false; - while ((opt = getopt(argc, argv, "c:ertw:x:y:")) != -1) - { - switch (opt) - { - case 'c': - /* Force, for when there is no DCS to set this properly */ - if (strcmp(optarg, "T41D") == 0) - { - line_encoding = T4_COMPRESSION_T4_1D; - } - else if (strcmp(optarg, "T42D") == 0) - { - line_encoding = T4_COMPRESSION_T4_2D; - } - else if (strcmp(optarg, "T6") == 0) - { - line_encoding = T4_COMPRESSION_T6; - } - else if (strcmp(optarg, "T85") == 0) - { - line_encoding = T4_COMPRESSION_T85; - } -#if defined(SPANDSP_SUPPORT_T88) - else if (strcmp(optarg, "T88") == 0) - { - line_encoding = T4_COMPRESSION_T88; - } -#endif - else if (strcmp(optarg, "T81") == 0) - { - line_encoding = T4_COMPRESSION_T42_T81; - } - else if (strcmp(optarg, "T43") == 0) - { - line_encoding = T4_COMPRESSION_T43; - } -#if defined(SPANDSP_SUPPORT_T45) - else if (strcmp(optarg, "T45") == 0) - { - line_encoding = T4_COMPRESSION_T45; - } -#endif - else - { - printf("Unrecognised line compression.\n"); - exit(2); - } - /*endif*/ - break; - case 'e': - /* Force, for when there is no DCS to set this properly */ - error_correcting_mode = true; - break; - case 'r': - t30_decode_reversed = true; - break; - case 't': - t30_decode = true; - break; - case 'w': - /* Force, for when there is no DCS to set this properly */ - image_width = 1728; - break; - case 'x': - /* Force, for when there is no DCS to set this properly */ - if (strcmp(optarg, "R4") == 0) - { - x_resolution = T4_X_RESOLUTION_R4; - } - else if (strcmp(optarg, "R8") == 0) - { - x_resolution = T4_X_RESOLUTION_R8; - } - else if (strcmp(optarg, "R16") == 0) - { - x_resolution = T4_X_RESOLUTION_R16; - } - else - { - printf("Unrecognised X-resolution.\n"); - exit(2); - } - /*endif*/ - break; - case 'y': - /* Force, for when there is no DCS to set this properly */ - if (strcmp(optarg, "standard") == 0) - { - y_resolution = T4_Y_RESOLUTION_STANDARD; - } - else if (strcmp(optarg, "fine") == 0) - { - y_resolution = T4_Y_RESOLUTION_FINE; - } - else if (strcmp(optarg, "superfine") == 0) - { - y_resolution = T4_Y_RESOLUTION_SUPERFINE; - } - else - { - printf("Unrecognised Y-resolution.\n"); - exit(2); - } - /*endif*/ - break; - } - /*endswitch*/ - } - /*endwhile*/ - argc -= optind; - argv += optind; - - if (argc > 0) - filename = argv[0]; - /*endif*/ - - memset(&t30_dummy, 0, sizeof(t30_dummy)); - logging = t30_get_logging_state(&t30_dummy); - span_log_init(logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(logging, "T.30"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - - if (t30_decode) - { - /* Decode T.30 messages entered as a string of hex byte values in the form xx xx xx */ - while (fgets(buf, 1024, stdin)) - { - for (i = 0; i < 256; i++) - { - if (sscanf(&buf[3*i], "%x", &hex) != 1) - break; - /*endif*/ - if (t30_decode_reversed) - hex = bit_reverse8(hex); - /*endif*/ - bytes[i] = hex; - } - /*endfor*/ - print_frame("", bytes, i); - } - /*endwhile*/ - exit(0); - } - /*endif*/ - - memset(&info, 0, sizeof(info)); - if ((inhandle = sf_open(filename, SFM_READ, &info)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s' for reading\n", filename); - exit(2); - } - /*endif*/ - if (info.samplerate != SAMPLE_RATE) - { - fprintf(stderr, " Unexpected sample rate in audio file '%s'\n", filename); - exit(2); - } - /*endif*/ - if (info.channels != 1) - { - fprintf(stderr, " Unexpected number of channels in audio file '%s'\n", filename); - exit(2); - } - /*endif*/ - - 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); - //v29 = v29_rx_init(NULL, 7200, v29_put_bit, NULL); - v27ter_4800 = v27ter_rx_init(NULL, 4800, v27ter_put_bit, NULL); - v27ter_2400 = v27ter_rx_init(NULL, 2400, v27ter_put_bit, NULL); - - fsk_rx_signal_cutoff(fsk, -45.5); - v17_rx_signal_cutoff(v17, -45.5); - v29_rx_signal_cutoff(v29, -45.5); - v27ter_rx_signal_cutoff(v27ter_4800, -40.0); - v27ter_rx_signal_cutoff(v27ter_2400, -40.0); - -#if 1 - logging = v17_rx_get_logging_state(v17); - span_log_set_protocol(logging, "V.17"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - - logging = v29_rx_get_logging_state(v29); - span_log_set_protocol(logging, "V.29"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - - logging = v27ter_rx_get_logging_state(v27ter_4800); - span_log_set_protocol(logging, "V.27ter-4800"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - - logging = v27ter_rx_get_logging_state(v27ter_2400); - span_log_set_protocol(logging, "V.27ter-2400"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); -#endif - - if (t4_rx_init(&t4_rx_state, "fax_decode.tif", T4_COMPRESSION_T4_2D) == NULL) - { - fprintf(stderr, "Failed to init\n"); - exit(0); - } - /*endif*/ - - for (;;) - { - len = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK); - if (len < SAMPLES_PER_CHUNK) - break; - /*endif*/ - fsk_rx(fsk, amp, len); - v17_rx(v17, amp, len); - v29_rx(v29, amp, len); - v27ter_rx(v27ter_4800, amp, len); - v27ter_rx(v27ter_2400, amp, len); - - logging = t30_get_logging_state(&t30_dummy); - span_log_bump_samples(logging, len); - logging = v17_rx_get_logging_state(v17); - span_log_bump_samples(logging, len); - logging = v29_rx_get_logging_state(v29); - span_log_bump_samples(logging, len); - logging = v27ter_rx_get_logging_state(v27ter_4800); - span_log_bump_samples(logging, len); - logging = v27ter_rx_get_logging_state(v27ter_2400); - span_log_bump_samples(logging, len); - } - /*endfor*/ - t4_rx_release(&t4_rx_state); - - if (sf_close(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", filename); - exit(2); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fax_tester.c b/libs/spandsp/tests/fax_tester.c deleted file mode 100644 index 419fb705fa..0000000000 --- a/libs/spandsp/tests/fax_tester.c +++ /dev/null @@ -1,1909 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_tester.c - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#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 - -#if defined(HAVE_LIBXML_XMLMEMORY_H) -#include -#endif -#if defined(HAVE_LIBXML_PARSER_H) -#include -#endif -#if defined(HAVE_LIBXML_XINCLUDE_H) -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#include "fax_utils.h" -#include "fax_tester.h" - -#define HDLC_FRAMING_OK_THRESHOLD 5 - -extern const char *output_tiff_file_name; - -struct xml_node_parms_s -{ - xmlChar *dir; - xmlChar *type; - xmlChar *modem; - xmlChar *value; - xmlChar *tag; - xmlChar *bad_rows; - xmlChar *crc_error; - xmlChar *pattern; - xmlChar *timein; - xmlChar *timeout; - xmlChar *min_bits; - xmlChar *frame_size; - xmlChar *block; - xmlChar *compression; -}; - -struct -{ - const char *tag; - int code; -} t30_status[] = -{ - {"OK", T30_ERR_OK}, - {"CEDTONE", T30_ERR_CEDTONE}, - {"T0_EXPIRED", T30_ERR_T0_EXPIRED}, - {"T1_EXPIRED", T30_ERR_T1_EXPIRED}, - {"T3_EXPIRED", T30_ERR_T3_EXPIRED}, - {"HDLC_CARRIER", T30_ERR_HDLC_CARRIER}, - {"CANNOT_TRAIN", T30_ERR_CANNOT_TRAIN}, - {"OPER_INT_FAIL", T30_ERR_OPER_INT_FAIL}, - {"INCOMPATIBLE", T30_ERR_INCOMPATIBLE}, - {"RX_INCAPABLE", T30_ERR_RX_INCAPABLE}, - {"TX_INCAPABLE", T30_ERR_TX_INCAPABLE}, - {"NORESSUPPORT", T30_ERR_NORESSUPPORT}, - {"NOSIZESUPPORT", T30_ERR_NOSIZESUPPORT}, - {"UNEXPECTED", T30_ERR_UNEXPECTED}, - {"TX_BADDCS", T30_ERR_TX_BADDCS}, - {"TX_BADPG", T30_ERR_TX_BADPG}, - {"TX_ECMPHD", T30_ERR_TX_ECMPHD}, - {"TX_GOTDCN", T30_ERR_TX_GOTDCN}, - {"TX_INVALRSP", T30_ERR_TX_INVALRSP}, - {"TX_NODIS", T30_ERR_TX_NODIS}, - {"TX_PHBDEAD", T30_ERR_TX_PHBDEAD}, - {"TX_PHDDEAD", T30_ERR_TX_PHDDEAD}, - {"TX_T5EXP", T30_ERR_TX_T5EXP}, - {"RX_ECMPHD", T30_ERR_RX_ECMPHD}, - {"RX_GOTDCS", T30_ERR_RX_GOTDCS}, - {"RX_INVALCMD", T30_ERR_RX_INVALCMD}, - {"RX_NOCARRIER", T30_ERR_RX_NOCARRIER}, - {"RX_NOEOL", T30_ERR_RX_NOEOL}, - {"RX_NOFAX", T30_ERR_RX_NOFAX}, - {"RX_T2EXPDCN", T30_ERR_RX_T2EXPDCN}, - {"RX_T2EXPD", T30_ERR_RX_T2EXPD}, - {"RX_T2EXPFAX", T30_ERR_RX_T2EXPFAX}, - {"RX_T2EXPMPS", T30_ERR_RX_T2EXPMPS}, - {"RX_T2EXPRR", T30_ERR_RX_T2EXPRR}, - {"RX_T2EXP", T30_ERR_RX_T2EXP}, - {"RX_DCNWHY", T30_ERR_RX_DCNWHY}, - {"RX_DCNDATA", T30_ERR_RX_DCNDATA}, - {"RX_DCNFAX", T30_ERR_RX_DCNFAX}, - {"RX_DCNPHD", T30_ERR_RX_DCNPHD}, - {"RX_DCNRRD", T30_ERR_RX_DCNRRD}, - {"RX_DCNNORTN", T30_ERR_RX_DCNNORTN}, - {"FILEERROR", T30_ERR_FILEERROR}, - {"NOPAGE", T30_ERR_NOPAGE}, - {"BADTIFF", T30_ERR_BADTIFF}, - {"BADPAGE", T30_ERR_BADPAGE}, - {"BADTAG", T30_ERR_BADTAG}, - {"BADTIFFHDR", T30_ERR_BADTIFFHDR}, - {"NOMEM", T30_ERR_NOMEM}, - {"RETRYDCN", T30_ERR_RETRYDCN}, - {"CALLDROPPED", T30_ERR_CALLDROPPED}, - {"NOPOLL", T30_ERR_NOPOLL}, - {"IDENT_UNACCEPTABLE", T30_ERR_IDENT_UNACCEPTABLE}, - {"SUB_UNACCEPTABLE", T30_ERR_SUB_UNACCEPTABLE}, - {"SEP_UNACCEPTABLE", T30_ERR_SEP_UNACCEPTABLE}, - {"PSA_UNACCEPTABLE", T30_ERR_PSA_UNACCEPTABLE}, - {"SID_UNACCEPTABLE", T30_ERR_SID_UNACCEPTABLE}, - {"PWD_UNACCEPTABLE", T30_ERR_PWD_UNACCEPTABLE}, - {"TSA_UNACCEPTABLE", T30_ERR_TSA_UNACCEPTABLE}, - {"IRA_UNACCEPTABLE", T30_ERR_IRA_UNACCEPTABLE}, - {"CIA_UNACCEPTABLE", T30_ERR_CIA_UNACCEPTABLE}, - {"ISP_UNACCEPTABLE", T30_ERR_ISP_UNACCEPTABLE}, - {"CSA_UNACCEPTABLE", T30_ERR_CSA_UNACCEPTABLE}, - {NULL, -1} -}; - -static void timer_update(faxtester_state_t *s, int len) -{ - s->timer += len; - if (s->timer > s->timeout) - { - s->timeout = 0x7FFFFFFFFFFFFFFFLL; - span_log(&s->logging, SPAN_LOG_FLOW, "FAX tester step timed out\n"); - printf("Test failed\n"); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void front_end_step_complete(faxtester_state_t *s) -{ - while (faxtester_next_step(s) == 0) - ; - /*endwhile*/ -} -/*- End of function --------------------------------------------------------*/ - -static int faxtester_phase_b_handler(void *user_data, int result) -{ - int ch; - int status; - faxtester_state_t *s; - const char *u; - - s = (faxtester_state_t *) user_data; - ch = s->far_tag; - status = T30_ERR_OK; - if ((u = t30_get_rx_ident(s->far_t30))) - { - printf("%c: Phase B: remote ident '%s'\n", ch, u); - if (s->expected_rx_info.ident[0] && strcmp(s->expected_rx_info.ident, u)) - { - printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, s->expected_rx_info.ident); - status = T30_ERR_IDENT_UNACCEPTABLE; - } - } - else - { - if (s->expected_rx_info.ident[0]) - { - printf("%c: Phase B: remote ident missing!\n", ch); - status = T30_ERR_IDENT_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_sub_address(s->far_t30))) - { - printf("%c: Phase B: remote sub-address '%s'\n", ch, u); - if (s->expected_rx_info.sub_address[0] && strcmp(s->expected_rx_info.sub_address, u)) - { - printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, s->expected_rx_info.sub_address); - status = T30_ERR_SUB_UNACCEPTABLE; - } - } - else - { - if (s->expected_rx_info.sub_address[0]) - { - printf("%c: Phase B: remote sub-address missing!\n", ch); - status = T30_ERR_SUB_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_polled_sub_address(s->far_t30))) - { - printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u); - if (s->expected_rx_info.polled_sub_address[0] && strcmp(s->expected_rx_info.polled_sub_address, u)) - { - printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, s->expected_rx_info.polled_sub_address); - status = T30_ERR_PSA_UNACCEPTABLE; - } - } - else - { - if (s->expected_rx_info.polled_sub_address[0]) - { - printf("%c: Phase B: remote polled sub-address missing!\n", ch); - status = T30_ERR_PSA_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_selective_polling_address(s->far_t30))) - { - printf("%c: Phase B: remote selective polling address '%s'\n", ch, u); - if (s->expected_rx_info.selective_polling_address[0] && strcmp(s->expected_rx_info.selective_polling_address, u)) - { - printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, s->expected_rx_info.selective_polling_address); - status = T30_ERR_SEP_UNACCEPTABLE; - } - } - else - { - if (s->expected_rx_info.selective_polling_address[0]) - { - printf("%c: Phase B: remote selective polling address missing!\n", ch); - status = T30_ERR_SEP_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_sender_ident(s->far_t30))) - { - printf("%c: Phase B: remote sender ident '%s'\n", ch, u); - if (s->expected_rx_info.sender_ident[0] && strcmp(s->expected_rx_info.sender_ident, u)) - { - printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, s->expected_rx_info.sender_ident); - status = T30_ERR_SID_UNACCEPTABLE; - } - } - else - { - if (s->expected_rx_info.sender_ident[0]) - { - printf("%c: Phase B: remote sender ident missing!\n", ch); - status = T30_ERR_SID_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_password(s->far_t30))) - { - printf("%c: Phase B: remote password '%s'\n", ch, u); - if (s->expected_rx_info.password[0] && strcmp(s->expected_rx_info.password, u)) - { - printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, s->expected_rx_info.password); - status = T30_ERR_PWD_UNACCEPTABLE; - } - } - else - { - if (s->expected_rx_info.password[0]) - { - printf("%c: Phase B: remote password missing!\n", ch); - status = T30_ERR_PWD_UNACCEPTABLE; - } - } - printf("%c: Phase B handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - return status; -} -/*- End of function --------------------------------------------------------*/ - -static int faxtester_phase_d_handler(void *user_data, int result) -{ - int i; - int ch; - faxtester_state_t *s; - char tag[20]; - - s = (faxtester_state_t *) user_data; - ch = s->far_tag; - i = 0; - snprintf(tag, sizeof(tag), "%c: Phase D", ch); - printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_page_transfer_statistics(s->far_t30, tag); - fax_log_tx_parameters(s->far_t30, tag); - fax_log_rx_parameters(s->far_t30, tag); - - if (s->use_receiver_not_ready) - t30_set_receiver_not_ready(s->far_t30, 3); - - if (s->test_local_interrupt) - { - if (i == 0) - { - printf("%c: Initiating interrupt request\n", ch); - t30_local_interrupt_request(s->far_t30, true); - } - else - { - switch (result) - { - case T30_PIP: - case T30_PRI_MPS: - case T30_PRI_EOM: - case T30_PRI_EOP: - printf("%c: Accepting interrupt request\n", ch); - t30_local_interrupt_request(s->far_t30, true); - break; - case T30_PIN: - break; - } - } - } - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static void faxtester_phase_e_handler(void *user_data, int result) -{ - int ch; - faxtester_state_t *s; - char tag[20]; - - s = (faxtester_state_t *) user_data; - ch = s->far_tag; - snprintf(tag, sizeof(tag), "%c: Phase E", ch); - printf("%c: Phase E handler on channel %c - (%d) %s\n", ch, ch, result, t30_completion_code_to_str(result)); - fax_log_final_transfer_statistics(s->far_t30, tag); - fax_log_tx_parameters(s->far_t30, tag); - fax_log_rx_parameters(s->far_t30, tag); -} -/*- End of function --------------------------------------------------------*/ - -static void t30_real_time_frame_handler(void *user_data, - bool incoming, - const uint8_t *msg, - int len) -{ - if (msg == NULL) - { - } - else - { - fprintf(stderr, - "T.30: Real time frame handler - %s, %s, length = %d\n", - (incoming) ? "line->T.30" : "T.30->line", - t30_frametype(msg[2]), - len); - } -} -/*- End of function --------------------------------------------------------*/ - -static int faxtester_document_handler(void *user_data, int event) -{ - int ch; - faxtester_state_t *s; - t30_state_t *t; - - s = (faxtester_state_t *) user_data; - ch = s->far_tag; - t = s->far_t30; - fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event); - if (s->next_tx_file[0]) - { - t30_set_tx_file(t, s->next_tx_file, -1, -1); - s->next_tx_file[0] = '\0'; - return true; - } - return false; -} -/*- End of function --------------------------------------------------------*/ - -static void faxtester_real_time_frame_handler(faxtester_state_t *s, - int direction, - const uint8_t *msg, - int len) -{ - if (msg == NULL) - { - while (faxtester_next_step(s) == 0) - ; - /*endwhile*/ - } - else - { - fprintf(stderr, - "TST: Real time frame handler - %s, %s, length = %d\n", - (direction) ? "line->tester" : "tester->line", - t30_frametype(msg[2]), - len); - if (direction && msg[1] == s->awaited[1]) - { - if ((s->awaited_len >= 0 && len != abs(s->awaited_len)) - || - (s->awaited_len < 0 && len < abs(s->awaited_len)) - || - memcmp(msg, s->awaited, abs(s->awaited_len)) != 0) - { - span_log_buf(&s->logging, SPAN_LOG_FLOW, "Expected", s->awaited, abs(s->awaited_len)); - span_log_buf(&s->logging, SPAN_LOG_FLOW, "Received", msg, len); - printf("Test failed\n"); - exit(2); - } - } - if (msg[1] == s->awaited[1]) - { - while (faxtester_next_step(s) == 0) - ; - /*endwhile*/ - } - } -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_send_hdlc_flags(faxtester_state_t *s, int flags) -{ - hdlc_tx_flags(&s->modems.hdlc_tx, flags); -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_send_hdlc_msg(faxtester_state_t *s, const uint8_t *msg, int len, int crc_ok) -{ - hdlc_tx_frame(&s->modems.hdlc_tx, msg, len); - if (!crc_ok) - hdlc_tx_corrupt_frame(&s->modems.hdlc_tx); -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_underflow_handler(void *user_data) -{ - faxtester_state_t *s; - uint8_t buf[400]; - - s = (faxtester_state_t *) user_data; - - if (s->image_buffer) - { - /* We are sending an ECM image */ - if (s->image_ptr < s->image_len) - { - buf[0] = 0xFF; - buf[1] = 0x03; - buf[2] = 0x06; - buf[3] = s->image_ptr/s->ecm_frame_size; - memcpy(&buf[4], &s->image_buffer[s->image_ptr], s->ecm_frame_size); - hdlc_tx_frame(&s->modems.hdlc_tx, buf, 4 + s->ecm_frame_size); - if (s->corrupt_crc >= 0 && s->corrupt_crc == s->image_ptr/s->ecm_frame_size) - hdlc_tx_corrupt_frame(&s->modems.hdlc_tx); - s->image_ptr += s->ecm_frame_size; - return; - } - /* The actual image is over. We are sending the final RCP frames. */ - if (s->image_bit_ptr > 2) - { - s->image_bit_ptr--; - buf[0] = 0xFF; - buf[1] = 0x03; - buf[2] = 0x86; - hdlc_tx_frame(&s->modems.hdlc_tx, buf, 3); - return; - } - /* All done. */ - s->image_buffer = NULL; - } - front_end_step_complete(s); -} -/*- End of function --------------------------------------------------------*/ - -static void modem_tx_status(void *user_data, int status) -{ - faxtester_state_t *s; - - s = (faxtester_state_t *) user_data; - printf("Tx status is %s (%d)\n", signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_SHUTDOWN_COMPLETE: - front_end_step_complete(s); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void tone_detected(void *user_data, int tone, int level, int delay) -{ - faxtester_state_t *s; - - s = (faxtester_state_t *) user_data; - span_log(&s->logging, - SPAN_LOG_FLOW, - "%s (%d) declared (%ddBm0)\n", - modem_connect_tone_to_str(tone), - tone, - level); - if (tone != MODEM_CONNECT_TONES_NONE) - { - s->tone_on_time = s->timer; - } - else - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "Tone was on for %fs\n", - (float) (s->timer - s->tone_on_time)/SAMPLE_RATE + 0.55); - } - s->tone_state = tone; - if (tone == MODEM_CONNECT_TONES_NONE) - front_end_step_complete(s); -} -/*- End of function --------------------------------------------------------*/ - -static int non_ecm_get_bit(void *user_data) -{ - faxtester_state_t *s; - int bit; - - s = (faxtester_state_t *) user_data; - if (s->image_bit_ptr == 0) - { - if (s->image_ptr >= s->image_len) - { - s->image_buffer = NULL; - return SIG_STATUS_END_OF_DATA; - } - s->image_bit_ptr = 8; - s->image_ptr++; - } - s->image_bit_ptr--; - bit = (s->image_buffer[s->image_ptr] >> (7 - s->image_bit_ptr)) & 0x01; - //printf("Rx bit - %d\n", bit); - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static void faxtester_set_ecm_image_buffer(faxtester_state_t *s, int block, int frame_size, int crc_hit) -{ - s->image_ptr = 256*frame_size*block; - if (s->image_len > s->image_ptr + 256*frame_size) - s->image_len = s->image_ptr + 256*frame_size; - - s->ecm_frame_size = frame_size; - s->image_bit_ptr = 8; - s->corrupt_crc = crc_hit; - s->image_buffer = s->image; - - /* Send the first frame */ - hdlc_underflow_handler(s); -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_rx_status(void *user_data, int status) -{ - faxtester_state_t *s; - - s = (faxtester_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier status is %s (%d)\n", signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_TRAINING_FAILED: - s->modems.rx_trained = false; - break; - case SIG_STATUS_TRAINING_SUCCEEDED: - /* The modem is now trained */ - s->modems.rx_trained = true; - break; - case SIG_STATUS_CARRIER_UP: - s->modems.rx_signal_present = true; - break; - case SIG_STATUS_CARRIER_DOWN: - if (s->modems.rx_trained) - faxtester_real_time_frame_handler(s, true, NULL, 0); - s->modems.rx_signal_present = false; - s->modems.rx_trained = false; - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void non_ecm_put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - non_ecm_rx_status(user_data, bit); - return; - } -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_rx_status(void *user_data, int status) -{ - faxtester_state_t *s; - - s = (faxtester_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier status is %s (%d)\n", signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_TRAINING_FAILED: - s->modems.rx_trained = false; - break; - case SIG_STATUS_TRAINING_SUCCEEDED: - /* The modem is now trained */ - s->modems.rx_trained = true; - break; - case SIG_STATUS_CARRIER_UP: - s->modems.rx_signal_present = true; - break; - case SIG_STATUS_CARRIER_DOWN: - s->modems.rx_signal_present = false; - s->modems.rx_trained = false; - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) -{ - faxtester_state_t *s; - - if (len < 0) - { - hdlc_rx_status(user_data, len); - return; - } - s = (faxtester_state_t *) user_data; - faxtester_real_time_frame_handler(s, true, msg, len); -} -/*- End of function --------------------------------------------------------*/ - -int faxtester_rx(faxtester_state_t *s, int16_t *amp, int len) -{ - int i; - - for (i = 0; i < len; i++) - amp[i] = dc_restore(&s->modems.dc_restore, amp[i]); - if (s->modems.rx_handler) - s->modems.rx_handler(s->modems.rx_user_data, amp, len); - timer_update(s, len); - if (s->wait_for_silence) - { - if (!s->modems.rx_signal_present) - { - s->wait_for_silence = false; - front_end_step_complete(s); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int faxtester_tx(faxtester_state_t *s, int16_t *amp, int max_len) -{ - int len; - - len = 0; - if (s->transmit) - { - 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 */ - front_end_step_complete(s); - if (!s->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; - } - } - } - else - { - if (s->modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - memset(amp, 0, max_len*sizeof(int16_t)); - len = max_len; - } - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -void faxtest_set_rx_silence(faxtester_state_t *s) -{ - s->wait_for_silence = true; -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_set_rx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) -{ - faxtester_state_t *s; - fax_modems_state_t *t; - - s = (faxtester_state_t *) user_data; - t = &s->modems; - span_log(&s->logging, SPAN_LOG_FLOW, "Set rx type %d\n", type); - if (s->current_rx_type == type) - return; - s->current_rx_type = type; - if (use_hdlc) - hdlc_rx_init(&t->hdlc_rx, false, false, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, s); - switch (type) - { - case T30_MODEM_CED: - fax_modems_start_slow_modem(t, FAX_MODEM_CED_TONE_RX); - s->tone_state = MODEM_CONNECT_TONES_NONE; - break; - case T30_MODEM_CNG: - fax_modems_start_slow_modem(t, FAX_MODEM_CNG_TONE_RX); - s->tone_state = MODEM_CONNECT_TONES_NONE; - break; - case T30_MODEM_V21: - if (s->flush_handler) - s->flush_handler(s, s->flush_user_data, 3); - fax_modems_start_slow_modem(t, FAX_MODEM_V21_RX); - break; - case T30_MODEM_V27TER: - fax_modems_start_fast_modem(t, FAX_MODEM_V27TER_RX, bit_rate, short_train, use_hdlc); - break; - case T30_MODEM_V29: - fax_modems_start_fast_modem(t, FAX_MODEM_V29_RX, bit_rate, short_train, use_hdlc); - break; - case T30_MODEM_V17: - fax_modems_start_fast_modem(t, FAX_MODEM_V17_RX, bit_rate, short_train, use_hdlc); - break; - case T30_MODEM_DONE: - span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); - default: - fax_modems_set_rx_handler(t, (span_rx_handler_t) &span_dummy_rx, s, NULL, s); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc) -{ - faxtester_state_t *s; - get_bit_func_t get_bit_func; - void *get_bit_user_data; - fax_modems_state_t *t; - int tone; - - s = (faxtester_state_t *) user_data; - t = &s->modems; - span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); - if (use_hdlc) - { - get_bit_func = (get_bit_func_t) hdlc_tx_get_bit; - get_bit_user_data = (void *) &t->hdlc_tx; - } - else - { - get_bit_func = non_ecm_get_bit; - get_bit_user_data = (void *) s; - } - if (type == s->current_tx_type) - { - if (type == T30_MODEM_PAUSE) - silence_gen_alter(&t->silence_gen, ms_to_samples(short_train)); - 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); - s->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); - 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; - break; - case T30_MODEM_V27TER: - fax_modems_set_get_bit(t, get_bit_func, get_bit_user_data); - fax_modems_start_fast_modem(t, FAX_MODEM_V27TER_TX, bit_rate, short_train, use_hdlc); - 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; - break; - case T30_MODEM_V29: - fax_modems_set_get_bit(t, get_bit_func, get_bit_user_data); - fax_modems_start_fast_modem(t, FAX_MODEM_V29_TX, bit_rate, short_train, use_hdlc); - 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; - break; - case T30_MODEM_V17: - fax_modems_set_get_bit(t, get_bit_func, get_bit_user_data); - fax_modems_start_fast_modem(t, FAX_MODEM_V17_TX, bit_rate, short_train, use_hdlc); - 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; - break; - case T30_MODEM_DONE: - span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); - /* Fall through */ - 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; - break; - } - s->current_tx_type = type; -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_set_timeout(faxtester_state_t *s, int timeout) -{ - if (timeout >= 0) - s->timeout = s->timer + timeout*SAMPLE_RATE/1000; - else - s->timeout = 0x7FFFFFFFFFFFFFFFLL; -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle) -{ - s->modems.transmit_on_idle = transmit_on_idle; -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep) -{ - fax_modems_set_tep_mode(&s->modems, use_tep); -} -/*- End of function --------------------------------------------------------*/ - -static void corrupt_image(faxtester_state_t *s, const char *bad_rows) -{ - int i; - int j; - int k; - uint32_t bits; - uint32_t bitsx; - int list[1000]; - int x; - int row; - const char *t; - - /* Form the list of rows to be hit */ - x = 0; - t = bad_rows; - while (*t) - { - while (isspace((int) *t)) - t++; - if (sscanf(t, "%d", &list[x]) < 1) - break; - x++; - while (isdigit((int) *t)) - t++; - if (*t == ',') - t++; - } - - /* Go through the image, and corrupt the first bit of every listed row */ - bits = 0x7FF; - bitsx = 0x7FF; - row = 0; - for (i = 0; i < s->image_len; i++) - { - bits ^= (s->image[i] << 11); - bitsx ^= (s->image[i] << 11); - for (j = 0; j < 8; j++) - { - if ((bits & 0xFFF) == 0x800) - { - /* We are at an EOL. Is this row in the list of rows to be corrupted? */ - row++; - for (k = 0; k < x; k++) - { - if (list[k] == row) - { - /* Corrupt this row. TSB85 says to hit the first bit after the EOL */ - bitsx ^= 0x1000; - } - } - } - bits >>= 1; - bitsx >>= 1; - } - s->image[i] = (bitsx >> 3) & 0xFF; - } - span_log(&s->logging, SPAN_LOG_FLOW, "%d rows found. %d corrupted\n", row, x); -} -/*- End of function --------------------------------------------------------*/ - -static int string_to_msg(uint8_t msg[], uint8_t mask[], const char buf[]) -{ - int i; - int x; - const char *t; - - msg[0] = 0; - mask[0] = 0xFF; - i = 0; - t = (char *) buf; - while (*t) - { - /* Skip white space */ - while (isspace((int) *t)) - t++; - /* If we find ... we allow arbitrary additional info beyond this point in the message */ - if (t[0] == '.' && t[1] == '.' && t[2] == '.') - { - return -i; - } - else if (isxdigit((int) *t)) - { - for ( ; isxdigit((int) *t); t++) - { - x = *t; - if (x >= 'a') - x -= 0x20; - if (x >= 'A') - x -= ('A' - 10); - else - x -= '0'; - msg[i] = (msg[i] << 4) | x; - } - mask[i] = 0xFF; - if (*t == '/') - { - /* There is a mask following the byte */ - mask[i] = 0; - for (t++; isxdigit((int) *t); t++) - { - x = *t; - if (x >= 'a') - x -= 0x20; - if (x >= 'A') - x -= ('A' - 10); - else - x -= '0'; - mask[i] = (mask[i] << 4) | x; - } - } - if (*t && !isspace((int) *t)) - { - /* Bad string */ - return 0; - } - i++; - } - } - return i; -} -/*- End of function --------------------------------------------------------*/ - -void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data) -{ - s->flush_handler = handler; - s->flush_user_data = user_data; -} -/*- End of function --------------------------------------------------------*/ - -static void fax_prepare(faxtester_state_t *s) -{ - if (s->far_fax) - { - fax_set_transmit_on_idle(s->far_fax, true); - fax_set_tep_mode(s->far_fax, true); - } -#if 0 - t30_set_tx_ident(s->far_t30, "1234567890"); - t30_set_tx_sub_address(s->far_t30, "Sub-address"); - t30_set_tx_sender_ident(s->far_t30, "Sender ID"); - t30_set_tx_password(s->far_t30, "Password"); - t30_set_tx_polled_sub_address(s->far_t30, "Polled sub-address"); - t30_set_tx_selective_polling_address(s->far_t30, "Sel polling address"); -#endif - t30_set_tx_nsf(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSF\x00", 16); - //t30_set_tx_nss(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSS\x00", 16); - t30_set_tx_nsc(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSC\x00", 16); - t30_set_ecm_capability(s->far_t30, true); - t30_set_supported_t30_features(s->far_t30, - T30_SUPPORT_IDENTIFICATION - | T30_SUPPORT_SELECTIVE_POLLING - | T30_SUPPORT_SUB_ADDRESSING); - t30_set_supported_image_sizes(s->far_t30, - 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(s->far_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(s->far_t30, 0); - t30_set_supported_modems(s->far_t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); - t30_set_supported_compressions(s->far_t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6); - t30_set_phase_b_handler(s->far_t30, faxtester_phase_b_handler, (void *) s); - t30_set_phase_d_handler(s->far_t30, faxtester_phase_d_handler, (void *) s); - t30_set_phase_e_handler(s->far_t30, faxtester_phase_e_handler, (void *) s); - t30_set_real_time_frame_handler(s->far_t30, t30_real_time_frame_handler, (void *) s); - t30_set_document_handler(s->far_t30, faxtester_document_handler, (void *) s); -} -/*- End of function --------------------------------------------------------*/ - -static void get_node_parms(struct xml_node_parms_s *parms, xmlNodePtr node) -{ - parms->dir = xmlGetProp(node, (const xmlChar *) "dir"); - parms->type = xmlGetProp(node, (const xmlChar *) "type"); - parms->modem = xmlGetProp(node, (const xmlChar *) "modem"); - parms->value = xmlGetProp(node, (const xmlChar *) "value"); - parms->tag = xmlGetProp(node, (const xmlChar *) "tag"); - parms->bad_rows = xmlGetProp(node, (const xmlChar *) "bad_rows"); - parms->crc_error = xmlGetProp(node, (const xmlChar *) "crc_error"); - parms->pattern = xmlGetProp(node, (const xmlChar *) "pattern"); - parms->timein = xmlGetProp(node, (const xmlChar *) "timein"); - parms->timeout = xmlGetProp(node, (const xmlChar *) "timeout"); - parms->min_bits = xmlGetProp(node, (const xmlChar *) "min_bits"); - parms->frame_size = xmlGetProp(node, (const xmlChar *) "frame_size"); - parms->block = xmlGetProp(node, (const xmlChar *) "block"); - parms->compression = xmlGetProp(node, (const xmlChar *) "compression"); -} -/*- End of function --------------------------------------------------------*/ - -static void free_node_parms(struct xml_node_parms_s *parms) -{ - if (parms->dir) - xmlFree(parms->dir); - if (parms->type) - xmlFree(parms->type); - if (parms->modem) - xmlFree(parms->modem); - if (parms->value) - xmlFree(parms->value); - if (parms->tag) - xmlFree(parms->tag); - if (parms->bad_rows) - xmlFree(parms->bad_rows); - if (parms->crc_error) - xmlFree(parms->crc_error); - if (parms->pattern) - xmlFree(parms->pattern); - if (parms->timein) - xmlFree(parms->timein); - if (parms->timeout) - xmlFree(parms->timeout); - if (parms->min_bits) - xmlFree(parms->min_bits); - if (parms->frame_size) - xmlFree(parms->frame_size); - if (parms->block) - xmlFree(parms->block); - if (parms->compression) - xmlFree(parms->compression); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) faxtester_next_step(faxtester_state_t *s) -{ - int delay; - int flags; - struct xml_node_parms_s parms; - uint8_t buf[1000]; - uint8_t mask[1000]; - char path[1024]; - int i; - int j; - int hdlc; - int short_train; - int min_row_bits; - int ecm_frame_size; - int ecm_block; - int compression_type; - xmlChar *min; - xmlChar *max; - t4_tx_state_t t4_tx_state; - t30_stats_t t30_stats; - - s->test_for_call_clear = false; - if (s->cur == NULL) - { - if (!s->final_delayed) - { - /* 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; - return 1; - } - /* Finished */ - printf("Test passed\n"); - exit(0); - } - for (;;) - { - if (s->cur == NULL) - { - if (s->repeat_parent == NULL) - { - /* Finished */ - printf("Test passed\n"); - exit(0); - } - if (++s->repeat_count > s->repeat_max) - { - /* Finished */ - printf("Too many repeats\n"); - printf("Test failed\n"); - exit(0); - } - if (s->repeat_count < s->repeat_min) - { - s->cur = s->repeat_start; - } - else - { - s->cur = s->repeat_parent->next; - s->repeat_parent = NULL; - } - } - if (xmlStrcmp(s->cur->name, (const xmlChar *) "step") == 0) - { - break; - } - if (s->repeat_parent == NULL && xmlStrcmp(s->cur->name, (const xmlChar *) "repeat") == 0) - { - min = xmlGetProp(s->cur, (const xmlChar *) "min"); - max = xmlGetProp(s->cur, (const xmlChar *) "max"); - s->repeat_min = min ? atoi((const char *) min) : 0; - s->repeat_max = max ? atoi((const char *) max) : INT_MAX; - s->repeat_count = 0; - if (min) - xmlFree(min); - if (max) - xmlFree(max); - if (s->repeat_min > 0) - { - s->repeat_parent = s->cur; - s->repeat_start = - s->cur = s->cur->xmlChildrenNode; - continue; - } - } - s->cur = s->cur->next; - } - - get_node_parms(&parms, s->cur); - - s->cur = s->cur->next; - - span_log(&s->logging, - SPAN_LOG_FLOW, - "Dir - %s, type - %s, modem - %s, value - %s, timein - %s, timeout - %s, tag - %s\n", - (parms.dir) ? (const char *) parms.dir : " ", - (parms.type) ? (const char *) parms.type : "", - (parms.modem) ? (const char *) parms.modem : "", - (parms.value) ? (const char *) parms.value : "", - (parms.timein) ? (const char *) parms.timein : "", - (parms.timeout) ? (const char *) parms.timeout : "", - (parms.tag) ? (const char *) parms.tag : ""); - if (parms.type == NULL) - { - free_node_parms(&parms); - return 1; - } - s->timein_x = (parms.timein) ? atoi((const char *) parms.timein) : -1; - s->timeout_x = (parms.timeout) ? atoi((const char *) parms.timeout) : -1; - - if (parms.dir && strcasecmp((const char *) parms.dir, "R") == 0) - { - /* Receive always has a timeout applied. */ - if (s->timeout_x < 0) - s->timeout_x = 7000; - faxtester_set_timeout(s, s->timeout_x); - if (parms.modem) - { - hdlc = (strcasecmp((const char *) parms.type, "PREAMBLE") == 0); - short_train = (strcasecmp((const char *) parms.type, "TCF") != 0); - faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false); - if (strcasecmp((const char *) parms.modem, "V.21") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V21, 300, false, true); - } - else if (strcasecmp((const char *) parms.modem, "V.17/14400") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V17, 14400, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.17/12000") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V17, 12000, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.17/9600") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V17, 9600, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.17/7200") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V17, 7200, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.29/9600") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V29, 9600, false, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.29/7200") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V29, 7200, false, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.27ter/4800") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, false, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.27ter/2400") == 0) - { - faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, false, hdlc); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n"); - } - } - - if (strcasecmp((const char *) parms.type, "SET") == 0) - { - if (strcasecmp((const char *) parms.tag, "IDENT") == 0) - strcpy(s->expected_rx_info.ident, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "SUB") == 0) - strcpy(s->expected_rx_info.sub_address, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "SEP") == 0) - strcpy(s->expected_rx_info.selective_polling_address, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "PSA") == 0) - strcpy(s->expected_rx_info.polled_sub_address, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "SID") == 0) - strcpy(s->expected_rx_info.sender_ident, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "PWD") == 0) - strcpy(s->expected_rx_info.password, (const char *) parms.value); - free_node_parms(&parms); - return 0; - } - else if (strcasecmp((const char *) parms.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); - } - else if (strcasecmp((const char *) parms.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); - } - else if (strcasecmp((const char *) parms.type, "HDLC") == 0) - { - i = string_to_msg(buf, mask, (const char *) parms.value); - bit_reverse(s->awaited, buf, abs(i)); - s->awaited_len = i; - } - else if (strcasecmp((const char *) parms.type, "TCF") == 0) - { - } - else if (strcasecmp((const char *) parms.type, "MSG") == 0) - { - } - else if (strcasecmp((const char *) parms.type, "PP") == 0) - { - } - else if (strcasecmp((const char *) parms.type, "SILENCE") == 0) - { - faxtest_set_rx_silence(s); - } - else if (strcasecmp((const char *) parms.type, "CLEAR") == 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n"); - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); - faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, s->timeout_x, false); - s->test_for_call_clear = true; - s->call_clear_timer = 0; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) parms.type); - free_node_parms(&parms); - return 0; - } - } - else - { - faxtester_set_timeout(s, s->timeout_x); - if (parms.modem) - { - hdlc = (strcasecmp((const char *) parms.type, "PREAMBLE") == 0); - short_train = (strcasecmp((const char *) parms.type, "TCF") != 0); - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); - if (strcasecmp((const char *) parms.modem, "V.21") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V21, 300, false, true); - } - else if (strcasecmp((const char *) parms.modem, "V.17/14400") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V17, 14400, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.17/12000") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V17, 12000, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.17/9600") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V17, 9600, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.17/7200") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V17, 7200, short_train, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.29/9600") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V29, 9600, false, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.29/7200") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V29, 7200, false, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.27ter/4800") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, false, hdlc); - } - else if (strcasecmp((const char *) parms.modem, "V.27ter/2400") == 0) - { - faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, false, hdlc); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n"); - } - } - - if (strcasecmp((const char *) parms.type, "SET") == 0) - { - if (strcasecmp((const char *) parms.tag, "IDENT") == 0) - t30_set_tx_ident(s->far_t30, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "SUB") == 0) - t30_set_tx_sub_address(s->far_t30, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "SEP") == 0) - t30_set_tx_selective_polling_address(s->far_t30, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "PSA") == 0) - t30_set_tx_polled_sub_address(s->far_t30, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "SID") == 0) - t30_set_tx_sender_ident(s->far_t30, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "PWD") == 0) - t30_set_tx_password(s->far_t30, (const char *) parms.value); - else if (strcasecmp((const char *) parms.tag, "RXFILE") == 0) - { - if (parms.value) - t30_set_rx_file(s->far_t30, (const char *) parms.value, -1); - else - t30_set_rx_file(s->far_t30, output_tiff_file_name, -1); - } - else if (strcasecmp((const char *) parms.tag, "TXFILE") == 0) - { - sprintf(s->next_tx_file, "%s/%s", s->image_path, (const char *) parms.value); - printf("Push '%s'\n", s->next_tx_file); - } - free_node_parms(&parms); - return 0; - } - else if (strcasecmp((const char *) parms.type, "CALL") == 0) - { - if (s->far_fax) - fax_restart(s->far_fax, false); - else - t38_terminal_restart(s->far_t38, false); - fax_prepare(s); - s->next_tx_file[0] = '\0'; - t30_set_rx_file(s->far_t30, output_tiff_file_name, -1); - /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */ - t30_set_supported_output_compressions(s->far_t30, T4_COMPRESSION_T4_1D); - if (parms.value) - { - sprintf(path, "%s/%s", s->image_path, (const char *) parms.value); - t30_set_tx_file(s->far_t30, path, -1, -1); - } - free_node_parms(&parms); - return 0; - } - else if (strcasecmp((const char *) parms.type, "ANSWER") == 0) - { - if (s->far_fax) - fax_restart(s->far_fax, true); - else - t38_terminal_restart(s->far_t38, true); - fax_prepare(s); - s->next_tx_file[0] = '\0'; - /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */ - t30_set_supported_output_compressions(s->far_t30, T4_COMPRESSION_T4_1D); - if (parms.value) - { - sprintf(path, "%s/%s", s->image_path, (const char *) parms.value); - t30_set_tx_file(s->far_t30, path, -1, -1); - } - free_node_parms(&parms); - return 0; - } - else if (strcasecmp((const char *) parms.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); - } - else if (strcasecmp((const char *) parms.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); - } - else if (strcasecmp((const char *) parms.type, "WAIT") == 0) - { - delay = (parms.value) ? atoi((const char *) parms.value) : 1; - 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 *) parms.type, "PREAMBLE") == 0) - { - flags = (parms.value) ? atoi((const char *) parms.value) : 37; - faxtester_send_hdlc_flags(s, flags); - } - else if (strcasecmp((const char *) parms.type, "POSTAMBLE") == 0) - { - flags = (parms.value) ? atoi((const char *) parms.value) : 5; - faxtester_send_hdlc_flags(s, flags); - } - else if (strcasecmp((const char *) parms.type, "HDLC") == 0) - { - i = string_to_msg(buf, mask, (const char *) parms.value); - bit_reverse(buf, buf, abs(i)); - if (parms.crc_error && strcasecmp((const char *) parms.crc_error, "0") == 0) - faxtester_send_hdlc_msg(s, buf, abs(i), false); - else - faxtester_send_hdlc_msg(s, buf, abs(i), true); - } - else if (strcasecmp((const char *) parms.type, "TCF") == 0) - { - i = (parms.value) ? atoi((const char *) parms.value) : 450; - if (parms.pattern) - { - /* TODO: implement proper patterns */ - j = atoi((const char *) parms.pattern); - memset(s->image, 0x55, j); - if (i > j) - memset(s->image + j, 0, i - j); - } - else - { - memset(s->image, 0, i); - } - s->image_ptr = 0; - s->image_bit_ptr = 8; - s->image_buffer = s->image; - s->image_len = i; - } - else if (strcasecmp((const char *) parms.type, "MSG") == 0) - { - /* A non-ECM page */ - min_row_bits = (parms.min_bits) ? atoi((const char *) parms.min_bits) : 0; - sprintf(path, "%s/%s", s->image_path, (const char *) parms.value); - if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n"); - printf("Test failed\n"); - exit(2); - } - t4_tx_set_header_info(&t4_tx_state, NULL); - compression_type = T4_COMPRESSION_T4_1D; - if (parms.compression) - { - if (strcasecmp((const char *) parms.compression, "T.4 1D") == 0) - compression_type = T4_COMPRESSION_T4_1D; - else if (strcasecmp((const char *) parms.compression, "T.4 2D") == 0) - compression_type = T4_COMPRESSION_T4_2D; - else if (strcasecmp((const char *) parms.compression, "T.6") == 0) - compression_type = T4_COMPRESSION_T6; - else if (strcasecmp((const char *) parms.compression, "T.85") == 0) - compression_type = T4_COMPRESSION_T85; - } - 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_min_bits_per_row(&t4_tx_state, min_row_bits); - if (t4_tx_start_page(&t4_tx_state)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n"); - printf("Test failed\n"); - exit(2); - } - s->image_len = t4_tx_get(&t4_tx_state, s->image, sizeof(s->image)); - if (parms.bad_rows) - { - span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n"); - corrupt_image(s, (const char *) parms.bad_rows); - } - t4_tx_release(&t4_tx_state); - span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM image is %d bytes (min row bits %d)\n", s->image_len, min_row_bits); - s->image_ptr = 0; - s->image_bit_ptr = 8; - s->image_buffer = s->image; - } - else if (strcasecmp((const char *) parms.type, "PP") == 0) - { - min_row_bits = (parms.min_bits) ? atoi((const char *) parms.min_bits) : 0; - ecm_block = (parms.block) ? atoi((const char *) parms.block) : 0; - ecm_frame_size = (parms.frame_size) ? atoi((const char *) parms.frame_size) : 64; - i = (parms.crc_error) ? atoi((const char *) parms.crc_error) : -1; - sprintf(path, "%s/%s", s->image_path, (const char *) parms.value); - if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n"); - printf("Test failed\n"); - exit(2); - } - t4_tx_set_header_info(&t4_tx_state, NULL); - compression_type = T4_COMPRESSION_T4_1D; - if (parms.compression) - { - if (strcasecmp((const char *) parms.compression, "T.4 1D") == 0) - compression_type = T4_COMPRESSION_T4_1D; - else if (strcasecmp((const char *) parms.compression, "T.4 2D") == 0) - compression_type = T4_COMPRESSION_T4_2D; - else if (strcasecmp((const char *) parms.compression, "T.6") == 0) - compression_type = T4_COMPRESSION_T6; - else if (strcasecmp((const char *) parms.compression, "T.85") == 0) - compression_type = T4_COMPRESSION_T85; - } - 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_min_bits_per_row(&t4_tx_state, min_row_bits); - if (t4_tx_start_page(&t4_tx_state)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n"); - printf("Test failed\n"); - exit(2); - } - /*endif*/ - s->image_len = t4_tx_get(&t4_tx_state, s->image, sizeof(s->image)); - if (parms.bad_rows) - { - span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n"); - corrupt_image(s, (const char *) parms.bad_rows); - } - /*endif*/ - t4_tx_release(&t4_tx_state); - span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", s->image_len, min_row_bits); - faxtester_set_ecm_image_buffer(s, ecm_block, ecm_frame_size, i); - } - else if (strcasecmp((const char *) parms.type, "CLEAR") == 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n"); - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); - faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, s->timeout_x, false); - t30_terminate(s->far_t30); - free_node_parms(&parms); - return 0; - } - else if (strcasecmp((const char *) parms.type, "STATUS") == 0) - { - if (parms.value) - { - for (i = 0; t30_status[i].code >= 0; i++) - { - if (strcmp(t30_status[i].tag, (const char *) parms.value) == 0) - break; - } - if (t30_status[i].code >= 0) - delay = t30_status[i].code; - else - delay = atoi((const char *) parms.value); - t30_get_transfer_statistics(s->far_t30, &t30_stats); - if (delay == t30_stats.current_status) - span_log(&s->logging, SPAN_LOG_FLOW, "Expected status (%s) found\n", t30_status[i].tag); - else - span_log(&s->logging, SPAN_LOG_FLOW, "Expected status %s, but found %s (%d)\n", t30_status[i].tag, t30_status[t30_stats.current_status].tag, t30_stats.current_status); - if (delay != t30_stats.current_status) - { - printf("Test failed\n"); - exit(2); - } - } - free_node_parms(&parms); - return 0; - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) parms.type); - free_node_parms(&parms); - return 0; - } - /*endif*/ - } - /*endif*/ - free_node_parms(&parms); - return 1; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_config(faxtester_state_t *s, xmlNodePtr cur) -{ - xmlChar *x; - xmlChar *y; - - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "path") == 0) - { - x = NULL; - y = NULL; - if ((x = xmlGetProp(cur, (const xmlChar *) "type")) - && - (y = xmlGetProp(cur, (const xmlChar *) "value"))) - { - if (strcasecmp((const char *) x, "IMAGE") == 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s' '%s'\n", (char *) x, (char *) y); - strcpy(s->image_path, (const char *) y); - } - /*endif*/ - } - /*endif*/ - if (x) - xmlFree(x); - /*endif*/ - if (y) - xmlFree(y); - /*endif*/ - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static int parse_test_group(faxtester_state_t *s, xmlNodePtr cur, const char *test) -{ - xmlChar *x; - - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "test") == 0) - { - if ((x = xmlGetProp(cur, (const xmlChar *) "name"))) - { - if (xmlStrcmp(x, (const xmlChar *) test) == 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s'\n", (char *) x); - s->cur = cur->xmlChildrenNode; - xmlFree(x); - return 0; - } - /*endif*/ - xmlFree(x); - } - /*endif*/ - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static int get_test_set(faxtester_state_t *s, const char *test_file, const char *test) -{ - xmlParserCtxtPtr ctxt; - xmlNodePtr cur; - - if ((ctxt = xmlNewParserCtxt()) == NULL) - { - fprintf(stderr, "Failed to allocate XML parser context\n"); - return -1; - } - /* parse the file, activating the DTD validation option */ - if ((s->doc = xmlCtxtReadFile(ctxt, test_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL) - { - fprintf(stderr, "Failed to read the XML document\n"); - return -1; - } - if (ctxt->valid == 0) - { - fprintf(stderr, "Failed to validate the XML document\n"); - xmlFreeDoc(s->doc); - s->doc = NULL; - xmlFreeParserCtxt(ctxt); - return -1; - } - xmlFreeParserCtxt(ctxt); - - /* Check the document is of the right kind */ - if ((cur = xmlDocGetRootElement(s->doc)) == NULL) - { - xmlFreeDoc(s->doc); - s->doc = NULL; - fprintf(stderr, "Empty document\n"); - return -1; - } - /*endif*/ - if (xmlStrcmp(cur->name, (const xmlChar *) "fax-tests")) - { - xmlFreeDoc(s->doc); - s->doc = NULL; - fprintf(stderr, "Document of the wrong type, root node != fax-tests\n"); - return -1; - } - /*endif*/ - cur = cur->xmlChildrenNode; - while (cur && xmlIsBlankNode(cur)) - cur = cur->next; - /*endwhile*/ - if (cur == NULL) - { - fprintf(stderr, "XML test not found\n"); - return -1; - } - /*endif*/ - xmlCleanupParser(); - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "config") == 0) - parse_config(s, cur->xmlChildrenNode); - /*endif*/ - if (xmlStrcmp(cur->name, (const xmlChar *) "test-group") == 0) - { - if (parse_test_group(s, cur->xmlChildrenNode, test) == 0) - return 0; - /*endif*/ - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - fprintf(stderr, "XML test not found\n"); - return -1; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(logging_state_t *) faxtester_get_logging_state(faxtester_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - -faxtester_state_t *faxtester_init(faxtester_state_t *s, const char *test_file, const char *test) -{ - if (s == NULL) - { - if ((s = (faxtester_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - } - /*endif*/ - - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "TST"); - fax_modems_init(&s->modems, - false, - hdlc_accept, - 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); - faxtester_set_timeout(s, -1); - s->timein_x = -1; - s->timeout_x = -1; - faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false); - strcpy(s->image_path, "."); - s->next_tx_file[0] = '\0'; - if (get_test_set(s, test_file, test) < 0) - { - /* TODO: free the state, if it was allocated. */ - return NULL; - } - /*endif*/ - memset(&s->expected_rx_info, 0, sizeof(s->expected_rx_info)); - return s; -} -/*- End of function --------------------------------------------------------*/ - -int faxtester_release(faxtester_state_t *s) -{ - if (s->doc) - { - xmlFreeDoc(s->doc); - s->doc = NULL; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int faxtester_free(faxtester_state_t *s) -{ - faxtester_release(s); - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fax_tester.h b/libs/spandsp/tests/fax_tester.h deleted file mode 100644 index 412c1fc340..0000000000 --- a/libs/spandsp/tests/fax_tester.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_tester.h - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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 */ - -#if !defined(_SPANDSP_FAX_TESTER_H_) -#define _SPANDSP_FAX_TESTER_H_ - -/*! \page fax_tester_page FAX over analogue modem handling - -\section fax_tester_page_sec_1 What does it do? - -\section fax_tester_page_sec_2 How does it work? -*/ - -typedef struct faxtester_state_s faxtester_state_t; - -typedef void (*faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which); - -/*! - FAX tester descriptor. -*/ -struct faxtester_state_s -{ - /*! \brief The far end FAX context */ - fax_state_t *far_fax; - t38_terminal_state_t *far_t38; - - int far_tag; - - /*! \brief The far end T.38 terminal context */ - t38_terminal_state_t *far_t38_fax; - - t30_state_t *far_t30; - - t30_exchanged_info_t expected_rx_info; - - bool use_receiver_not_ready; - bool test_local_interrupt; - - /*! \brief Path for the FAX image test files. */ - char image_path[1024]; - - /*! \brief Pointer to the XML document. */ - xmlDocPtr doc; - /*! \brief Pointer to our current step in the test. */ - xmlNodePtr cur; - - int repeat_min; - int repeat_max; - int repeat_count; - xmlNodePtr repeat_start; - xmlNodePtr repeat_parent; - - faxtester_flush_handler_t flush_handler; - void *flush_user_data; - - const uint8_t *image_buffer; - int image_len; - int image_ptr; - int image_bit_ptr; - - uint8_t image[1000000]; - - int ecm_frame_size; - int corrupt_crc; - - int final_delayed; - - fax_modems_state_t modems; - - /*! \brief CED or CNG detector */ - modem_connect_tones_rx_state_t connect_rx; - - /*! If true, transmission is in progress */ - bool transmit; - - /*! \brief true if the short training sequence should be used. */ - bool short_train; - - /*! \brief The currently select receiver type */ - int current_rx_type; - /*! \brief The currently select transmitter type */ - int current_tx_type; - - int wait_for_silence; - - int tone_state; - int64_t tone_on_time; - - int64_t timer; - int64_t timeout; - - bool test_for_call_clear; - int call_clear_timer; - - bool far_end_cleared_call; - - int timein_x; - int timeout_x; - - uint8_t awaited[1000]; - int awaited_len; - - char next_tx_file[1000]; - - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/*! Apply T.30 receive processing to a block of audio samples. - \brief Apply T.30 receive processing to a block of audio samples. - \param s The FAX tester context. - \param amp The audio sample buffer. - \param len The number of samples in the buffer. - \return The number of samples unprocessed. This should only be non-zero if - the software has reached the end of the FAX call. -*/ -int faxtester_rx(faxtester_state_t *s, int16_t *amp, int len); - -/*! Apply T.30 transmit processing to generate a block of audio samples. - \brief Apply T.30 transmit processing to generate a block of audio samples. - \param s The FAX tester context. - \param amp The audio sample buffer. - \param max_len The number of samples to be generated. - \return The number of samples actually generated. This will be zero when - there is nothing to send. -*/ -int faxtester_tx(faxtester_state_t *s, int16_t *amp, int max_len); - -void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc); - -void faxtester_set_rx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc); - -void faxtest_set_rx_silence(faxtester_state_t *s); - -void faxtester_send_hdlc_flags(faxtester_state_t *s, int flags); - -void faxtester_send_hdlc_msg(faxtester_state_t *s, const uint8_t *msg, int len, int crc_ok); - -void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data); - -/*! 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 - idle. FALSE to transmit zero length audio when the FAX transmitter is idle. The default - behaviour is FALSE. -*/ -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. -*/ -void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep); - -void faxtester_set_timeout(faxtester_state_t *s, int timeout); - -SPAN_DECLARE(int) faxtester_next_step(faxtester_state_t *s); - -/*! Get the logging context associated with a FAX tester context. - \brief Get the logging context associated with a FAX tester context. - \param s The FAX tester context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) faxtester_get_logging_state(faxtester_state_t *s); - -/*! Initialise a FAX tester context. - \brief Initialise a FAX tester context. - \param s The FAX tester context. - \param test_file The name of the file of XML test scripts. - \param test The name of the XML script test. - \return A pointer to the FAX context, or NULL if there was a problem. -*/ -faxtester_state_t *faxtester_init(faxtester_state_t *s, const char *test_file, const char *test); - -/*! Release a FAX context. - \brief Release a FAX context. - \param s The FAX tester context. - \return 0 for OK, else -1. */ -int faxtester_release(faxtester_state_t *s); - -/*! Free a FAX context. - \brief Free a FAX context. - \param s The FAX tester context. - \return 0 for OK, else -1. */ -int faxtester_free(faxtester_state_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c deleted file mode 100644 index 57de0da361..0000000000 --- a/libs/spandsp/tests/fax_tests.c +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_tests.c - Tests for the audio and T.38 FAX modules. - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2006, 2009, 2010 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 fax_tests_page FAX tests -\section fax_tests_page_sec_1 What does it do? -These tests exercise the following FAX to FAX paths: - -TSB85 <-----------+ +-----------> TSB85 - \ / - T.31 <-----------+ \ / +-----------> T.31 - \ \ / / - +--Modems-+-+-----------TDM/RTP-----------+-+-Modems--+ - | \ / | - | \ / | - T.30 <---+ T.38 gateway T.38 gateway +---> T.30 - | \ / | - | \ / | - +---T.38---+-+----+----UDPTL/RTP----+----+ +---T.38---+ - / / \ / \ \ - T.31 <------------/ / +----------TCP----------+ \ +------------> T.31 - / \ -TSB85 <------------+ +------------> TSB85 - -T.30<->Modems<-------------------------TDM/RTP------------------------->Modems<->T.30 -T.30<->Modems<-TDM/RTP->T.38 gateway<-UDPTL/RTP->T.38 gateway<-TDM/RTP->Modems<->T.30 -T.30<->Modems<-TDM/RTP->T.38 gateway<-UDPTL/RTP-------------------------->T.38<->T.30 -T.30<->T.38<--------------------------UDPTL/RTP->T.38 gateway<-TDM/RTP->Modems<->T.30 -T.30<->T.38<--------------------------UDPTL/RTP-------------------------->T.38<->T.30 - -The T.31 and TSB85 parts are incomplete right now. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#endif - -#if defined(HAVE_LIBXML_XMLMEMORY_H) -#include -#endif -#if defined(HAVE_LIBXML_PARSER_H) -#include -#endif -#if defined(HAVE_LIBXML_XINCLUDE_H) -#include -#endif - -#include "udptl.h" -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif -#include "fax_tester.h" -#include "fax_utils.h" -#include "pcap_parse.h" - -#define SAMPLES_PER_CHUNK 160 - -#define INPUT_TIFF_FILE_NAME "../test-data/itu/fax/itutests.tif" -#define OUTPUT_TIFF_FILE_NAME "fax_tests.tif" -#define INPUT_WAVE_FILE_NAME "fax_cap.wav" -#define OUTPUT_WAVE_FILE_NAME "fax_tests.wav" - -enum -{ - AUDIO_FAX = 1, - T38_FAX, - T31_AUDIO_FAX, - T31_T38_FAX, - TSB85_AUDIO_FAX, - TSB85_T38_FAX, - REPLAY_AUDIO_FAX, - REPLAY_T38_FAX, - AUDIO_TO_T38_GATEWAY, - PASSTHROUGH, - AUDIO_CHAN, - T38_CHAN -}; - -const char *output_tiff_file_name; - -struct audio_buf_s -{ - int16_t amp[SAMPLES_PER_CHUNK]; - int len; -}; - -struct chain_element_s -{ - int node_type; - int left_chan_type; - int right_chan_type; - struct - { - fax_state_t *fax_state; - t38_terminal_state_t *t38_state; - faxtester_state_t *faxtester_state; - t38_gateway_state_t *t38_gateway_state; - SNDFILE *wave_handle; - } node; - struct - { - g1050_state_t *g1050_path; - both_ways_line_model_state_t *line_model; - struct audio_buf_s *audio_in_buf; - struct audio_buf_s *audio_out_buf; - } path; - t30_state_t *t30_state; - t38_core_state_t *t38_core_state; - int t38_subst_seq; - bool phase_e_reached; - bool completed; - bool succeeded; - t30_exchanged_info_t expected_rx_info; - - awgn_state_t *awgn_state; - - struct audio_buf_s audio_buf[2]; - - int peer; - int t38_peer; - - char tag[10]; -}; - -struct chain_element_s chain[7]; -int chain_elements = 2; - -bool t38_simulate_incrementing_repeats = false; -bool use_receiver_not_ready = false; -bool test_local_interrupt = false; - -double when = 0.0; - -static int phase_b_handler(void *user_data, int result) -{ - int i; - int ch; - int status; - int len; - t30_state_t *s; - char tag[20]; - const char *u; - const uint8_t *v; - t30_exchanged_info_t *info; - - i = (int) (intptr_t) user_data; - s = chain[i].t30_state; - ch = i + 'A'; - info = &chain[i].expected_rx_info; - snprintf(tag, sizeof(tag), "%c: Phase B", ch); - printf("%c: Phase B handler - (0x%X) %s\n", ch, result, t30_frametype(result)); - fax_log_rx_parameters(s, tag); - status = T30_ERR_OK; - - if ((u = t30_get_rx_ident(s))) - { - printf("%c: Phase B remote ident '%s'\n", ch, u); - if (info->ident[0] && strcmp(info->ident, u)) - { - printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, info->ident); - status = T30_ERR_IDENT_UNACCEPTABLE; - } - } - else - { - if (info->ident[0]) - { - printf("%c: Phase B: remote ident missing!\n", ch); - status = T30_ERR_IDENT_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_sub_address(s))) - { - printf("%c: Phase B: remote sub-address '%s'\n", ch, u); - if (info->sub_address[0] && strcmp(info->sub_address, u)) - { - printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, info->sub_address); - status = T30_ERR_SUB_UNACCEPTABLE; - } - } - else - { - if (info->sub_address[0]) - { - printf("%c: Phase B: remote sub-address missing!\n", ch); - status = T30_ERR_SUB_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_polled_sub_address(s))) - { - printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u); - if (info->polled_sub_address[0] && strcmp(info->polled_sub_address, u)) - { - printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, info->polled_sub_address); - status = T30_ERR_PSA_UNACCEPTABLE; - } - } - else - { - if (info->polled_sub_address[0]) - { - printf("%c: Phase B: remote polled sub-address missing!\n", ch); - status = T30_ERR_PSA_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_selective_polling_address(s))) - { - printf("%c: Phase B: remote selective polling address '%s'\n", ch, u); - if (info->selective_polling_address[0] && strcmp(info->selective_polling_address, u)) - { - printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, info->selective_polling_address); - status = T30_ERR_SEP_UNACCEPTABLE; - } - } - else - { - if (info->selective_polling_address[0]) - { - printf("%c: Phase B: remote selective polling address missing!\n", ch); - status = T30_ERR_SEP_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_sender_ident(s))) - { - printf("%c: Phase B: remote sender ident '%s'\n", ch, u); - if (info->sender_ident[0] && strcmp(info->sender_ident, u)) - { - printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, info->sender_ident); - status = T30_ERR_SID_UNACCEPTABLE; - } - } - else - { - if (info->sender_ident[0]) - { - printf("%c: Phase B: remote sender ident missing!\n", ch); - status = T30_ERR_SID_UNACCEPTABLE; - } - } - if ((u = t30_get_rx_password(s))) - { - printf("%c: Phase B: remote password '%s'\n", ch, u); - if (info->password[0] && strcmp(info->password, u)) - { - printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, info->password); - status = T30_ERR_PWD_UNACCEPTABLE; - } - } - else - { - if (info->password[0]) - { - printf("%c: Phase B: remote password missing!\n", ch); - status = T30_ERR_PWD_UNACCEPTABLE; - } - } - if ((len = t30_get_rx_nsf(s, &v))) - { - printf("%c: Phase B: NSF %d bytes\n", ch, len); - if (info->nsf_len && (info->nsf_len != len || memcmp(info->nsf, v, len))) - { - printf("%c: Phase B: remote NSF incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsf_len); - } - } - else - { - if (info->nsf_len) - { - printf("%c: Phase B: remote NSF missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len); - } - } - if ((len = t30_get_rx_nsc(s, &v))) - { - printf("%c: Phase B: NSC %d bytes\n", ch, len); - if (info->nsc_len && (info->nsc_len != len || memcmp(info->nsc, v, len))) - { - printf("%c: Phase B: remote NSC incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsc_len); - } - } - else - { - if (info->nsc_len) - { - printf("%c: Phase B: remote NSC missing! - expected %u bytes\n", ch, (unsigned int) info->nsc_len); - } - } - if ((len = t30_get_rx_nss(s, &v))) - { - printf("%c: Phase B: NSS %d bytes\n", ch, len); - if (info->nss_len && (info->nss_len != len || memcmp(info->nss, v, len))) - { - printf("%c: Phase B: remote NSS incorrect! - expected %u bytes\n", ch, (unsigned int) info->nss_len); - } - } - else - { - if (info->nss_len) - { - printf("%c: Phase B: remote NSS missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len); - } - } - - return status; -} -/*- End of function --------------------------------------------------------*/ - -static int phase_d_handler(void *user_data, int result) -{ - int i; - int ch; - t30_state_t *s; - char tag[20]; - - i = (int) (intptr_t) user_data; - s = chain[i].t30_state; - ch = i + 'A'; - snprintf(tag, sizeof(tag), "%c: Phase D", ch); - printf("%c: Phase D handler - (0x%X) %s\n", ch, result, t30_frametype(result)); - fax_log_page_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); - - if (use_receiver_not_ready) - t30_set_receiver_not_ready(s, 3); - - if (test_local_interrupt) - { - if (i == 0) - { - printf("%c: Initiating interrupt request\n", ch); - t30_local_interrupt_request(s, true); - } - else - { - switch (result) - { - case T30_PIP: - case T30_PRI_MPS: - case T30_PRI_EOM: - case T30_PRI_EOP: - printf("%c: Accepting interrupt request\n", ch); - t30_local_interrupt_request(s, true); - break; - case T30_PIN: - break; - } - } - } - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static void phase_e_handler(void *user_data, int result) -{ - int i; - int ch; - t30_stats_t t; - t30_state_t *s; - char tag[20]; - - i = (int) (intptr_t) user_data; - s = chain[i].t30_state; - ch = i + 'A'; - snprintf(tag, sizeof(tag), "%c: Phase E", ch); - printf("%c: Phase E handler - (%d) %s\n", ch, result, t30_completion_code_to_str(result)); - fax_log_final_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); - t30_get_transfer_statistics(s, &t); - chain[i].succeeded = (result == T30_ERR_OK); - chain[i].phase_e_reached = true; -} -/*- End of function --------------------------------------------------------*/ - -static void real_time_t30_frame_handler(void *user_data, - bool incoming, - const uint8_t *msg, - int len) -{ - int i; - int ch; - - i = (intptr_t) user_data; - ch = i + 'A'; - printf("%c: Real time frame handler - %s, %s, length = %d\n", - ch, - (incoming) ? "line->T.30" : "T.30->line", - t30_frametype(msg[2]), - len); -} -/*- End of function --------------------------------------------------------*/ - -static int document_handler(void *user_data, int event) -{ - int i; - int ch; - - i = (intptr_t) user_data; - ch = i + 'A'; - printf("%c: Document handler - event %d\n", ch, event); - return false; -} -/*- End of function --------------------------------------------------------*/ - -static void set_t30_callbacks(t30_state_t *t30, int chan) -{ - t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) chan); - t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) chan); - t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) chan); - t30_set_real_time_frame_handler(t30, real_time_t30_frame_handler, (void *) (intptr_t) chan); - t30_set_document_handler(t30, document_handler, (void *) (intptr_t) chan); -} -/*- End of function --------------------------------------------------------*/ - -static void real_time_gateway_frame_handler(void *user_data, - bool incoming, - const uint8_t *msg, - int len) -{ - int i; - - i = (intptr_t) user_data; - printf("%c: Real time gateway frame handler - %s, %s, length = %d\n", - i + 'A', - (incoming) ? "PSTN->T.38" : "T.38->PSTN", - t30_frametype(msg[2]), - len); -} -/*- End of function --------------------------------------------------------*/ - -static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - int i; - int chan; - - /* This routine queues messages between two instances of T.38 processing */ - chan = (intptr_t) user_data; - if (t38_simulate_incrementing_repeats) - { - for (i = 0; i < count; i++) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", chain[chan].t38_subst_seq, len); - - if (g1050_put(chain[chan].path.g1050_path, buf, len, chain[chan].t38_subst_seq, when) < 0) - printf("Lost packet %d\n", chain[chan].t38_subst_seq); - chain[chan].t38_subst_seq = (chain[chan].t38_subst_seq + 1) & 0xFFFF; - } - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); - - for (i = 0; i < count; i++) - { - if (g1050_put(chain[chan].path.g1050_path, buf, len, s->tx_seq_no, when) < 0) - printf("Lost packet %d\n", s->tx_seq_no); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void t33_tests(void) -{ - int n; - int item_no; - int type; - uint8_t num[21]; - uint8_t new_t33[133]; - /* These patterns are from the T.33 spec */ - static const uint8_t *pkts[] = - { - (const uint8_t *) "#1234567890#1234", - (const uint8_t *) "1234#5678#8910", - (const uint8_t *) "#6174444100#1234#567", - (const uint8_t *) "1234#5678##2032223", - (const uint8_t *) "#2037445555##6446666", - (const uint8_t *) "#2037445555#1234##6446666#5678", - //(const uint8_t *) "#123456789012345678901#1234##6446666#5678", - (const uint8_t *) "" - }; - - printf("T.33 sub-address packing/unpacking tests\n"); - for (n = 0; pkts[n][0]; n++) - { - new_t33[0] = '\0'; - printf("'%s'\n", pkts[n]); - for (item_no = 0; item_no < 100; item_no++) - { - if ((type = t33_sub_address_extract_field(num, pkts[n], item_no)) <= 0) - { - if (type == T33_NONE) - break; - printf("Bad sub-address field\n"); - exit(2); - } - switch (type) - { - case T33_SST: - printf("SST '%s'\n", num); - t33_sub_address_add_field(new_t33, num, type); - break; - case T33_EXT: - printf(" EXT '%s'\n", num); - t33_sub_address_add_field(new_t33, num, type); - break; - } - } - if (strcmp((const char *) pkts[n], (const char *) new_t33)) - { - printf("Re-encode mismatch '%s' '%s'\n", pkts[n], new_t33); - exit(2); - } - } -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int16_t silence[SAMPLES_PER_CHUNK]; - int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK]; - int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK]; - int16_t audio_log[SAMPLES_PER_CHUNK*4]; - int hist_ptr; - int log_audio; - int msg_len; - uint8_t msg[1024]; - int outframes; - SNDFILE *wave_handle; - bool use_ecm; - bool use_tep; - bool use_polled_mode; - bool use_transmit_on_idle; - bool feedback_audio; - int t38_version; - const char *input_tiff_file_name; - const char *replay_file_name; - int i; - int j; - int k; - int seq_no; - int g1050_model_no; - int g1050_speed_pattern_no; - int t38_transport; - double tx_when; - double rx_when; - int supported_modems; - int opt; - int start_page; - int end_page; - int drop_frame; - int drop_frame_rate; - float signal_scaling; - int signal_level; - 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; - int expected_pages; - char *page_header_info; - char *page_header_tz; - const char *xml_file_name; - const char *xml_test_name[2]; - int xml_step; - char buf[132 + 1]; - int line_model_no; - int channel_codec; - int rbs_pattern; -#if defined(ENABLE_GUI) - int use_gui; -#endif - -#if defined(ENABLE_GUI) - use_gui = false; -#endif - log_audio = false; - use_ecm = false; - t38_version = 1; - input_tiff_file_name = INPUT_TIFF_FILE_NAME; - output_tiff_file_name = OUTPUT_TIFF_FILE_NAME; - 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; - use_polled_mode = false; - supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; - page_header_info = NULL; - page_header_tz = NULL; - drop_frame = 0; - drop_frame_rate = 0; - start_page = -1; - end_page = -1; - signal_level = 0; - noise_level = -99; - scan_line_time = 0; - replay_file_name = INPUT_WAVE_FILE_NAME; - code_to_look_up = -1; - allowed_bilevel_resolutions[0] = 0; - allowed_bilevel_resolutions[1] = 0; - allowed = 0; - line_model_no = 0; - channel_codec = MUNGE_CODEC_NONE; - rbs_pattern = 0; - colour_enabled = false; - t37_like_output = false; - t38_transport = T38_TRANSPORT_UDPTL; - xml_file_name = "../spandsp/tsb85.xml"; - xml_test_name[0] = "MRGN01"; - xml_test_name[1] = "MRGN01"; - xml_step = 0; - while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:Ps:S:tT:u:v:x:X: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': - replay_file_name = optarg; - break; - case 'D': - drop_frame_rate = - drop_frame = atoi(optarg); - break; - case 'e': - use_ecm = true; - break; - case 'f': - feedback_audio = true; - break; - case 'F': - remove_fill_bits = true; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'H': - page_header_info = optarg; - break; - case 'i': - input_tiff_file_name = optarg; - break; - case 'I': - t38_simulate_incrementing_repeats = true; - break; - case 'l': - log_audio = true; - break; - case 'm': - supported_modems = atoi(optarg); - break; - case 'M': - g1050_model_no = optarg[0] - 'A' + 1; - break; - case 'n': - noise_level = atoi(optarg); - break; - case 'p': - /* - -p FAX-audio-FAX - -p FAX-T38-FAX - -p FAX-audio-T38gateway-T38-T38gateway-audio-FAX - -p FAX-T38-T38gateway-audio-T38gateway-T38-FAX - -p FAX-T38-T38gateway-audio-FAX - -p FAX-audio-T38gateway-T38-FAX - -p tester-audio-FAX - -p tester-T38-FAX - -p tester-audio-T38gateway-T38-T38gateway-audio-FAX - -p tester-T38-T38gateway-audio-T38gateway-T38-FAX - -p tester-T38-T38gateway-audio-FAX - -p tester-audio-T38gateway-T38-FAX - */ - for (i = 0, chain_elements = 0, k = 0; chain_elements < 7; i++) - { - if (optarg[i] != '-' && optarg[i] != '\0') - continue; - j = optarg[i]; - optarg[i] = '\0'; - if (strcmp(&optarg[k], "FAX") == 0) - { - chain[chain_elements++].node_type = AUDIO_FAX; - } - else if (strcmp(&optarg[k], "T38") == 0) - { - chain[chain_elements++].node_type = T38_FAX; - } - else if (strcmp(&optarg[k], "T31") == 0) - { - chain[chain_elements++].node_type = T31_AUDIO_FAX; - } - else if (strcmp(&optarg[k], "tester") == 0) - { - chain[chain_elements++].node_type = TSB85_AUDIO_FAX; - } - else if (strcmp(&optarg[k], "replay") == 0) - { - chain[chain_elements++].node_type = REPLAY_AUDIO_FAX; - } - else if (strcmp(&optarg[k], "T38gateway") == 0) - { - chain[chain_elements++].node_type = AUDIO_TO_T38_GATEWAY; - } - else if (strcmp(&optarg[k], "passthrough") == 0) - { - chain[chain_elements++].node_type = PASSTHROUGH; - } - else - { - fprintf(stderr, "Unknown FAX path element %s\n", &optarg[k]); - exit(2); - } - k = i + 1; - if (j == '\0') - break; - } -#if 0 - if ((chain[0].node_type == AUDIO_FAX && chain[chain_elements - 1].node_type != AUDIO_FAX) - || - (chain[0].node_type != AUDIO_FAX && chain[chain_elements - 1].node_type == AUDIO_FAX)) - { - fprintf(stderr, "Invalid FAX path\n"); - exit(2); - } -#endif - break; - case 'P': - use_polled_mode = true; - break; - case 's': - g1050_speed_pattern_no = atoi(optarg); - break; -#if 0 - case 's': - signal_level = atoi(optarg); - break; -#endif - case 'S': - scan_line_time = atoi(optarg); - break; - case 't': - use_tep = true; - break; - case 'T': - start_page = 0; - end_page = atoi(optarg); - break; - case 'u': - if (strcasecmp(optarg, "udptl") == 0) - t38_transport = T38_TRANSPORT_UDPTL; - else if (strcasecmp(optarg, "rtp") == 0) - t38_transport = T38_TRANSPORT_RTP; - else if (strcasecmp(optarg, "tcp") == 0) - t38_transport = T38_TRANSPORT_TCP; - else if (strcasecmp(optarg, "tcp-tpkt") == 0) - t38_transport = T38_TRANSPORT_TCP_TPKT; - else - { - fprintf(stderr, "Unknown T.38 transport mode\n"); - exit(2); - } - break; - case 'v': - t38_version = atoi(optarg); - break; - case 'x': - xml_test_name[xml_step] = optarg; - xml_step ^= 1; - break; - case 'X': - xml_file_name = optarg; - break; - case 'z': - page_header_tz = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - - if (code_to_look_up >= 0) - { - printf("Result code %d is %s\n", code_to_look_up, t30_completion_code_to_str(code_to_look_up)); - exit(0); - } - - printf("Using T.38 version %d\n", t38_version); - if (use_ecm) - printf("Using ECM\n"); - - wave_handle = NULL; - if (log_audio) - { - if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 4)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - memset(silence, 0, sizeof(silence)); - - srand48(0x1234567); - - memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a)); - memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b)); - - /* Set up the nodes */ - chain[0].peer = chain_elements - 1; - chain[chain_elements - 1].peer = 0; - - for (i = 0; i < chain_elements; i++) - { - chain[i].tag[0] = i + 'A'; - chain[i].tag[1] = '\0'; - - memset(&chain[i].audio_buf[0], 0, sizeof(chain[i].audio_buf[0])); - memset(&chain[i].audio_buf[1], 0, sizeof(chain[i].audio_buf[1])); - memset(&chain[i].expected_rx_info, 0, sizeof(chain[i].expected_rx_info)); - - switch (chain[i].node_type) - { - case AUDIO_FAX: - if ((chain[i].node.fax_state = fax_init(NULL, (i == 0))) == NULL) - { - fprintf(stderr, " Cannot start FAX instance\n"); - exit(2); - } - chain[i].t30_state = fax_get_t30_state(chain[i].node.fax_state); - - logging = fax_get_logging_state(chain[i].node.fax_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - logging = t30_get_logging_state(chain[i].t30_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - set_t30_callbacks(chain[i].t30_state, i); - - chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0]; - chain[i].path.audio_out_buf = &chain[i].audio_buf[0]; - - chain[i].awgn_state = NULL; - signal_scaling = 1.0f; - if (noise_level > -99) - { - chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level); - signal_scaling = powf(10.0f, signal_level/20.0f); - printf("Signal scaling %f\n", signal_scaling); - } - break; - case T38_FAX: - if ((chain[i].node.t38_state = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL) - { - fprintf(stderr, " Cannot start the T.38 terminal instance\n"); - exit(2); - } - chain[i].t30_state = t38_terminal_get_t30_state(chain[i].node.t38_state); - chain[i].t38_core_state = t38_terminal_get_t38_core_state(chain[i].node.t38_state); - - logging = t38_terminal_get_logging_state(chain[i].node.t38_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - logging = t38_core_get_logging_state(chain[i].t38_core_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - logging = t30_get_logging_state(chain[i].t30_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - set_t30_callbacks(chain[i].t30_state, i); - - if (i == 0) - { - chain[i].t38_peer = i + 1; - } - else - { - switch (chain[i - 1].node_type) - { - case T38_FAX: - case AUDIO_TO_T38_GATEWAY: - chain[i].t38_peer = i - 1; - break; - default: - chain[i].t38_peer = i + 1; - break; - } - } - break; - case T31_AUDIO_FAX: - break; - case T31_T38_FAX: - break; - case TSB85_AUDIO_FAX: - case TSB85_T38_FAX: - if ((chain[i].node.faxtester_state = faxtester_init(NULL, xml_file_name, xml_test_name[(i == 0) ? 0 : 1])) == NULL) - { - fprintf(stderr, " Cannot start FAX tester instance\n"); - exit(2); - } - logging = faxtester_get_logging_state(chain[i].node.faxtester_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - faxtester_set_transmit_on_idle(chain[i].node.faxtester_state, true); - - chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0]; - chain[i].path.audio_out_buf = &chain[i].audio_buf[0]; - - if (i == 0) - { - chain[i].t38_peer = i + 1; - } - else - { - switch (chain[i - 1].node_type) - { - case T38_FAX: - case AUDIO_TO_T38_GATEWAY: - chain[i].t38_peer = i - 1; - break; - default: - chain[i].t38_peer = i + 1; - break; - } - } - - chain[i].awgn_state = NULL; - signal_scaling = 1.0f; - if (noise_level > -99) - { - chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level); - signal_scaling = powf(10.0f, signal_level/20.0f); - printf("Signal scaling %f\n", signal_scaling); - } - break; - case REPLAY_AUDIO_FAX: - if ((chain[i].node.wave_handle = sf_open_telephony_read(replay_file_name, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", replay_file_name); - exit(2); - } - - chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0]; - chain[i].path.audio_out_buf = &chain[i].audio_buf[0]; - break; - case AUDIO_TO_T38_GATEWAY: - if ((chain[i].node.t38_gateway_state = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL) - { - fprintf(stderr, " Cannot start T.38 gateway instance\n"); - exit(2); - } - chain[i].t38_core_state = t38_gateway_get_t38_core_state(chain[i].node.t38_gateway_state); - - logging = t38_gateway_get_logging_state(chain[i].node.t38_gateway_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - logging = fax_modems_get_logging_state(&chain[i].node.t38_gateway_state->audio.modems); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - logging = t38_core_get_logging_state(chain[i].t38_core_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, chain[i].tag); - - t38_gateway_set_transmit_on_idle(chain[i].node.t38_gateway_state, use_transmit_on_idle); - t38_gateway_set_supported_modems(chain[i].node.t38_gateway_state, supported_modems); - //t38_gateway_set_nsx_suppression(chain[i].node.t38_state, NULL, 0, NULL, 0); - t38_gateway_set_fill_bit_removal(chain[i].node.t38_gateway_state, remove_fill_bits); - t38_gateway_set_real_time_frame_handler(chain[i].node.t38_gateway_state, real_time_gateway_frame_handler, (void *) (intptr_t) i); - t38_gateway_set_ecm_capability(chain[i].node.t38_gateway_state, use_ecm); - t38_set_t38_version(chain[i].t38_core_state, t38_version); - - if (i == 0) - { - chain[i].t38_peer = i + 1; - chain[i].path.audio_in_buf = NULL; - } - else - { - switch (chain[i - 1].node_type) - { - case T38_FAX: - case AUDIO_TO_T38_GATEWAY: - chain[i].t38_peer = i - 1; - chain[i].path.audio_in_buf = &chain[i + 1].audio_buf[0]; - break; - default: - chain[i].t38_peer = i + 1; - chain[i].path.audio_in_buf = &chain[i - 1].audio_buf[0]; - break; - } - } - - chain[i].path.audio_out_buf = &chain[i].audio_buf[0]; - - chain[i].awgn_state = NULL; - signal_scaling = 1.0f; - if (noise_level > -99) - { - chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level); - signal_scaling = powf(10.0f, signal_level/20.0f); - printf("Signal scaling %f\n", signal_scaling); - } - } - if ((chain[i].path.g1050_path = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL) - { - fprintf(stderr, " Failed to start IP network path model\n"); - exit(2); - } - } - - for (i = 0; i < chain_elements; i++) - { - j = i + 1; - if (chain[i].t30_state) - { - sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j); - t30_set_tx_ident(chain[i].t30_state, buf); - strcpy(chain[chain[i].peer].expected_rx_info.ident, buf); - sprintf(buf, "Sub-address %d", j); - t30_set_tx_sub_address(chain[i].t30_state, buf); - //strcpy(chain[chain[i].peer].expected_rx_info.sub_address, buf); - sprintf(buf, "Sender ID %d", j); - t30_set_tx_sender_ident(chain[i].t30_state, buf); - //strcpy(chain[chain[i].peer].expected_rx_info.sender_ident, buf); - sprintf(buf, "Password %d", j); - t30_set_tx_password(chain[i].t30_state, buf); - //strcpy(chain[chain[i].peer].expected_rx_info.password, buf); - sprintf(buf, "Polled sub-add %d", j); - t30_set_tx_polled_sub_address(chain[i].t30_state, buf); - //strcpy(chain[chain[i].peer].expected_rx_info.polled_sub_address, buf); - sprintf(buf, "Select poll add %d", j); - t30_set_tx_selective_polling_address(chain[i].t30_state, buf); - //strcpy(chain[chain[i].peer].expected_rx_info.selective_polling_address, buf); - t30_set_tx_page_header_info(chain[i].t30_state, page_header_info); - if (page_header_tz) - t30_set_tx_page_header_tz(chain[i].t30_state, page_header_tz); - - if (i != 0) - { - t30_set_tx_nsf(chain[i].t30_state, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); - chain[chain[i].peer].expected_rx_info.nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00"; - chain[chain[i].peer].expected_rx_info.nsf_len = 12; - } - - t30_set_supported_modems(chain[i].t30_state, supported_modems); - t30_set_supported_t30_features(chain[i].t30_state, - T30_SUPPORT_IDENTIFICATION - | T30_SUPPORT_SELECTIVE_POLLING - | T30_SUPPORT_SUB_ADDRESSING); - t30_set_supported_image_sizes(chain[i].t30_state, - 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 == 0) ? 0 : 1]) - { - case 0: - /* Allow anything */ - t30_set_supported_bilevel_resolutions(chain[i].t30_state, - 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(chain[i].t30_state, - 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(chain[i].t30_state, - 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(chain[i].t30_state, - 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(chain[i].t30_state, - T4_RESOLUTION_R8_STANDARD - | T4_RESOLUTION_200_100); - break; - } - if (colour_enabled) - { - t30_set_supported_colour_resolutions(chain[i].t30_state, - 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_colour_resolutions(chain[i].t30_state, 0); - } - if (t37_like_output) - { - t30_set_supported_output_compressions(chain[i].t30_state, - T4_COMPRESSION_T85 - | T4_COMPRESSION_T85_L0 - | T4_COMPRESSION_T6 - | T4_COMPRESSION_T42_T81); - } - else - { - t30_set_supported_output_compressions(chain[i].t30_state, - T4_COMPRESSION_T6 - | T4_COMPRESSION_JPEG); - } - - t30_set_ecm_capability(chain[i].t30_state, use_ecm); - t30_set_supported_compressions(chain[i].t30_state, - 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(chain[i].t30_state, scan_line_time); - } - - switch (chain[i].node_type) - { - case AUDIO_FAX: - fax_set_transmit_on_idle(chain[i].node.fax_state, use_transmit_on_idle); - fax_set_tep_mode(chain[i].node.fax_state, use_tep); - break; - case T38_FAX: - t38_set_t38_version(chain[i].t38_core_state, t38_version); - //t30_set_iaf_mode(chain[i].t30_state, T30_IAF_MODE_NO_FILL_BITS); - switch (t38_transport) - { - case T38_TRANSPORT_UDPTL: - case T38_TRANSPORT_RTP: - t38_terminal_set_fill_bit_removal(chain[i].node.t38_state, remove_fill_bits); - t38_terminal_set_tep_mode(chain[i].node.t38_state, use_tep); - break; - case T38_TRANSPORT_TCP: - case T38_TRANSPORT_TCP_TPKT: - t38_terminal_set_fill_bit_removal(chain[i].node.t38_state, true); - t38_terminal_set_config(chain[i].node.t38_state, T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS); - t38_terminal_set_tep_mode(chain[i].node.t38_state, false); - break; - } - break; - } - } - - for (i = 0; i < chain_elements; i++) - { - switch (chain[i].node_type) - { - case TSB85_AUDIO_FAX: - case TSB85_T38_FAX: - if (chain[chain[i].peer].node_type == AUDIO_FAX) - chain[i].node.faxtester_state->far_fax = chain[chain[i].peer].node.fax_state; - else - chain[i].node.faxtester_state->far_t38 = chain[chain[i].peer].node.t38_state; - chain[i].node.faxtester_state->far_t30 = chain[chain[i].peer].t30_state; - chain[i].node.faxtester_state->far_tag = chain[i].peer + 'A'; - - while (faxtester_next_step(chain[i].node.faxtester_state) == 0) - /*dummy loop*/; - /*endwhile*/ - break; - case REPLAY_AUDIO_FAX: - break; - case PASSTHROUGH: - if (chain[i - 1].path.audio_in_buf == &chain[i].audio_buf[0]) - chain[i - 1].path.audio_in_buf = &chain[i + 1].audio_buf[0]; - if (chain[i + 1].path.audio_in_buf == &chain[i].audio_buf[0]) - chain[i + 1].path.audio_in_buf = &chain[i - 1].audio_buf[0]; - break; - } - } - - switch (chain[chain_elements - 1].node_type) - { - case AUDIO_FAX: - case T38_FAX: - k = (use_polled_mode) ? (chain_elements - 1) : 0; - if (chain[k].t30_state) - t30_set_tx_file(chain[k].t30_state, input_tiff_file_name, start_page, end_page); - break; - } - switch (chain[0].node_type) - { - case AUDIO_FAX: - case T38_FAX: - k = (use_polled_mode) ? 0 : (chain_elements - 1); - if (chain[k].t30_state) - t30_set_rx_file(chain[k].t30_state, output_tiff_file_name, -1); - break; - } - -#if defined(ENABLE_GUI) - if (use_gui) - start_media_monitor(); -#endif - hist_ptr = 0; - for (;;) - { - memset(audio_log, 0, sizeof(audio_log)); - - for (i = 0; i < chain_elements; i++) - { - /* Update T.30 timing */ - switch (chain[i].node_type) - { - case AUDIO_FAX: - /* Update timing */ - logging = t30_get_logging_state(chain[i].t30_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); - logging = fax_get_logging_state(chain[i].node.fax_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); - logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); -#if 0 - /* Probe inside the modems to update their logs */ - span_log_bump_samples(chain[i].node.fax_state->modems.v27ter_rx.logging, len); - span_log_bump_samples(chain[i].node.fax_state->modems.v29_rx.logging, len); - span_log_bump_samples(chain[i].node.fax_state->modems.v17_rx.logging, len); -#endif - -#if 0 - /* Mute the signal */ - vec_zeroi16(chain[i].path.audio_in_buf->amp, SAMPLES_PER_CHUNK); - chain[i].path.audio_in_buf->len = SAMPLES_PER_CHUNK; -#endif - if (log_audio) - { - k = (i == 0) ? 0 : 2; - for (j = 0; j < chain[i].path.audio_in_buf->len; j++) - audio_log[4*j + k] = chain[i].path.audio_in_buf->amp[j]; - } - fax_rx(chain[i].node.fax_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len); - if (!t30_call_active(chain[i].t30_state)) - { - chain[i].completed = true; - continue; - } - - chain[i].path.audio_out_buf->len = fax_tx(chain[i].node.fax_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK); - if (!use_transmit_on_idle) - { - /* The receive side always expects a full block of samples, but the - transmit side may not be sending any when it doesn't need to. We - may need to pad with some silence. */ - if (chain[i].path.audio_out_buf->len < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&chain[i].path.audio_out_buf->amp[chain[i].path.audio_out_buf->len], SAMPLES_PER_CHUNK - chain[i].path.audio_out_buf->len); - chain[i].path.audio_out_buf->len = SAMPLES_PER_CHUNK; - } - } - if (chain[i].awgn_state) - { - for (j = 0; j < chain[i].path.audio_out_buf->len; j++) - chain[i].path.audio_out_buf->amp[j] = ((int16_t) (chain[i].path.audio_out_buf->amp[j]*signal_scaling)) + awgn(chain[i].awgn_state); - } - if (log_audio) - { - k = (i == 0) ? 1 : 3; - for (j = 0; j < chain[i].path.audio_out_buf->len; j++) - audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j]; - } - if (feedback_audio) - { - for (j = 0; j < chain[i].path.audio_out_buf->len; j++) - chain[i].path.audio_out_buf->amp[j] += t38_amp_hist_a[hist_ptr][j] >> 1; - memcpy(t38_amp_hist_a[hist_ptr], chain[i].path.audio_out_buf->amp, sizeof(int16_t)*SAMPLES_PER_CHUNK); - } - break; - case T38_FAX: - /* Update timing */ - logging = t30_get_logging_state(chain[i].t30_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); - logging = t38_terminal_get_logging_state(chain[i].node.t38_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); - logging = t38_core_get_logging_state(chain[i].t38_core_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); - - chain[i].completed = t38_terminal_send_timeout(chain[i].node.t38_state, SAMPLES_PER_CHUNK); - - while ((msg_len = g1050_get(chain[i].path.g1050_path, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(seq_no, tx_when, rx_when); -#endif - t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no); - } - break; - case TSB85_AUDIO_FAX: - /* Update timing */ - logging = faxtester_get_logging_state(chain[i].node.faxtester_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); -#if 0 - /* Probe inside the modems to update their logs */ - span_log_bump_samples(&chain[i].node.faxtester_state->modems.v27ter_rx.logging, len); - span_log_bump_samples(&chain[i].node.faxtester_state->modems.v29_rx.logging, len); - span_log_bump_samples(&chain[i].node.faxtester_state->modems.v17_rx.logging, len); -#endif - - if (log_audio) - { - k = (i == 0) ? 0 : 2; - for (j = 0; j < chain[i].path.audio_in_buf->len; j++) - audio_log[4*j + k] = chain[i].path.audio_in_buf->amp[j]; - } - faxtester_rx(chain[i].node.faxtester_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len); - chain[i].path.audio_out_buf->len = faxtester_tx(chain[i].node.faxtester_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK); - if (chain[i].path.audio_out_buf->len == 0) - break; - if (log_audio) - { - k = (i == 0) ? 1 : 3; - for (j = 0; j < chain[i].path.audio_out_buf->len; j++) - audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j]; - } - if (chain[i].node.faxtester_state->test_for_call_clear && !chain[i].node.faxtester_state->far_end_cleared_call) - { - chain[i].node.faxtester_state->call_clear_timer += chain[i].path.audio_out_buf->len; - if (!t30_call_active(chain[i].node.faxtester_state->far_t30)) - { - span_log(faxtester_get_logging_state(chain[i].node.faxtester_state), - SPAN_LOG_FLOW, - "Far end cleared after %dms (limits %dms to %dms)\n", - chain[i].node.faxtester_state->call_clear_timer/8, - chain[i].node.faxtester_state->timein_x, - chain[i].node.faxtester_state->timeout); - if (chain[i].node.faxtester_state->call_clear_timer/8 < chain[i].node.faxtester_state->timein_x || chain[i].node.faxtester_state->call_clear_timer/8 > chain[i].node.faxtester_state->timeout_x) - { - printf("Test failed\n"); - exit(2); - } - span_log(faxtester_get_logging_state(chain[i].node.faxtester_state), SPAN_LOG_FLOW, "Clear time OK\n"); - chain[i].node.faxtester_state->far_end_cleared_call = true; - chain[i].node.faxtester_state->test_for_call_clear = false; - while (faxtester_next_step(chain[i].node.faxtester_state) == 0) - /*dummy loop*/; - /*endwhile*/ - } - /*endif*/ - } - /*endif*/ - break; - case REPLAY_AUDIO_FAX: - chain[i].path.audio_out_buf->len = sf_readf_short(chain[i].node.wave_handle, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK); - if (chain[i].path.audio_out_buf->len == 0) - break; - break; - case AUDIO_TO_T38_GATEWAY: - /* Update timing */ - logging = t38_gateway_get_logging_state(chain[i].node.t38_gateway_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); - logging = t38_core_get_logging_state(chain[i].t38_core_state); - span_log_bump_samples(logging, SAMPLES_PER_CHUNK); -#if 0 - /* Probe inside the modems to update their logs */ - span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v27ter_rx.logging, len); - span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v29_rx.logging, len); - span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v17_rx.logging, len); -#endif - - if (drop_frame_rate && --drop_frame == 0) - { - drop_frame = drop_frame_rate; - if (t38_gateway_rx_fillin(chain[i].node.t38_gateway_state, SAMPLES_PER_CHUNK)) - break; - } - else - { - if (t38_gateway_rx(chain[i].node.t38_gateway_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len)) - break; - } - - chain[i].path.audio_out_buf->len = t38_gateway_tx(chain[i].node.t38_gateway_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK); - if (!use_transmit_on_idle) - { - if (chain[i].path.audio_out_buf->len < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&chain[i].path.audio_out_buf->amp[chain[i].path.audio_out_buf->len], SAMPLES_PER_CHUNK - chain[i].path.audio_out_buf->len); - chain[i].path.audio_out_buf->len = SAMPLES_PER_CHUNK; - } - } - if (feedback_audio) - { - for (j = 0; j < chain[i].path.audio_out_buf->len; j++) - chain[i].path.audio_out_buf->amp[j] += t38_amp_hist_a[hist_ptr][j] >> 1; - vec_movei16(t38_amp_hist_a[hist_ptr], chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK); - } - -#if 0 - if (log_audio) - { - k = (i == 0) ? 1 : 3; - for (j = 0; j < chain[i].path.audio_out_buf->len; j++) - audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j]; - } -#endif - while ((msg_len = g1050_get(chain[i].path.g1050_path, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(seq_no, tx_when, rx_when); -#endif - t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no); - } - break; - } - } - if (log_audio) - { - outframes = sf_writef_short(wave_handle, audio_log, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - break; - } - - when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE; - - if (chain[0].completed && chain[chain_elements - 1].completed) - break; -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_update_display(); -#endif - if (++hist_ptr > 3) - hist_ptr = 0; - } - - for (i = 0; i < chain_elements; i++) - { - switch (chain[i].node_type) - { - case AUDIO_TO_T38_GATEWAY: - t38_gateway_get_transfer_statistics(chain[i].node.t38_gateway_state, &t38_stats); - printf("%c side exchanged %d pages at %dbps, in %s mode\n", - i + 'A', - t38_stats.pages_transferred, - t38_stats.bit_rate, - (t38_stats.error_correcting_mode) ? "ECM" : "non-ECM"); - break; - } - } - if (log_audio) - { - if (sf_close_telephony(wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - /* Check how many pages should have been transferred */ - expected_pages = get_tiff_total_pages(input_tiff_file_name); - if (end_page >= 0 && expected_pages > end_page + 1) - expected_pages = end_page + 1; - if (start_page >= 0) - expected_pages -= start_page; - /* Check how many pages were transferred */ - for (j = 0; j < 2; j++) - { - i = (j == 0) ? 0 : (chain_elements - 1); - if (!chain[i].phase_e_reached) - break; - if (!chain[i].succeeded) - break; - - t30_get_transfer_statistics(chain[i].t30_state, &t30_stats); - if ((!use_polled_mode && i != 0) || (use_polled_mode && i == 0)) - { - if (t30_stats.pages_tx != 0 || t30_stats.pages_rx != expected_pages) - break; - } - else - { - if (t30_stats.pages_tx != expected_pages || t30_stats.pages_rx != 0) - break; - } - } - for (i = 0; i < chain_elements; i++) - { - switch (chain[i].node_type) - { - case AUDIO_FAX: - fax_free(chain[i].node.fax_state); - break; - case T38_FAX: - t38_terminal_free(chain[i].node.t38_state); - break; - case TSB85_AUDIO_FAX: - case TSB85_T38_FAX: - faxtester_free(chain[i].node.faxtester_state); - break; - case REPLAY_AUDIO_FAX: - if (sf_close_telephony(chain[i].node.wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", replay_file_name); - exit(2); - } - chain[i].node.wave_handle = NULL; - break; - case AUDIO_TO_T38_GATEWAY: - t38_gateway_free(chain[i].node.t38_gateway_state); - break; - } - if (chain[i].path.g1050_path) - { - g1050_free(chain[i].path.g1050_path); - chain[i].path.g1050_path = NULL; - } - } - if (j < 2) - { - printf("Tests failed\n"); - exit(2); - } - t33_tests(); - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fax_tests.sh b/libs/spandsp/tests/fax_tests.sh deleted file mode 100755 index 140d8fddf9..0000000000 --- a/libs/spandsp/tests/fax_tests.sh +++ /dev/null @@ -1,401 +0,0 @@ -#!/bin/sh -# -# spandsp fax tests -# -# 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 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. - -run_fax_test() -{ - rm -f fax_tests.tif - echo ./fax_tests ${OPTS} -i ${FILE} - ./fax_tests ${OPTS} -i ${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 ${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_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 FAX-FAX" "-p T38-T38" "-p FAX-T38gateway-T38gateway-FAX" "-p T38-T38gateway-FAX" "-p FAX-T38gateway-T38" -#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 FAX-FAX -C -e" "-p T38-T38 -C -e" "-p FAX-T38gateway-T38gateway-FAX -C -e" "-p T38-T38gateway-FAX -C -e" "-p FAX-T38gateway-T38 -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 FAX-FAX" "-p FAX-FAX -e" "-p T38-T38" "-p T38-T38 -e" "-p FAX-T38gateway-T38gateway-FAX" "-p FAX-T38gateway-T38gateway-FAX -e" "-p T38-T38gateway-FAX" "-p T38-T38gateway-FAX -e" "-p FAX-T38gateway-T38" "-p FAX-T38gateway-T38 -e" -do - 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 FAX-FAX" "-p FAX-FAX -e" "-p T38-T38" "-p T38-T38 -e" "-p FAX-T38gateway-T38gateway-FAX" "-p FAX-T38gateway-T38gateway-FAX -e" "-p T38-T38gateway-FAX" "-p T38-T38gateway-FAX -e" "-p FAX-T38gateway-T38" "-p FAX-T38gateway-T38 -e" -do - FILE="${ITUTESTS_DIR}/itutests.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/100pages.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/striped.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/mixed_size_pages.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_R8_385_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R8_385_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R8_385_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_R8_77_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R8_77_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R8_77_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_R8_154_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R8_154_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R8_154_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_R16_154_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R16_154_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_R16_154_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_200_100_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_200_100_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_200_100_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_200_200_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_200_200_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_200_200_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_200_400_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_200_400_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_200_400_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_300_300_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_300_300_B4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_300_300_A3.tif" - run_fax_test - - - FILE="${ITUTESTS_DIR}/bilevel_300_600_A4.tif" - run_fax_test - - FILE="${ITUTESTS_DIR}/bilevel_300_600_B4.tif" - run_fax_test - - 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 - -echo -echo All fax tests successfully completed - diff --git a/libs/spandsp/tests/fax_utils.c b/libs/spandsp/tests/fax_utils.c deleted file mode 100644 index 7491d862f3..0000000000 --- a/libs/spandsp/tests/fax_utils.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_utils.c - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" -#include "fax_utils.h" - -void fax_log_tx_parameters(t30_state_t *s, const char *tag) -{ - const char *u; - - if ((u = t30_get_tx_ident(s))) - printf("%s: Local ident '%s'\n", tag, u); - if ((u = t30_get_tx_sub_address(s))) - printf("%s: Local sub-address '%s'\n", tag, u); - if ((u = t30_get_tx_polled_sub_address(s))) - printf("%s: Local polled sub-address '%s'\n", tag, u); - if ((u = t30_get_tx_selective_polling_address(s))) - printf("%s: Local selective polling address '%s'\n", tag, u); - if ((u = t30_get_tx_sender_ident(s))) - printf("%s: Local sender ident '%s'\n", tag, u); - if ((u = t30_get_tx_password(s))) - printf("%s: Local password '%s'\n", tag, u); -} -/*- End of function --------------------------------------------------------*/ - -void fax_log_rx_parameters(t30_state_t *s, const char *tag) -{ - const char *u; - - if ((u = t30_get_rx_ident(s))) - printf("%s: Remote ident '%s'\n", tag, u); - if ((u = t30_get_rx_sub_address(s))) - printf("%s: Remote sub-address '%s'\n", tag, u); - if ((u = t30_get_rx_polled_sub_address(s))) - printf("%s: Remote polled sub-address '%s'\n", tag, u); - if ((u = t30_get_rx_selective_polling_address(s))) - printf("%s: Remote selective polling address '%s'\n", tag, u); - if ((u = t30_get_rx_sender_ident(s))) - printf("%s: Remote sender ident '%s'\n", tag, u); - if ((u = t30_get_rx_password(s))) - printf("%s: Remote password '%s'\n", tag, u); - if ((u = t30_get_rx_country(s))) - printf("%s: Remote was made in '%s'\n", tag, u); - if ((u = t30_get_rx_vendor(s))) - printf("%s: Remote was made by '%s'\n", tag, u); - if ((u = t30_get_rx_model(s))) - printf("%s: Remote is model '%s'\n", tag, u); -} -/*- End of function --------------------------------------------------------*/ - -void fax_log_final_transfer_statistics(t30_state_t *s, const char *tag) -{ - t30_stats_t t; - - t30_get_transfer_statistics(s, &t); - printf("%s: Bit rate %d\n", tag, t.bit_rate); - printf("%s: ECM %s\n", tag, (t.error_correcting_mode) ? "on" : "off"); - printf("%s: RTP events %d. RTN events %d\n", tag, t.rtp_events, t.rtn_events); - printf("%s: Tx pages %d, rx pages %d\n", tag, t.pages_tx, t.pages_rx); -} -/*- End of function --------------------------------------------------------*/ - -void fax_log_page_transfer_statistics(t30_state_t *s, const char *tag) -{ - t30_stats_t t; - - t30_get_transfer_statistics(s, &t); - printf("%s: Page statistics\n", 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_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); - printf("%s: Image resolution %d pels/m x %d pels/m (%d pels/m x %d pels/m in the file)\n", tag, t.x_resolution, t.y_resolution, t.image_x_resolution, t.image_y_resolution); -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - printf("%s: Bits per row - min %d, max %d\n", tag, s->t4.tx.encoder.t4_t6.min_row_bits, s->t4.tx.encoder.t4_t6.max_row_bits); -#endif - - fax_log_final_transfer_statistics(s, tag); -} -/*- End of function --------------------------------------------------------*/ - -int get_tiff_total_pages(const char *file) -{ - TIFF *tiff_file; - int max; - - if ((tiff_file = TIFFOpen(file, "r")) == NULL) - return -1; - /* Each page *should* contain the total number of pages, but can this be - trusted? Some files say 0. Actually searching for the last page is - more reliable. */ - max = 0; - while (TIFFSetDirectory(tiff_file, (tdir_t) max)) - max++; - TIFFClose(tiff_file); - return max; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fax_utils.h b/libs/spandsp/tests/fax_utils.h deleted file mode 100644 index a2a1c6c12b..0000000000 --- a/libs/spandsp/tests/fax_utils.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fax_utils.h - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 */ - -#if !defined(_SPANDSP_FAX_UTILS_H_) -#define _SPANDSP_FAX_UTILS_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -void fax_log_tx_parameters(t30_state_t *s, const char *tag); - -void fax_log_rx_parameters(t30_state_t *s, const char *tag); - -void fax_log_page_transfer_statistics(t30_state_t *s, const char *tag); - -void fax_log_final_transfer_statistics(t30_state_t *s, const char *tag); - -int get_tiff_total_pages(const char *file); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/fsk_tests.c b/libs/spandsp/tests/fsk_tests.c deleted file mode 100644 index 1dc3e6cc12..0000000000 --- a/libs/spandsp/tests/fsk_tests.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * fsk_tests.c - Tests for the low speed FSK modem code (V.21, V.23, etc.). - * - * 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 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. - */ - -/*! \page fsk_tests_page FSK modem tests -\section fsk_tests_page_sec_1 What does it do? -These tests allow either: - - - An FSK transmit modem to feed an FSK receive modem, of the same type, - through a telephone line model. BER testing is then used to evaluate - performance under various line conditions. This is effective for testing - the basic performance of the receive modem. It is also the only test mode - provided for evaluating the transmit modem. - - - An FSK receive modem is used to decode FSK audio, stored in a file. - This is good way to evaluate performance with audio recorded from other - models of modem, and with real world problematic telephone lines. - -\section fsk_tests_page_sec_2 How does it work? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define BLOCK_LEN 160 - -#define OUTPUT_FILE_NAME "fsk.wav" - -char *decode_test_file = NULL; -both_ways_line_model_state_t *model; -int rx_bits = 0; -bool cutoff_test_carrier = false; - -static void rx_status(void *user_data, int status) -{ - printf("FSK rx status is %s (%d)\n", signal_status_to_str(status), status); -} -/*- End of function --------------------------------------------------------*/ - -static void tx_status(void *user_data, int status) -{ - printf("FSK tx status is %s (%d)\n", signal_status_to_str(status), status); -} -/*- End of function --------------------------------------------------------*/ - -static void put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - rx_status(user_data, bit); - return; - } - - printf("Rx bit %d - %d\n", rx_bits++, bit); -} -/*- End of function --------------------------------------------------------*/ - -static void cutoff_test_rx_status(void *user_data, int status) -{ - printf("FSK rx status is %s (%d)\n", signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_CARRIER_UP: - cutoff_test_carrier = true; - break; - case SIG_STATUS_CARRIER_DOWN: - cutoff_test_carrier = false; - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void cutoff_test_put_bit(void *user_data, int bit) -{ - if (bit < 0) - { - cutoff_test_rx_status(user_data, bit); - return; - } -} -/*- End of function --------------------------------------------------------*/ - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - int channel; - - channel = (int) (intptr_t) user_data; - switch (reason) - { - case BERT_REPORT_SYNCED: - fprintf(stderr, "%d: BERT report synced\n", channel); - break; - case BERT_REPORT_UNSYNCED: - fprintf(stderr, "%d: BERT report unsync'ed\n", channel); - break; - case BERT_REPORT_REGULAR: - fprintf(stderr, "%d: BERT report regular - %d bits, %d bad bits, %d resyncs\n", channel, results->total_bits, results->bad_bits, results->resyncs); - break; - case BERT_REPORT_GT_10_2: - fprintf(stderr, "%d: BERT report > 1 in 10^2\n", channel); - break; - case BERT_REPORT_LT_10_2: - fprintf(stderr, "%d: BERT report < 1 in 10^2\n", channel); - break; - case BERT_REPORT_LT_10_3: - fprintf(stderr, "%d: BERT report < 1 in 10^3\n", channel); - break; - case BERT_REPORT_LT_10_4: - fprintf(stderr, "%d: BERT report < 1 in 10^4\n", channel); - break; - case BERT_REPORT_LT_10_5: - fprintf(stderr, "%d: BERT report < 1 in 10^5\n", channel); - break; - case BERT_REPORT_LT_10_6: - fprintf(stderr, "%d: BERT report < 1 in 10^6\n", channel); - break; - case BERT_REPORT_LT_10_7: - fprintf(stderr, "%d: BERT report < 1 in 10^7\n", channel); - break; - default: - fprintf(stderr, "%d: BERT report reason %d\n", channel, reason); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - fsk_tx_state_t *caller_tx; - fsk_rx_state_t *caller_rx; - fsk_tx_state_t *answerer_tx; - fsk_rx_state_t *answerer_rx; - bert_state_t caller_bert; - bert_state_t answerer_bert; - bert_results_t bert_results; - power_meter_t caller_meter; - power_meter_t answerer_meter; - int16_t caller_amp[BLOCK_LEN]; - int16_t answerer_amp[BLOCK_LEN]; - int16_t caller_model_amp[BLOCK_LEN]; - int16_t answerer_model_amp[BLOCK_LEN]; - int16_t out_amp[2*BLOCK_LEN]; - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int i; - int j; - int samples; - int test_bps; - int noise_level; - int noise_sweep; - int bits_per_test; - int line_model_no; - int modem_under_test_1; - int modem_under_test_2; - int modems_set; - 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; - - channel_codec = MUNGE_CODEC_NONE; - rbs_pattern = 0; - line_model_no = 0; - decode_test_file = NULL; - noise_sweep = false; - modem_under_test_1 = FSK_V21CH1; - modem_under_test_2 = FSK_V21CH2; - log_audio = false; - modems_set = 0; - while ((opt = getopt(argc, argv, "c:d:lm:nr:s:")) != -1) - { - switch (opt) - { - case 'c': - channel_codec = atoi(optarg); - break; - case 'd': - decode_test_file = optarg; - break; - case 'l': - log_audio = true; - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'n': - noise_sweep = true; - break; - case 'r': - rbs_pattern = atoi(optarg); - break; - case 's': - switch (modems_set++) - { - case 0: - modem_under_test_1 = atoi(optarg); - break; - case 1: - modem_under_test_2 = atoi(optarg); - break; - } - break; - default: - //usage(); - exit(2); - break; - } - } - - if (modem_under_test_1 >= 0) - printf("Modem channel 1 is '%s'\n", preset_fsk_specs[modem_under_test_1].name); - if (modem_under_test_2 >= 0) - printf("Modem channel 2 is '%s'\n", preset_fsk_specs[modem_under_test_2].name); - - outhandle = NULL; - - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - } - noise_level = -200; - bits_per_test = 0; - inhandle = NULL; - - memset(caller_amp, 0, sizeof(*caller_amp)); - memset(answerer_amp, 0, sizeof(*answerer_amp)); - memset(caller_model_amp, 0, sizeof(*caller_model_amp)); - memset(answerer_model_amp, 0, sizeof(*answerer_model_amp)); - power_meter_init(&caller_meter, 7); - power_meter_init(&answerer_meter, 7); - - if (decode_test_file) - { - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, put_bit, NULL); - fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); - test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; - - for (;;) - { - samples = sf_readf_short(inhandle, caller_model_amp, BLOCK_LEN); - if (samples < BLOCK_LEN) - break; - for (i = 0; i < samples; i++) - power_meter_update(&caller_meter, caller_model_amp[i]); - fsk_rx(caller_rx, caller_model_amp, samples); - } - - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - fsk_rx_free(caller_rx); - } - else - { - printf("Test cutoff level\n"); - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, cutoff_test_put_bit, NULL); - fsk_rx_signal_cutoff(caller_rx, -30.0f); - fsk_rx_set_modem_status_handler(caller_rx, cutoff_test_rx_status, (void *) &caller_rx); - on_at = 0; - for (i = -40; i < -25; i++) - { - tone_gen_descriptor_init(&tone_desc, - 1500, - i, - 0, - 0, - 1, - 0, - 0, - 0, - true); - tone_gen_init(&tone_tx, &tone_desc); - for (j = 0; j < 10; j++) - { - samples = tone_gen(&tone_tx, caller_model_amp, 160); - fsk_rx(caller_rx, caller_model_amp, samples); - } - if (cutoff_test_carrier) - break; - } - on_at = i; - off_at = 0; - for ( ; i > -40; i--) - { - tone_gen_descriptor_init(&tone_desc, - 1500, - i, - 0, - 0, - 1, - 0, - 0, - 0, - true); - tone_gen_init(&tone_tx, &tone_desc); - for (j = 0; j < 10; j++) - { - samples = tone_gen(&tone_tx, caller_model_amp, 160); - fsk_rx(caller_rx, caller_model_amp, samples); - } - if (!cutoff_test_carrier) - break; - } - off_at = i; - printf("Carrier on at %d, off at %d\n", on_at, off_at); - if (on_at < -29 || on_at > -26 - || - off_at < -35 || off_at > -31) - { - printf("Tests failed.\n"); - exit(2); - } - fsk_rx_free(caller_rx); - - printf("Test with BERT\n"); - test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; - if (modem_under_test_1 >= 0) - { - caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); - fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); - answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert); - fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); - } - if (modem_under_test_2 >= 0) - { - answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); - fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert); - fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); - } - test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; - - bits_per_test = 500000; - noise_level = -24; - - bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1); - bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); - if ((model = both_ways_line_model_init(line_model_no, - (float) noise_level, - -15.0f, - -15.0f, - line_model_no, - (float) noise_level, - -15.0f, - -15.0f, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - for (;;) - { - samples = fsk_tx(caller_tx, caller_amp, BLOCK_LEN); - for (i = 0; i < samples; i++) - power_meter_update(&caller_meter, caller_amp[i]); - samples = fsk_tx(answerer_tx, answerer_amp, BLOCK_LEN); - for (i = 0; i < samples; i++) - power_meter_update(&answerer_meter, answerer_amp[i]); - both_ways_line_model(model, - caller_model_amp, - caller_amp, - answerer_model_amp, - answerer_amp, - samples); - - //printf("Powers %10.5fdBm0 %10.5fdBm0\n", power_meter_current_dbm0(&caller_meter), power_meter_current_dbm0(&answerer_meter)); - - fsk_rx(answerer_rx, caller_model_amp, samples); - for (i = 0; i < samples; i++) - out_amp[2*i] = caller_model_amp[i]; - for ( ; i < BLOCK_LEN; i++) - out_amp[2*i] = 0; - - fsk_rx(caller_rx, answerer_model_amp, samples); - for (i = 0; i < samples; i++) - out_amp[2*i + 1] = answerer_model_amp[i]; - for ( ; i < BLOCK_LEN; i++) - out_amp[2*i + 1] = 0; - - if (log_audio) - { - outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN); - if (outframes != BLOCK_LEN) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - - if (samples < BLOCK_LEN) - { - bert_result(&caller_bert, &bert_results); - fprintf(stderr, "%ddB AWGN, %d bits, %d bad bits, %d resyncs\n", noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - if (!noise_sweep) - { - if (bert_results.total_bits != bits_per_test - 43 - || - bert_results.bad_bits != 0 - || - bert_results.resyncs != 0) - { - printf("Tests failed.\n"); - exit(2); - } - } - bert_result(&answerer_bert, &bert_results); - fprintf(stderr, "%ddB AWGN, %d bits, %d bad bits, %d resyncs\n", noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - if (!noise_sweep) - { - if (bert_results.total_bits != bits_per_test - 43 - || - bert_results.bad_bits != 0 - || - bert_results.resyncs != 0) - { - printf("Tests failed.\n"); - exit(2); - } - break; - } - - /* Put a little silence between the chunks in the file. */ - memset(out_amp, 0, sizeof(out_amp)); - if (log_audio) - { - for (i = 0; i < 200; i++) - outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN); - } - if (modem_under_test_1 >= 0) - { - caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); - fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); - answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert); - fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); - } - if (modem_under_test_2 >= 0) - { - answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); - fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); - caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert); - fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); - } - noise_level++; - both_ways_line_model_free(model); - if ((model = both_ways_line_model_init(line_model_no, - (float) noise_level, - line_model_no, - -15.0f, - -15.0f, - noise_level, - channel_codec, - -15.0f, - -15.0f, - 0)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1); - bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); - } - } - bert_release(&caller_bert); - bert_release(&answerer_bert); - if (modem_under_test_1 >= 0) - { - fsk_tx_free(caller_tx); - fsk_rx_free(answerer_rx); - } - if (modem_under_test_2 >= 0) - { - fsk_tx_free(answerer_tx); - fsk_rx_free(caller_rx); - } - both_ways_line_model_free(model); - printf("Tests passed.\n"); - } - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g1050_tests.c b/libs/spandsp/tests/g1050_tests.c deleted file mode 100644 index 397a2c6225..0000000000 --- a/libs/spandsp/tests/g1050_tests.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g1050_tests.c - Tests for the G.1050/TIA-921 model. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_MATH_H) -#define GEN_CONST -#endif - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif - -#define PACKET_SIZE 256 -#define PACKET_INTERVAL 20 -#define SIMULATION_TIME 300 - -#define MODEL_NO 8 -#define SPEED_PATTERN_NO 133 - -int main(int argc, char *argv[]) -{ - g1050_state_t *s; - double *packet_arrival_times; - int packets_per_sec; - int num_packets; - int model_no; - int speed_pattern_no; - int simulation_time; - int i; - int len; - uint8_t put_pkt[256]; - uint8_t get_pkt[256]; - int put_pkt_len; - int get_pkt_len; - int get_seq_no; - double get_departure_time; - double get_arrival_time; - int packets_put; - int packets_really_put; - int packets_got; - int oos_packets_got; - int missing_packets_got; - int highest_seq_no_got; - int opt; - FILE *out_file; -#if defined(ENABLE_GUI) - int use_gui; -#endif - -#if defined(ENABLE_GUI) - use_gui = false; -#endif - model_no = MODEL_NO; - speed_pattern_no = SPEED_PATTERN_NO; - simulation_time = SIMULATION_TIME; - while ((opt = getopt(argc, argv, "gm:s:t:")) != -1) - { - switch (opt) - { - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'm': - model_no = optarg[0] - 'A' + 1; - if (model_no < 0 || model_no > 8) - { - fprintf(stderr, "Bad model ID '%s'\n", optarg); - exit(2); - } - break; - case 's': - speed_pattern_no = atoi(optarg); - if (speed_pattern_no < 1 || speed_pattern_no > 133) - { - fprintf(stderr, "Bad link speed pattern %s\n", optarg); - exit(2); - } - break; - case 't': - simulation_time = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - - if ((out_file = fopen("g1050_tests.txt", "w")) == NULL) - { - fprintf(stderr, "Can't open %s\n", "g1050_tests.txt"); - return 2; - } - packets_per_sec = 1000/PACKET_INTERVAL; - num_packets = packets_per_sec*simulation_time; - - if ((packet_arrival_times = calloc(num_packets, sizeof(double))) == NULL) - { - fprintf(stderr, "Can't allocate the data buffers\n"); - return 2; - } - for (i = 0; i < num_packets; i++) - packet_arrival_times[i] = 0.0; - - /* If we don't initialise this random number generator it gives endless zeros on some systems. */ - /* Use a fixed seed to produce identical results in successive runs of the simulation, for debug purposes. */ - srand48(0x1234567); - - if ((s = g1050_init(model_no, speed_pattern_no, PACKET_SIZE, packets_per_sec)) == NULL) - { - fprintf(stderr, "Failed to start the G.1050 model\n"); - exit(2); - } - g1050_dump_parms(model_no, speed_pattern_no); - -#if defined(ENABLE_GUI) - if (use_gui) - start_media_monitor(); -#endif - - for (i = 0; i < 256; i++) - put_pkt[i] = i; - put_pkt_len = 256; - get_pkt_len = -1; - get_seq_no = -1; - get_arrival_time = -1; - packets_put = 0; - packets_really_put = 0; - packets_got = 0; - oos_packets_got = 0; - missing_packets_got = 0; - highest_seq_no_got = -1; - for (i = 0; i < num_packets; i++) - { - if ((len = g1050_put(s, put_pkt, put_pkt_len, i, (double) i*0.001*PACKET_INTERVAL)) > 0) - packets_really_put++; - packets_put++; - if (i == 5) - g1050_queue_dump(s); - if (i >= 5) - { - do - { - get_pkt_len = g1050_get(s, get_pkt, 256, (double) i*0.001*PACKET_INTERVAL, &get_seq_no, &get_departure_time, &get_arrival_time); - if (get_pkt_len >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(get_seq_no, get_departure_time, get_arrival_time); -#endif - packets_got++; - if (get_seq_no < highest_seq_no_got) - oos_packets_got++; - else if (get_seq_no > highest_seq_no_got + 1) - missing_packets_got += (get_seq_no - highest_seq_no_got - 1); - if (get_seq_no > highest_seq_no_got) - highest_seq_no_got = get_seq_no; - fprintf(out_file, "%d, %.3f, %.8f\n", get_seq_no, get_seq_no*0.001*PACKET_INTERVAL, get_arrival_time); - } - } - while (get_pkt_len >= 0); - } -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_update_display(); -#endif - } - /* Clear out anything remaining in the queue, by jumping forwards in time */ - do - { - get_pkt_len = g1050_get(s, get_pkt, 256, (double) i*0.001*PACKET_INTERVAL + 5.0, &get_seq_no, &get_departure_time, &get_arrival_time); - if (get_pkt_len >= 0) - { - packets_got++; - fprintf(out_file, "%d, %.3f, %.8f\n", get_seq_no, get_seq_no*0.001*PACKET_INTERVAL, get_arrival_time); - } - } - while (get_pkt_len >= 0); - - fclose(out_file); - - printf("Put %d packets. Really put %d packets. Got %d packets.\n", packets_put, packets_really_put, packets_got); - printf("%d OOS packets, %d missing packets\n", oos_packets_got, missing_packets_got - oos_packets_got); - if (packets_really_put != packets_got) - { - printf("%d packets queued, but only %d received\n", packets_really_put, packets_got); - exit(2); - } - printf("%.3f%% of packets lost\n", 100.0*(packets_put - packets_really_put)/packets_put); - g1050_free(s); - free(packet_arrival_times); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g168_tests.c b/libs/spandsp/tests/g168_tests.c deleted file mode 100644 index 6eb9d7b48f..0000000000 --- a/libs/spandsp/tests/g168_tests.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g168tests.c - Tests of the "test equipment" (filters, etc.) specified - * in G.168. This code is only for checking out the tools, - * not for testing an echo cancellor. - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp/g168models.h" -#include "spandsp-sim.h" - -typedef struct -{ - const char *name; - int max; - int cur; - float gain; - SNDFILE *handle; - int16_t signal[SAMPLE_RATE]; -} signal_source_t; - -signal_source_t local_css; -signal_source_t far_css; - -static void signal_load(signal_source_t *sig, const char *name) -{ - sig->handle = sf_open_telephony_read(name, 1); - sig->name = name; - sig->max = sf_readf_short(sig->handle, sig->signal, SAMPLE_RATE); - if (sig->max < 0) - { - fprintf(stderr, " Error reading sound file '%s'\n", sig->name); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_free(signal_source_t *sig) -{ - if (sf_close_telephony(sig->handle)) - { - fprintf(stderr, " Cannot close sound file '%s'\n", sig->name); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_restart(signal_source_t *sig, float gain) -{ - sig->cur = 0; - sig->gain = powf(10.0f, gain/20.0f); -} -/*- End of function --------------------------------------------------------*/ - -static int16_t signal_amp(signal_source_t *sig) -{ - int16_t tx; - - tx = sig->signal[sig->cur++]*sig->gain; - if (sig->cur >= sig->max) - sig->cur = 0; - return tx; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int f; - int i; - int16_t amp[8000]; - int16_t value; - int signal; - float power[10]; - tone_gen_descriptor_t tone_desc; - tone_gen_state_t tone_state; - awgn_state_t noise_source; - fir32_state_t line_model_d2; - fir32_state_t line_model_d3; - fir32_state_t line_model_d4; - fir32_state_t line_model_d5; - fir32_state_t line_model_d6; - fir32_state_t line_model_d7; - fir32_state_t line_model_d8; - fir32_state_t line_model_d9; - fir_float_state_t level_measurement_bp; - - signal_load(&local_css, "sound_c1_8k.wav"); - signal_load(&far_css, "sound_c3_8k.wav"); - - fir32_create(&line_model_d2, - line_model_d2_coeffs, - sizeof(line_model_d2_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d3, - line_model_d3_coeffs, - sizeof(line_model_d3_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d4, - line_model_d4_coeffs, - sizeof(line_model_d4_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d5, - line_model_d5_coeffs, - sizeof(line_model_d5_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d6, - line_model_d6_coeffs, - sizeof(line_model_d6_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d7, - line_model_d7_coeffs, - sizeof(line_model_d7_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d8, - line_model_d8_coeffs, - sizeof(line_model_d8_coeffs)/sizeof(int32_t)); - fir32_create(&line_model_d9, - line_model_d9_coeffs, - sizeof(line_model_d9_coeffs)/sizeof(int32_t)); - fir_float_create(&level_measurement_bp, - level_measurement_bp_coeffs, - sizeof(level_measurement_bp_coeffs)/sizeof(float)); - - for (f = 10; f < 4000; f++) - { - tone_gen_descriptor_init(&tone_desc, - f, - -10, - 0, - 0, - 1, - 0, - 0, - 0, - true); - tone_gen_init(&tone_state, &tone_desc); - tone_gen(&tone_state, amp, 8000); - for (i = 0; i < 10; i++) - power[i] = 0.0f; - for (i = 0; i < 800; i++) - { - signal = fir32(&line_model_d2, amp[i]); - power[0] += ((signal*signal - power[0])/32.0f); - signal = fir32(&line_model_d3, amp[i]); - power[1] += ((signal*signal - power[1])/32.0f); - signal = fir32(&line_model_d4, amp[i]); - power[2] += ((signal*signal - power[2])/32.0f); - signal = fir32(&line_model_d5, amp[i]); - power[3] += ((signal*signal - power[3])/32.0f); - signal = fir32(&line_model_d6, amp[i]); - power[4] += ((signal*signal - power[4])/32.0f); - signal = fir32(&line_model_d7, amp[i]); - power[5] += ((signal*signal - power[5])/32.0f); - signal = fir32(&line_model_d8, amp[i]); - power[6] += ((signal*signal - power[6])/32.0f); - signal = fir32(&line_model_d9, amp[i]); - power[7] += ((signal*signal - power[7])/32.0f); - signal = fir_float(&level_measurement_bp, amp[i]); - power[8] += ((signal*signal - power[8])/32.0f); - signal = amp[i]; - power[9] += ((signal*signal - power[9])/32.0f); - } - printf("%d %f %f %f %f %f %f %f %f %f %f\n", - f, - sqrt(power[0])*LINE_MODEL_D2_GAIN, - sqrt(power[1])*LINE_MODEL_D3_GAIN, - sqrt(power[2])*LINE_MODEL_D4_GAIN, - sqrt(power[3])*LINE_MODEL_D5_GAIN, - sqrt(power[4])*LINE_MODEL_D6_GAIN, - sqrt(power[5])*LINE_MODEL_D7_GAIN, - sqrt(power[6])*LINE_MODEL_D8_GAIN, - sqrt(power[7])*LINE_MODEL_D9_GAIN, - sqrt(power[8]), - sqrt(power[9])); - } - awgn_init_dbm0(&noise_source, 1234567, -20.0f); - for (i = 0; i < 10; i++) - power[i] = 0.0f; - signal_restart(&local_css, 0.0f); - signal_restart(&far_css, 0.0f); - for (i = 0; i < SAMPLE_RATE; i++) - { - value = signal_amp(&local_css); - //value = awgn(&noise_source); - signal = fir32(&line_model_d2, value); - power[0] += ((signal*signal - power[0])/32.0f); - signal = fir32(&line_model_d3, value); - power[1] += ((signal*signal - power[1])/32.0f); - signal = fir32(&line_model_d4, value); - power[2] += ((signal*signal - power[2])/32.0f); - signal = fir32(&line_model_d5, value); - power[3] += ((signal*signal - power[3])/32.0f); - signal = fir32(&line_model_d6, value); - power[4] += ((signal*signal - power[4])/32.0f); - signal = fir32(&line_model_d7, value); - power[5] += ((signal*signal - power[5])/32.0f); - signal = fir32(&line_model_d8, value); - power[6] += ((signal*signal - power[6])/32.0f); - signal = fir32(&line_model_d9, value); - power[7] += ((signal*signal - power[7])/32.0f); - signal = fir_float(&level_measurement_bp, value); - power[8] += ((signal*signal - power[8])/32.0f); - signal = value; - power[9] += ((signal*signal - power[9])/32.0f); - } - for (i = 0; i < 10; i++) - power[i] = 0.0f; - for (i = 0; i < SAMPLE_RATE; i++) - { - value = signal_amp(&local_css); - //value = awgn(&noise_source); - signal = fir32(&line_model_d2, value); - power[0] += ((signal*signal - power[0])/32.0f); - signal = fir32(&line_model_d3, value); - power[1] += ((signal*signal - power[1])/32.0f); - signal = fir32(&line_model_d4, value); - power[2] += ((signal*signal - power[2])/32.0f); - signal = fir32(&line_model_d5, value); - power[3] += ((signal*signal - power[3])/32.0f); - signal = fir32(&line_model_d6, value); - power[4] += ((signal*signal - power[4])/32.0f); - signal = fir32(&line_model_d7, value); - power[5] += ((signal*signal - power[5])/32.0f); - signal = fir32(&line_model_d8, value); - power[6] += ((signal*signal - power[6])/32.0f); - signal = fir32(&line_model_d9, value); - power[7] += ((signal*signal - power[7])/32.0f); - signal = fir_float(&level_measurement_bp, value); - power[8] += ((signal*signal - power[8])/32.0f); - signal = value; - power[9] += ((signal*signal - power[9])/32.0f); - } - printf("%d %f %f %f %f %f %f %f %f %f %f\n", - 0, - sqrt(power[0])*LINE_MODEL_D2_GAIN, - sqrt(power[1])*LINE_MODEL_D3_GAIN, - sqrt(power[2])*LINE_MODEL_D4_GAIN, - sqrt(power[3])*LINE_MODEL_D5_GAIN, - sqrt(power[4])*LINE_MODEL_D6_GAIN, - sqrt(power[5])*LINE_MODEL_D7_GAIN, - sqrt(power[6])*LINE_MODEL_D8_GAIN, - sqrt(power[7])*LINE_MODEL_D9_GAIN, - sqrt(power[8]), - sqrt(power[9])); - printf("%d %f %f %f %f %f %f %f %f %f %f\n", - 0, - sqrt(power[0]), - sqrt(power[1]), - sqrt(power[2]), - sqrt(power[3]), - sqrt(power[4]), - sqrt(power[5]), - sqrt(power[6]), - sqrt(power[7]), - sqrt(power[8]), - sqrt(power[9])); - printf("%d %f %f %f %f %f %f %f %f %f %f\n", - 0, - sqrt(power[0])/sqrt(power[9]), - sqrt(power[1])/sqrt(power[9]), - sqrt(power[2])/sqrt(power[9]), - sqrt(power[3])/sqrt(power[9]), - sqrt(power[4])/sqrt(power[9]), - sqrt(power[5])/sqrt(power[9]), - sqrt(power[6])/sqrt(power[9]), - sqrt(power[7])/sqrt(power[9]), - sqrt(power[8]), - sqrt(power[9])); - printf("%d %f %f %f %f %f %f %f %f %f %f\n", - 0, - sqrt(power[0])*LINE_MODEL_D2_GAIN/sqrt(power[9]), - sqrt(power[1])*LINE_MODEL_D3_GAIN/sqrt(power[9]), - sqrt(power[2])*LINE_MODEL_D4_GAIN/sqrt(power[9]), - sqrt(power[3])*LINE_MODEL_D5_GAIN/sqrt(power[9]), - sqrt(power[4])*LINE_MODEL_D6_GAIN/sqrt(power[9]), - sqrt(power[5])*LINE_MODEL_D7_GAIN/sqrt(power[9]), - sqrt(power[6])*LINE_MODEL_D8_GAIN/sqrt(power[9]), - sqrt(power[7])*LINE_MODEL_D9_GAIN/sqrt(power[9]), - sqrt(power[8]), - sqrt(power[9])); - - for (i = 0; i < (int) (sizeof(css_c1)/sizeof(css_c1[0])); i++) - printf("%d\n", css_c1[i]); - printf("\n"); - for (i = 0; i < (int) (sizeof(css_c1)/sizeof(css_c3[0])); i++) - printf("%d\n", css_c3[i]); - signal_free(&local_css); - signal_free(&far_css); - fir32_free(&line_model_d2); - fir32_free(&line_model_d3); - fir32_free(&line_model_d4); - fir32_free(&line_model_d5); - fir32_free(&line_model_d6); - fir32_free(&line_model_d7); - fir32_free(&line_model_d8); - fir32_free(&line_model_d9); - fir_float_free(&level_measurement_bp); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g711_tests.c b/libs/spandsp/tests/g711_tests.c deleted file mode 100644 index 9efb8ebaaa..0000000000 --- a/libs/spandsp/tests/g711_tests.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g711_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -/*! \page g711_tests_page A-law and u-law conversion tests -\section g711_tests_page_sec_1 What does it do? - -\section g711_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define BLOCK_LEN 160 - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define ENCODED_FILE_NAME "g711.g711" -#define OUT_FILE_NAME "post_g711.wav" - -int16_t amp[65536]; -uint8_t ulaw_data[65536]; -uint8_t alaw_data[65536]; - -const uint8_t alaw_1khz_sine[] = {0x34, 0x21, 0x21, 0x34, 0xB4, 0xA1, 0xA1, 0xB4}; -const uint8_t ulaw_1khz_sine[] = {0x1E, 0x0B, 0x0B, 0x1E, 0x9E, 0x8B, 0x8B, 0x9E}; - -static void compliance_tests(int log_audio) -{ - SNDFILE *outhandle; - power_meter_t power_meter; - int outframes; - int i; - int block; - int pre; - int post; - int post_post; - int alaw_failures; - int ulaw_failures; - float worst_alaw; - float worst_ulaw; - float tmp; - int len; - g711_state_t *enc_state; - g711_state_t *transcode; - g711_state_t *dec_state; - - outhandle = NULL; - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - - printf("Conversion accuracy tests.\n"); - alaw_failures = 0; - ulaw_failures = 0; - worst_alaw = 0.0; - worst_ulaw = 0.0; - for (block = 0; block < 1; block++) - { - for (i = 0; i < 65536; i++) - { - pre = i - 32768; - post = alaw_to_linear(linear_to_alaw(pre)); - if (abs(pre) > 140) - { - tmp = (float) abs(post - pre)/(float) abs(pre); - if (tmp > 0.10) - { - printf("A-law: Excessive error at %d (%d)\n", pre, post); - alaw_failures++; - } - if (tmp > worst_alaw) - worst_alaw = tmp; - } - else - { - /* Small values need different handling for sensible measurement */ - if (abs(post - pre) > 15) - { - printf("A-law: Excessive error at %d (%d)\n", pre, post); - alaw_failures++; - } - } - amp[i] = post; - } - if (log_audio) - { - outframes = sf_writef_short(outhandle, amp, 65536); - if (outframes != 65536) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - for (i = 0; i < 65536; i++) - { - pre = i - 32768; - post = ulaw_to_linear(linear_to_ulaw(pre)); - if (abs(pre) > 40) - { - tmp = (float) abs(post - pre)/(float) abs(pre); - if (tmp > 0.10) - { - printf("u-law: Excessive error at %d (%d)\n", pre, post); - ulaw_failures++; - } - if (tmp > worst_ulaw) - worst_ulaw = tmp; - } - else - { - /* Small values need different handling for sensible measurement */ - if (abs(post - pre) > 4) - { - printf("u-law: Excessive error at %d (%d)\n", pre, post); - ulaw_failures++; - } - } - amp[i] = post; - } - if (log_audio) - { - outframes = sf_writef_short(outhandle, amp, 65536); - if (outframes != 65536) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - } - printf("Worst A-law error (ignoring small values) %f%%\n", worst_alaw*100.0); - printf("Worst u-law error (ignoring small values) %f%%\n", worst_ulaw*100.0); - if (alaw_failures || ulaw_failures) - { - printf("%d A-law values with excessive error\n", alaw_failures); - printf("%d u-law values with excessive error\n", ulaw_failures); - printf("Tests failed\n"); - exit(2); - } - - printf("Cyclic conversion repeatability tests.\n"); - /* Find what happens to every possible linear value after a round trip. */ - for (i = 0; i < 65536; i++) - { - pre = i - 32768; - /* Make a round trip */ - post = alaw_to_linear(linear_to_alaw(pre)); - /* A second round trip should cause no further change */ - post_post = alaw_to_linear(linear_to_alaw(post)); - if (post_post != post) - { - printf("A-law second round trip mismatch - at %d, %d != %d\n", pre, post, post_post); - printf("Tests failed\n"); - exit(2); - } - /* Make a round trip */ - post = ulaw_to_linear(linear_to_ulaw(pre)); - /* A second round trip should cause no further change */ - post_post = ulaw_to_linear(linear_to_ulaw(post)); - if (post_post != post) - { - printf("u-law round trip mismatch - at %d, %d != %d\n", pre, post, post_post); - printf("Tests failed\n"); - exit(2); - } - } - - printf("Reference power level tests.\n"); - power_meter_init(&power_meter, 7); - - for (i = 0; i < 8000; i++) - { - amp[i] = ulaw_to_linear(ulaw_1khz_sine[i & 7]); - power_meter_update(&power_meter, amp[i]); - } - printf("Reference u-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter)); - if (log_audio) - { - outframes = sf_writef_short(outhandle, amp, 8000); - if (outframes != 8000) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - if (0.1f < fabs(power_meter_current_dbm0(&power_meter))) - { - printf("Test failed.\n"); - exit(2); - } - - for (i = 0; i < 8000; i++) - { - amp[i] = alaw_to_linear(alaw_1khz_sine[i & 7]); - power_meter_update(&power_meter, amp[i]); - } - printf("Reference A-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter)); - if (log_audio) - { - outframes = sf_writef_short(outhandle, amp, 8000); - if (outframes != 8000) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - if (0.1f < fabs(power_meter_current_dbm0(&power_meter))) - { - printf("Test failed.\n"); - exit(2); - } - - /* Check the transcoding functions. */ - printf("Testing transcoding A-law -> u-law -> A-law\n"); - for (i = 0; i < 256; i++) - { - if (alaw_to_ulaw(ulaw_to_alaw(i)) != i) - { - if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) - { - printf("u-law -> A-law -> u-law gave %d -> %d\n", i, alaw_to_ulaw(ulaw_to_alaw(i))); - printf("Test failed\n"); - exit(2); - } - } - } - - printf("Testing transcoding u-law -> A-law -> u-law\n"); - for (i = 0; i < 256; i++) - { - if (ulaw_to_alaw(alaw_to_ulaw(i)) != i) - { - if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) - { - printf("A-law -> u-law -> A-law gave %d -> %d\n", i, ulaw_to_alaw(alaw_to_ulaw(i))); - printf("Test failed\n"); - exit(2); - } - } - } - - enc_state = g711_init(NULL, G711_ALAW); - transcode = g711_init(NULL, G711_ALAW); - dec_state = g711_init(NULL, G711_ULAW); - - len = 65536; - for (i = 0; i < len; i++) - amp[i] = i - 32768; - len = g711_encode(enc_state, alaw_data, amp, len); - len = g711_transcode(transcode, ulaw_data, alaw_data, len); - len = g711_decode(dec_state, amp, ulaw_data, len); - if (len != 65536) - { - printf("Block coding gave the wrong length - %d instead of %d\n", len, 65536); - printf("Test failed\n"); - exit(2); - } - for (i = 0; i < len; i++) - { - pre = i - 32768; - post = amp[i]; - if (abs(pre) > 140) - { - tmp = (float) abs(post - pre)/(float) abs(pre); - if (tmp > 0.10) - { - printf("Block: Excessive error at %d (%d)\n", pre, post); - exit(2); - } - } - else - { - /* Small values need different handling for sensible measurement */ - if (abs(post - pre) > 15) - { - printf("Block: Excessive error at %d (%d)\n", pre, post); - exit(2); - } - } - } - g711_free(enc_state); - g711_free(transcode); - g711_free(dec_state); - - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - - printf("Tests passed.\n"); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int opt; - int samples; - int len2; - int len3; - int basic_tests; - int law; - int encode; - int decode; - int file; - const char *in_file; - const char *out_file; - g711_state_t *enc_state; - g711_state_t *dec_state; - int16_t indata[BLOCK_LEN]; - int16_t outdata[BLOCK_LEN]; - uint8_t g711data[BLOCK_LEN]; - - basic_tests = true; - law = G711_ALAW; - encode = false; - decode = false; - in_file = NULL; - out_file = NULL; - while ((opt = getopt(argc, argv, "ad:e:l:u")) != -1) - { - switch (opt) - { - case 'a': - law = G711_ALAW; - basic_tests = false; - break; - case 'd': - in_file = optarg; - basic_tests = false; - decode = true; - break; - case 'e': - in_file = optarg; - basic_tests = false; - encode = true; - break; - case 'l': - out_file = optarg; - break; - case 'u': - law = G711_ULAW; - basic_tests = false; - break; - default: - //usage(); - exit(2); - } - } - - if (basic_tests) - { - compliance_tests(true); - } - else - { - if (!decode && !encode) - { - decode = - encode = true; - } - if (in_file == NULL) - { - in_file = (encode) ? IN_FILE_NAME : ENCODED_FILE_NAME; - } - if (out_file == NULL) - { - out_file = (decode) ? OUT_FILE_NAME : ENCODED_FILE_NAME; - } - inhandle = NULL; - outhandle = NULL; - file = -1; - enc_state = NULL; - dec_state = NULL; - if (encode) - { - if ((inhandle = sf_open_telephony_read(in_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", in_file); - exit(2); - } - enc_state = g711_init(NULL, law); - } - else - { - if ((file = open(in_file, O_RDONLY)) < 0) - { - fprintf(stderr, " Failed to open '%s'\n", in_file); - exit(2); - } - } - if (decode) - { - if ((outhandle = sf_open_telephony_write(out_file, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", out_file); - exit(2); - } - dec_state = g711_init(NULL, law); - } - else - { - if ((file = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) - { - fprintf(stderr, " Failed to open '%s'\n", out_file); - exit(2); - } - } - for (;;) - { - if (encode) - { - samples = sf_readf_short(inhandle, indata, BLOCK_LEN); - if (samples <= 0) - break; - len2 = g711_encode(enc_state, g711data, indata, samples); - } - else - { - len2 = read(file, g711data, BLOCK_LEN); - if (len2 <= 0) - break; - } - if (decode) - { - len3 = g711_decode(dec_state, outdata, g711data, len2); - outframes = sf_writef_short(outhandle, outdata, len3); - if (outframes != len3) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - else - { - len3 = write(file, g711data, len2); - if (len3 <= 0) - break; - } - } - if (encode) - { - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME); - exit(2); - } - } - else - { - close(file); - } - if (decode) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - else - { - close(file); - } - printf("'%s' translated to '%s' using %s.\n", in_file, out_file, (law == G711_ALAW) ? "A-law" : "u-law"); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g722_tests.c b/libs/spandsp/tests/g722_tests.c deleted file mode 100644 index 9e51312361..0000000000 --- a/libs/spandsp/tests/g722_tests.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g722_tests.c - Test G.722 encode and decode. - * - * 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 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 g722_tests_page G.722 tests -\section g722_tests_page_sec_1 What does it do? -This modules implements two sets of tests: - - The tests defined in the G.722 specification, using the test data files supplied - with the specification. - - A generally audio quality test, consisting of compressing and decompressing a speeech - file for audible comparison. - -The speech file should be recorded at 16 bits/sample, 16000 samples/second, and named -"pre_g722.wav". - -The ITU tests use the codec in a special mode, in which the QMFs, which split and recombine the -sub-bands, are disabled. This means they do not test 100% of the codec. This is the reason for -including the additional listening test. - -\section g722_tests_page_sec_2 How is it used? -To perform the tests in the G.722 specification you need to obtain the test data files from the -specification. These are copyright material, and so cannot be distributed with this test software. - -The files, containing test vectors, which are supplied with the G.722 specification, should be -copied to itutests/g722. The ITU tests can then be run by executing g722_tests without -any parameters. - -To perform a general audio quality test, g722_tests should be run with a parameter specifying -the required bit rate for compression. The valid parameters are "-48", "-56", and "-64". -The file ../test-data/local/short_wb_voice.wav will be compressed to the specified bit rate, decompressed, -and the resulting audio stored in post_g722.wav. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -#include "spandsp/private/g722.h" - -#define G722_SAMPLE_RATE 16000 - -#define BLOCK_LEN 320 - -#define MAX_TEST_VECTOR_LEN 40000 - -#define TESTDATA_DIR "../test-data/itu/g722/" - -#define EIGHTK_IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define IN_FILE_NAME "../test-data/local/short_wb_voice.wav" -#define ENCODED_FILE_NAME "g722.g722" -#define OUT_FILE_NAME "post_g722.wav" - -#if 0 -static const char *itu_test_files[] = -{ - TESTDATA_DIR "T1C1.XMT", /* 69973 bytes */ - TESTDATA_DIR "T1C2.XMT", /* 3605 bytes */ - TESTDATA_DIR "T1D3.COD", /* 69973 bytes */ - - TESTDATA_DIR "T2R1.COD", /* 69973 bytes */ - TESTDATA_DIR "T2R2.COD", /* 3605 bytes */ - - TESTDATA_DIR "T3L1.RC1", /* 69973 bytes */ - TESTDATA_DIR "T3L1.RC2", /* 69973 bytes */ - TESTDATA_DIR "T3L1.RC3", /* 69973 bytes */ - TESTDATA_DIR "T3H1.RC0", /* 69973 bytes */ - TESTDATA_DIR "T3L2.RC1", /* 3605 bytes */ - TESTDATA_DIR "T3L2.RC2", /* 3605 bytes */ - TESTDATA_DIR "T3L2.RC3", /* 3605 bytes */ - TESTDATA_DIR "T3H2.RC0", /* 3605 bytes */ - TESTDATA_DIR "T3L3.RC1", /* 69973 bytes */ - TESTDATA_DIR "T3L3.RC2", /* 69973 bytes */ - TESTDATA_DIR "T3L3.RC3", /* 69973 bytes */ - TESTDATA_DIR "T3H3.RC0" /* 69973 bytes */ -}; -#endif - -static const char *encode_test_files[] = -{ - TESTDATA_DIR "T1C1.XMT", - TESTDATA_DIR "T2R1.COD", - TESTDATA_DIR "T1C2.XMT", - TESTDATA_DIR "T2R2.COD", - NULL -}; - -static const char *decode_test_files[] = -{ - TESTDATA_DIR "T2R1.COD", - TESTDATA_DIR "T3L1.RC1", - TESTDATA_DIR "T3L1.RC2", - TESTDATA_DIR "T3L1.RC3", - TESTDATA_DIR "T3H1.RC0", - - TESTDATA_DIR "T2R2.COD", - TESTDATA_DIR "T3L2.RC1", - TESTDATA_DIR "T3L2.RC2", - TESTDATA_DIR "T3L2.RC3", - TESTDATA_DIR "T3H2.RC0", - - TESTDATA_DIR "T1D3.COD", - TESTDATA_DIR "T3L3.RC1", - TESTDATA_DIR "T3L3.RC2", - TESTDATA_DIR "T3L3.RC3", - TESTDATA_DIR "T3H3.RC0", - - NULL -}; - -int16_t itu_data[MAX_TEST_VECTOR_LEN]; -uint16_t itu_ref[MAX_TEST_VECTOR_LEN]; -uint16_t itu_ref_upper[MAX_TEST_VECTOR_LEN]; -uint8_t compressed[MAX_TEST_VECTOR_LEN]; -int16_t decompressed[MAX_TEST_VECTOR_LEN]; - -static int hex_get(char *s) -{ - int i; - int value; - int x; - - for (value = i = 0; i < 4; i++) - { - x = *s++ - 0x30; - if (x > 9) - x -= 0x07; - if (x > 15) - x -= 0x20; - if (x < 0 || x > 15) - return -1; - value <<= 4; - value |= x; - } - return value; -} -/*- End of function --------------------------------------------------------*/ - -static int get_vector(FILE *file, uint16_t vec[]) -{ - char buf[132 + 1]; - char *s; - int i; - int value; - - while (fgets(buf, 133, file)) - { - if (buf[0] == '/' && buf[1] == '*') - continue; - s = buf; - i = 0; - while ((value = hex_get(s)) >= 0) - { - vec[i++] = value; - s += 4; - } - return i; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int get_test_vector(const char *file, uint16_t buf[], int max_len) -{ - int octets; - int i; - FILE *infile; - - if ((infile = fopen(file, "r")) == NULL) - { - fprintf(stderr, " Failed to open '%s'\n", file); - exit(2); - } - octets = 0; - while ((i = get_vector(infile, buf + octets)) > 0) - octets += i; - fclose(infile); - return octets; -} -/*- End of function --------------------------------------------------------*/ - -static void itu_compliance_tests(void) -{ - g722_encode_state_t *enc_state; - g722_decode_state_t *dec_state; - int i; - int j; - int k; - int len_comp; - int len_comp_lower; - int len_comp_upper; - int len_data; - int len; - int len2; - int mode; - int file; - -#if 1 - /* ITU G.722 encode tests, using configuration 1. The QMF is bypassed */ - for (file = 0; encode_test_files[file]; file += 2) - { - printf("Testing %s -> %s\n", encode_test_files[file], encode_test_files[file + 1]); - - /* Get the input data */ - len_data = get_test_vector(encode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN); - - /* Get the reference output data */ - len_comp = get_test_vector(encode_test_files[file + 1], itu_ref, MAX_TEST_VECTOR_LEN); - - if (len_data != len_comp) - { - printf("Test data length mismatch\n"); - exit(2); - } - /* Process the input data */ - /* Skip the reset stuff at each end of the data */ - for (i = 0; i < len_data; i++) - { - if ((itu_data[i] & 1) == 0) - break; - } - for (j = i; j < len_data; j++) - { - if ((itu_data[j] & 1)) - break; - } - len = j - i; - enc_state = g722_encode_init(NULL, 64000, 0); - 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 */ - j = 0; - for (k = 0; k < len2; k++) - { - if ((compressed[k] & 0xFF) != ((itu_ref[k + i] >> 8) & 0xFF)) - { - printf(">>> %6d %4x %4x\n", k, compressed[k] & 0xFF, itu_ref[k + i] & 0xFFFF); - j++; - } - } - printf("%d bad samples, out of %d/%d samples\n", j, len, len_data); - if (j) - { - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - g722_encode_free(enc_state); - } -#endif -#if 1 - /* ITU G.722 decode tests, using configuration 2. The QMF is bypassed */ - /* Run each of the tests for each of the modes - 48kbps, 56kbps and 64kbps. */ - for (mode = 1; mode <= 3; mode++) - { - for (file = 0; decode_test_files[file]; file += 5) - { - printf("Testing mode %d, %s -> %s + %s\n", - mode, - decode_test_files[file], - decode_test_files[file + mode], - decode_test_files[file + 4]); - - /* Get the input data */ - len_data = get_test_vector(decode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN); - - /* Get the lower reference output data */ - len_comp_lower = get_test_vector(decode_test_files[file + mode], itu_ref, MAX_TEST_VECTOR_LEN); - - /* Get the upper reference output data */ - len_comp_upper = get_test_vector(decode_test_files[file + 4], itu_ref_upper, MAX_TEST_VECTOR_LEN); - - if (len_data != len_comp_lower || len_data != len_comp_upper) - { - printf("Test data length mismatch\n"); - exit(2); - } - /* Process the input data */ - /* Skip the reset stuff at each end of the data */ - for (i = 0; i < len_data; i++) - { - if ((itu_data[i] & 1) == 0) - break; - } - for (j = i; j < len_data; j++) - { - if ((itu_data[j] & 1)) - break; - } - len = j - i; - for (k = 0; k < len; k++) - 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; - len2 = g722_decode(dec_state, decompressed, compressed, len); - - /* Check the result against the ITU's reference output data */ - j = 0; - for (k = 0; k < len2; k += 2) - { - if ((decompressed[k] & 0xFFFF) != (itu_ref[(k >> 1) + i] & 0xFFFF) - || - (decompressed[k + 1] & 0xFFFF) != (itu_ref_upper[(k >> 1) + i] & 0xFFFF)) - { - printf(">>> %6d %4x %4x %4x %4x\n", k >> 1, decompressed[k] & 0xFFFF, decompressed[k + 1] & 0xFFFF, itu_ref[(k >> 1) + i] & 0xFFFF, itu_ref_upper[(k >> 1) + i] & 0xFFFF); - j++; - } - } - printf("%d bad samples, out of %d/%d samples\n", j, len, len_data); - if (j) - { - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - g722_decode_free(dec_state); - } - } -#endif - printf("Tests passed.\n"); -} -/*- End of function --------------------------------------------------------*/ - -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; - int16_t original[1024]; - uint8_t compressed[1024]; - int16_t decompressed[1024]; - int len; - int len2; - int len3; - int i; - int32_t in_level; - int32_t out_level; - - /* Test a back to back encoder/decoder pair to ensure we comply with Figure 11/G.722 to - 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); - 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]); - 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]); - 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); - do - { - len = swept_tone(swept, original, 1024); - for (i = 0; i < len; 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]); - printf("%10d, %10d, %f\n", in_level, out_level, (float) out_level/in_level); - } - while (len > 0); - swept_tone_free(swept); - g722_encode_free(enc_state); - g722_decode_free(dec_state); - power_meter_free(in_meter); - power_meter_free(out_meter); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - g722_encode_state_t *enc_state; - g722_decode_state_t *dec_state; - int len2; - int len3; - int i; - int file; - SNDFILE *inhandle; - SNDFILE *outhandle; - SF_INFO info; - int outframes; - int samples; - int opt; - int itutests; - int bit_rate; - int eight_k_in; - int eight_k_out; - int encode; - int decode; - int tone_test; - const char *in_file; - const char *out_file; - int16_t indata[BLOCK_LEN]; - int16_t outdata[BLOCK_LEN]; - uint8_t adpcmdata[BLOCK_LEN]; - float tone_level; - uint32_t tone_phase; - 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; - in_file = NULL; - out_file = NULL; - while ((opt = getopt(argc, argv, "b:d:e:i:l:o:t")) != -1) - { - switch (opt) - { - case 'b': - bit_rate = atoi(optarg); - if (bit_rate != 48000 && bit_rate != 56000 && bit_rate != 64000) - { - fprintf(stderr, "Invalid bit rate selected. Only 48000, 56000 and 64000 are valid.\n"); - exit(2); - } - itutests = false; - break; - case 'd': - in_file = optarg; - decode = true; - itutests = false; - break; - case 'e': - in_file = optarg; - encode = true; - itutests = false; - break; - case 'i': - i = atoi(optarg); - if (i != 8000 && i != 16000) - { - fprintf(stderr, "Invalid incoming sample rate. Only 8000 and 16000 are valid.\n"); - exit(2); - } - eight_k_in = (i == 8000); - if (eight_k_in) - in_file = EIGHTK_IN_FILE_NAME; - break; - case 'l': - out_file = optarg; - break; - case 'o': - i = atoi(optarg); - if (i != 8000 && i != 16000) - { - fprintf(stderr, "Invalid outgoing sample rate. Only 8000 and 16000 are valid.\n"); - exit(2); - } - eight_k_out = (i == 8000); - break; - case 't': - tone_test = true; - itutests = false; - break; - default: - //usage(); - exit(2); - } - } - - if (itutests) - { - itu_compliance_tests(); - signal_to_distortion_tests(); - } - else - { - tone_level = dds_scaling_dbm0f(2.5f); - tone_phase = 0; - tone_phase_rate = dds_phase_ratef(1500.0f/2.0f); - if (!decode && !encode) - { - decode = - encode = true; - } - if (in_file == NULL) - { - if (encode) - { - if (eight_k_in) - in_file = EIGHTK_IN_FILE_NAME; - else - in_file = IN_FILE_NAME; - } - else - { - in_file = ENCODED_FILE_NAME; - } - } - if (out_file == NULL) - { - out_file = (decode) ? OUT_FILE_NAME : ENCODED_FILE_NAME; - } - inhandle = NULL; - outhandle = NULL; - file = -1; - if (encode) - { - if (eight_k_in) - { - if ((inhandle = sf_open(in_file, SFM_READ, &info)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", in_file); - exit(2); - } - if (info.samplerate != SAMPLE_RATE) - { - fprintf(stderr, " Unexpected sample rate %d in audio file '%s'\n", info.samplerate, in_file); - exit(2); - } - if (info.channels != 1) - { - fprintf(stderr, " Unexpected number of channels in audio file '%s'\n", in_file); - exit(2); - } - enc_state = g722_encode_init(NULL, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000); - } - else - { - if ((inhandle = sf_open(in_file, SFM_READ, &info)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", in_file); - exit(2); - } - if (info.samplerate != G722_SAMPLE_RATE) - { - fprintf(stderr, " Unexpected sample rate %d in audio file '%s'\n", info.samplerate, in_file); - exit(2); - } - if (info.channels != 1) - { - fprintf(stderr, " Unexpected number of channels in audio file '%s'\n", in_file); - exit(2); - } - enc_state = g722_encode_init(NULL, bit_rate, G722_PACKED); - } - } - else - { - if ((file = open(in_file, O_RDONLY)) < 0) - { - fprintf(stderr, " Failed to open '%s'\n", in_file); - exit(2); - } - } - dec_state = NULL; - if (decode) - { - memset(&info, 0, sizeof(info)); - info.frames = 0; - info.samplerate = (eight_k_out) ? SAMPLE_RATE : G722_SAMPLE_RATE; - info.channels = 1; - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - info.sections = 1; - info.seekable = 1; - if ((outhandle = sf_open(out_file, SFM_WRITE, &info)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", out_file); - exit(2); - } - if (eight_k_out) - dec_state = g722_decode_init(NULL, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000); - else - dec_state = g722_decode_init(NULL, bit_rate, G722_PACKED); - } - else - { - if ((file = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) - { - fprintf(stderr, " Failed to open '%s'\n", out_file); - exit(2); - } - } - for (;;) - { - if (encode) - { - samples = sf_readf_short(inhandle, indata, BLOCK_LEN); - if (samples <= 0) - break; - if (tone_test) - { - for (i = 0; i < samples; i++) - indata[i] = dds_modf(&tone_phase, tone_phase_rate, tone_level, 0); - } - len2 = g722_encode(enc_state, adpcmdata, indata, samples); - } - else - { - len2 = read(file, adpcmdata, BLOCK_LEN); - if (len2 <= 0) - break; - } - if (decode) - { - len3 = g722_decode(dec_state, outdata, adpcmdata, len2); - outframes = sf_writef_short(outhandle, outdata, len3); - if (outframes != len3) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - else - { - len3 = write(file, adpcmdata, len2); - if (len3 <= 0) - break; - } - } - if (encode) - { - if (sf_close(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME); - exit(2); - } - g722_encode_free(enc_state); - } - else - { - close(file); - } - if (decode) - { - if (sf_close(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - g722_decode_free(dec_state); - } - else - { - close(file); - } - printf("'%s' translated to '%s' at %dbps.\n", in_file, out_file, bit_rate); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g726_tests.c b/libs/spandsp/tests/g726_tests.c deleted file mode 100644 index 45f64c228a..0000000000 --- a/libs/spandsp/tests/g726_tests.c +++ /dev/null @@ -1,1280 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * g726_tests.c - Test G.726 encode and decode. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 g726_tests_page G.726 tests -\section g726_tests_page_sec_1 What does it do? -Two sets of tests are performed: - - The tests defined in the G.726 specification, using the test data files supplied with - the specification. - - A generally audio quality test, consisting of compressing and decompressing a speeech - file for audible comparison. - -The speech file should be recorded at 16 bits/sample, 8000 samples/second, and named -"pre_g726.wav". - -\section g726_tests_page_sec_2 How is it used? -To perform the tests in the G.726 specification you need to obtain the test data files from the -specification. These are copyright material, and so cannot be distributed with this test software. - -The files, containing test vectors, which are supplied with the G.726 specification, should be -copied to itutests/g726 so the files are arranged in the same directory heirarchy in which they -are supplied. That is, you should have file names like - - - itutests/g726/DISK1/INPUT/NRM.M - - itutests/g726/DISK1/INPUT/OVR.M - - itutests/g726/DISK2/INPUT/NRM.A - - itutests/g726/DISK2/INPUT/OVR.A - -in your source tree. The ITU tests can then be run by executing g726_tests without -any parameters. - -To perform a general audio quality test, g726_tests should be run with a parameter specifying -the required bit rate for compression. The valid parameters are "-16", "-24", "-32", and "-40". -The test file ../test-data/local/short_nb_voice.wav will be compressed to the specified bit rate, -decompressed, and the resulting audio stored in post_g726.wav. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define BLOCK_LEN 320 -#define MAX_TEST_VECTOR_LEN 40000 - -#define TESTDATA_DIR "../test-data/itu/g726/" - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUT_FILE_NAME "post_g726.wav" - -int16_t outdata[MAX_TEST_VECTOR_LEN]; -uint8_t adpcmdata[MAX_TEST_VECTOR_LEN]; - -int16_t itudata[MAX_TEST_VECTOR_LEN]; -uint8_t itu_ref[MAX_TEST_VECTOR_LEN]; -uint8_t unpacked[MAX_TEST_VECTOR_LEN]; -uint8_t xlaw[MAX_TEST_VECTOR_LEN]; - -/* -Table 4 - Reset and homing sequences for u-law - Normal I-input Overload -Algorithm Input Intermediate Output Input Output Input Intermediate Output - (PCM) (ADPCM) (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) - -16F NRM.M RN16FM.I RN16FM.O I16 RI16FM.O OVR.M RV16FM.I RV16FM.O - HN16FM.I HN16FM.O HI16FM.O HV16FM.I HV16FM.O - -24F NRM.M RN24FM.I RN24FM.O I24 RI24FM.O OVR.M RV24FM.I RV24FM.O - HN24FM.I HN24FM.O HI24FM.O HV24FM.I HV24FM.O - -32F NRM.M RN32FM.I RN32FM.O I32 RI32FM.O OVR.M RV32FM.I RV32FM.O - HN32FM.I HN32FM.O HI32FM.O HV32FM.I HV32FM.O - -40F NRM.M RN40FM.I RN40FM.O I40 RI40FM.O OVR.M RV40FM.I RV40FM.O - HN40FM.I HN40FM.O HI40FM.O HV40FM.I HV40FM.O - - -Table 5 - Reset and homing sequences for A-law - Normal I-input Overload -Algorithm Input Intermediate Output Input Output Input Intermediate Output - (PCM) (ADPCM) (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) -16F NRM.A RN16FA.I RN16FA.O I16 RI16FA.O OVR.A RV16FA.I RV16FA.O - HN16FA.I HN16FA.O HI16FA.O HV16FA.I HV16FA.O - -24F NRM.A RN24FA.I RN24FA.O I24 RI24FA.O OVR.A RV24FA.I RV24FA.O - HN24FA.I HN24FA.O HI24FA.O HV24FA.I HV24FA.O - -32F NRM.A RN32FA.I RN32FA.O I32 RI32FA.O OVR.A RV32FA.I RV32FA.O - HN32FA.I HN32FA.O HI32FA.O HV32FA.I HV32FA.O - -40F NRM.A RN40FA.I RN40FA.O I40 RI40FA.O OVR.A RV40FA.I RV40FA.O - HN40FA.I HN40FA.O HI40FA.O HV40FA.I HV40FA.O - -Table 6 - Reset and homing cross sequences for u-law -> A-law - Normal Overload -Algorithm Input Intermediate Output Input Intermediate Output - (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) -16F NRM.M RN16FM.I RN16FC.O OVR.M RV16FM.I RV16FC.O - HN16FM.I HN16FC.O HV16FM.I HV16FC.O - -24F NRM.M RN24FM.I RN24FC.O OVR.M RV24FM.I RV24FC.O - HN24FM.I HN24FC.O HV24FM.I HV24FC.O - -32F NRM.M RN32FM.I RN32FC.O OVR.M RV32FM.I RV32FC.O - HN32FM.I HN32FC.O HV32FM.I HV32FC.O - -40F NRM.M RN40FM.I RN40FC.O OVR.M RV40FM.I RV40FC.O - HN40FM.I HN40FC.O HV40FM.I HV40FC.O - -Table 7 - Reset and homing cross sequences for A-law -> u-law - Normal Overload -Algorithm Input Intermediate Output Input Intermediate Output - (PCM) (ADPCM) (PCM) (PCM) (ADPCM) (PCM) -16F NRM.A RN16FA.I RN16FX.O OVR.A RV16FA.I RV16FX.O - HN16FA.I HN16FX.O HV16FA.I HV16FX.O - -24F NRM.A RN24FA.I RN24FX.O OVR.A RV24FA.I RV24FX.O - HN24FA.I HN24FX.O HV24FA.I HV24FX.O - -32F NRM.A RN32FA.I RN32FX.O OVR.A RV32FA.I RV32FX.O - HN32FA.I HN32FX.O HV32FA.I HV32FX.O - -40F NRM.A RN40FA.I RN40FX.O OVR.A RV40FA.I RV40FX.O - HN40FA.I HN40FX.O HV40FA.I HV40FX.O -*/ - -#define G726_ENCODING_NONE 9999 - -typedef struct -{ - const char *conditioning_pcm_file; - const char *pcm_file; - const char *conditioning_adpcm_file; - const char *adpcm_file; - const char *output_file; - int rate; - int compression_law; - int decompression_law; -} test_set_t; - -static test_set_t itu_test_sets[] = -{ - /* u-law to u-law tests */ - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/16/RN16FM.I", - TESTDATA_DIR "DISK1/RESET/16/RN16FM.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK1/INPUT/I16", - TESTDATA_DIR "DISK1/RESET/16/RI16FM.O", - 16000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/16/RV16FM.I", - TESTDATA_DIR "DISK1/RESET/16/RV16FM.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/24/RN24FM.I", - TESTDATA_DIR "DISK1/RESET/24/RN24FM.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK1/INPUT/I24", - TESTDATA_DIR "DISK1/RESET/24/RI24FM.O", - 24000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/24/RV24FM.I", - TESTDATA_DIR "DISK1/RESET/24/RV24FM.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/32/RN32FM.I", - TESTDATA_DIR "DISK1/RESET/32/RN32FM.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK1/INPUT/I32", - TESTDATA_DIR "DISK1/RESET/32/RI32FM.O", - 32000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/32/RV32FM.I", - TESTDATA_DIR "DISK1/RESET/32/RV32FM.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/40/RN40FM.I", - TESTDATA_DIR "DISK1/RESET/40/RN40FM.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK1/INPUT/I40", - TESTDATA_DIR "DISK1/RESET/40/RI40FM.O", - 40000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/40/RV40FM.I", - TESTDATA_DIR "DISK1/RESET/40/RV40FM.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - /* A-law to A-law tests */ - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/16/RN16FA.I", - TESTDATA_DIR "DISK2/RESET/16/RN16FA.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK2/INPUT/I16", - TESTDATA_DIR "DISK2/RESET/16/RI16FA.O", - 16000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/16/RV16FA.I", - TESTDATA_DIR "DISK2/RESET/16/RV16FA.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/24/RN24FA.I", - TESTDATA_DIR "DISK2/RESET/24/RN24FA.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK2/INPUT/I24", - TESTDATA_DIR "DISK2/RESET/24/RI24FA.O", - 24000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/24/RV24FA.I", - TESTDATA_DIR "DISK2/RESET/24/RV24FA.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/32/RN32FA.I", - TESTDATA_DIR "DISK2/RESET/32/RN32FA.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK2/INPUT/I32", - TESTDATA_DIR "DISK2/RESET/32/RI32FA.O", - 32000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/32/RV32FA.I", - TESTDATA_DIR "DISK2/RESET/32/RV32FA.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/40/RN40FA.I", - TESTDATA_DIR "DISK2/RESET/40/RN40FA.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - "", - TESTDATA_DIR "DISK2/INPUT/I40", - TESTDATA_DIR "DISK2/RESET/40/RI40FA.O", - 40000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/40/RV40FA.I", - TESTDATA_DIR "DISK2/RESET/40/RV40FA.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - /* u-law to A-law tests */ - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/16/RN16FM.I", - TESTDATA_DIR "DISK1/RESET/16/RN16FC.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/16/RV16FM.I", - TESTDATA_DIR "DISK1/RESET/16/RV16FC.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/24/RN24FM.I", - TESTDATA_DIR "DISK1/RESET/24/RN24FC.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/24/RV24FM.I", - TESTDATA_DIR "DISK1/RESET/24/RV24FC.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/32/RN32FM.I", - TESTDATA_DIR "DISK1/RESET/32/RN32FC.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/32/RV32FM.I", - TESTDATA_DIR "DISK1/RESET/32/RV32FC.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - "", - TESTDATA_DIR "DISK1/RESET/40/RN40FM.I", - TESTDATA_DIR "DISK1/RESET/40/RN40FC.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - "", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - "", - TESTDATA_DIR "DISK1/RESET/40/RV40FM.I", - TESTDATA_DIR "DISK1/RESET/40/RV40FC.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - /* A-law to u-law tests */ - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/16/RN16FA.I", - TESTDATA_DIR "DISK2/RESET/16/RN16FX.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/16/RV16FA.I", - TESTDATA_DIR "DISK2/RESET/16/RV16FX.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/24/RN24FA.I", - TESTDATA_DIR "DISK2/RESET/24/RN24FX.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/24/RV24FA.I", - TESTDATA_DIR "DISK2/RESET/24/RV24FX.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/32/RN32FA.I", - TESTDATA_DIR "DISK2/RESET/32/RN32FX.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/32/RV32FA.I", - TESTDATA_DIR "DISK2/RESET/32/RV32FX.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - "", - TESTDATA_DIR "DISK2/RESET/40/RN40FA.I", - TESTDATA_DIR "DISK2/RESET/40/RN40FX.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - "", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - "", - TESTDATA_DIR "DISK2/RESET/40/RV40FA.I", - TESTDATA_DIR "DISK2/RESET/40/RV40FX.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - /* u-law to u-law tests */ - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", - TESTDATA_DIR "DISK1/HOMING/16/HN16FM.I", - TESTDATA_DIR "DISK1/HOMING/16/HN16FM.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", - TESTDATA_DIR "DISK1/INPUT/I16", - TESTDATA_DIR "DISK1/HOMING/16/HI16FM.O", - 16000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", - TESTDATA_DIR "DISK1/HOMING/16/HV16FM.I", - TESTDATA_DIR "DISK1/HOMING/16/HV16FM.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", - TESTDATA_DIR "DISK1/HOMING/24/HN24FM.I", - TESTDATA_DIR "DISK1/HOMING/24/HN24FM.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", - TESTDATA_DIR "DISK1/INPUT/I24", - TESTDATA_DIR "DISK1/HOMING/24/HI24FM.O", - 24000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", - TESTDATA_DIR "DISK1/HOMING/24/HV24FM.I", - TESTDATA_DIR "DISK1/HOMING/24/HV24FM.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", - TESTDATA_DIR "DISK1/HOMING/32/HN32FM.I", - TESTDATA_DIR "DISK1/HOMING/32/HN32FM.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", - TESTDATA_DIR "DISK1/INPUT/I32", - TESTDATA_DIR "DISK1/HOMING/32/HI32FM.O", - 32000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", - TESTDATA_DIR "DISK1/HOMING/32/HV32FM.I", - TESTDATA_DIR "DISK1/HOMING/32/HV32FM.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", - TESTDATA_DIR "DISK1/HOMING/40/HN40FM.I", - TESTDATA_DIR "DISK1/HOMING/40/HN40FM.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - { - "", - "", - TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", - TESTDATA_DIR "DISK1/INPUT/I40", - TESTDATA_DIR "DISK1/HOMING/40/HI40FM.O", - 40000, - G726_ENCODING_NONE, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", - TESTDATA_DIR "DISK1/HOMING/40/HV40FM.I", - TESTDATA_DIR "DISK1/HOMING/40/HV40FM.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ULAW - }, - /* A-law to A-law tests */ - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", - TESTDATA_DIR "DISK2/HOMING/16/HN16FA.I", - TESTDATA_DIR "DISK2/HOMING/16/HN16FA.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", - TESTDATA_DIR "DISK2/INPUT/I16", - TESTDATA_DIR "DISK2/HOMING/16/HI16FA.O", - 16000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", - TESTDATA_DIR "DISK2/HOMING/16/HV16FA.I", - TESTDATA_DIR "DISK2/HOMING/16/HV16FA.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", - TESTDATA_DIR "DISK2/HOMING/24/HN24FA.I", - TESTDATA_DIR "DISK2/HOMING/24/HN24FA.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", - TESTDATA_DIR "DISK2/INPUT/I24", - TESTDATA_DIR "DISK2/HOMING/24/HI24FA.O", - 24000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", - TESTDATA_DIR "DISK2/HOMING/24/HV24FA.I", - TESTDATA_DIR "DISK2/HOMING/24/HV24FA.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", - TESTDATA_DIR "DISK2/HOMING/32/HN32FA.I", - TESTDATA_DIR "DISK2/HOMING/32/HN32FA.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", - TESTDATA_DIR "DISK2/INPUT/I32", - TESTDATA_DIR "DISK2/HOMING/32/HI32FA.O", - 32000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", - TESTDATA_DIR "DISK2/HOMING/32/HV32FA.I", - TESTDATA_DIR "DISK2/HOMING/32/HV32FA.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", - TESTDATA_DIR "DISK2/HOMING/40/HN40FA.I", - TESTDATA_DIR "DISK2/HOMING/40/HN40FA.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - { - "", - "", - TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", - TESTDATA_DIR "DISK2/INPUT/I40", - TESTDATA_DIR "DISK2/HOMING/40/HI40FA.O", - 40000, - G726_ENCODING_NONE, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", - TESTDATA_DIR "DISK2/HOMING/40/HV40FA.I", - TESTDATA_DIR "DISK2/HOMING/40/HV40FA.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ALAW - }, - /* u-law to A-law tests */ - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", - TESTDATA_DIR "DISK1/HOMING/16/HN16FM.I", - TESTDATA_DIR "DISK1/HOMING/16/HN16FC.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK2/HOMING/16/I_INI_16.A", - TESTDATA_DIR "DISK1/HOMING/16/HV16FM.I", - TESTDATA_DIR "DISK1/HOMING/16/HV16FC.O", - 16000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", - TESTDATA_DIR "DISK1/HOMING/24/HN24FM.I", - TESTDATA_DIR "DISK1/HOMING/24/HN24FC.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK2/HOMING/24/I_INI_24.A", - TESTDATA_DIR "DISK1/HOMING/24/HV24FM.I", - TESTDATA_DIR "DISK1/HOMING/24/HV24FC.O", - 24000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", - TESTDATA_DIR "DISK1/HOMING/32/HN32FM.I", - TESTDATA_DIR "DISK1/HOMING/32/HN32FC.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK2/HOMING/32/I_INI_32.A", - TESTDATA_DIR "DISK1/HOMING/32/HV32FM.I", - TESTDATA_DIR "DISK1/HOMING/32/HV32FC.O", - 32000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/NRM.M", - TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", - TESTDATA_DIR "DISK1/HOMING/40/HN40FM.I", - TESTDATA_DIR "DISK1/HOMING/40/HN40FC.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - { - TESTDATA_DIR "DISK1/PCM_INIT.M", - TESTDATA_DIR "DISK1/INPUT/OVR.M", - TESTDATA_DIR "DISK2/HOMING/40/I_INI_40.A", - TESTDATA_DIR "DISK1/HOMING/40/HV40FM.I", - TESTDATA_DIR "DISK1/HOMING/40/HV40FC.O", - 40000, - G726_ENCODING_ULAW, - G726_ENCODING_ALAW - }, - /* A-law to u-law tests */ - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", - TESTDATA_DIR "DISK2/HOMING/16/HN16FA.I", - TESTDATA_DIR "DISK2/HOMING/16/HN16FX.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK1/HOMING/16/I_INI_16.M", - TESTDATA_DIR "DISK2/HOMING/16/HV16FA.I", - TESTDATA_DIR "DISK2/HOMING/16/HV16FX.O", - 16000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", - TESTDATA_DIR "DISK2/HOMING/24/HN24FA.I", - TESTDATA_DIR "DISK2/HOMING/24/HN24FX.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK1/HOMING/24/I_INI_24.M", - TESTDATA_DIR "DISK2/HOMING/24/HV24FA.I", - TESTDATA_DIR "DISK2/HOMING/24/HV24FX.O", - 24000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", - TESTDATA_DIR "DISK2/HOMING/32/HN32FA.I", - TESTDATA_DIR "DISK2/HOMING/32/HN32FX.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK1/HOMING/32/I_INI_32.M", - TESTDATA_DIR "DISK2/HOMING/32/HV32FA.I", - TESTDATA_DIR "DISK2/HOMING/32/HV32FX.O", - 32000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/NRM.A", - TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", - TESTDATA_DIR "DISK2/HOMING/40/HN40FA.I", - TESTDATA_DIR "DISK2/HOMING/40/HN40FX.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - TESTDATA_DIR "DISK2/PCM_INIT.A", - TESTDATA_DIR "DISK2/INPUT/OVR.A", - TESTDATA_DIR "DISK1/HOMING/40/I_INI_40.M", - TESTDATA_DIR "DISK2/HOMING/40/HV40FA.I", - TESTDATA_DIR "DISK2/HOMING/40/HV40FX.O", - 40000, - G726_ENCODING_ALAW, - G726_ENCODING_ULAW - }, - { - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0 - } -}; - -static int hex_get(char *s) -{ - int i; - int value; - int x; - - for (value = i = 0; i < 2; i++) - { - x = *s++ - 0x30; - if (x > 9) - x -= 0x07; - if (x > 15) - x -= 0x20; - if (x < 0 || x > 15) - return -1; - value <<= 4; - value |= x; - } - return value; -} -/*- End of function --------------------------------------------------------*/ - -static int get_vector(FILE *file, uint8_t vec[]) -{ - char buf[132 + 1]; - char *s; - int i; - int value; - - while (fgets(buf, 133, file)) - { - s = buf; - i = 0; - while ((value = hex_get(s)) >= 0) - { - vec[i++] = value; - s += 2; - } - return i; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int get_test_vector(const char *file, uint8_t buf[], int max_len) -{ - int octets; - int i; - int sum; - FILE *infile; - - if ((infile = fopen(file, "r")) == NULL) - { - fprintf(stderr, " Failed to open '%s'\n", file); - exit(2); - } - octets = 0; - while ((i = get_vector(infile, buf + octets)) > 0) - octets += i; - fclose(infile); - /* The last octet is a sumcheck, so the real data octets are one less than - the total we have */ - octets--; - /* Test the checksum */ - for (sum = i = 0; i < octets; i++) - sum += buf[i]; - if (sum%255 != (int) buf[i]) - { - fprintf(stderr, " Sumcheck failed in '%s' - %x %x\n", file, sum%255, buf[i]); - exit(2); - } - return octets; -} -/*- End of function --------------------------------------------------------*/ - -static void itu_compliance_tests(void) -{ - g726_state_t enc_state; - g726_state_t dec_state; - int len2; - int len3; - int i; - int test; - int bad_samples; - int conditioning_samples; - int samples; - int conditioning_adpcm; - int adpcm; - - len2 = 0; - conditioning_samples = 0; - for (test = 0; itu_test_sets[test].rate; test++) - { - printf("Test %2d: '%s' + '%s'\n" - " -> '%s' + '%s'\n" - " -> '%s' [%d, %d, %d]\n", - test, - itu_test_sets[test].conditioning_pcm_file, - itu_test_sets[test].pcm_file, - itu_test_sets[test].conditioning_adpcm_file, - itu_test_sets[test].adpcm_file, - itu_test_sets[test].output_file, - itu_test_sets[test].rate, - itu_test_sets[test].compression_law, - itu_test_sets[test].decompression_law); - if (itu_test_sets[test].compression_law != G726_ENCODING_NONE) - { - /* Test the encode side */ - g726_init(&enc_state, itu_test_sets[test].rate, itu_test_sets[test].compression_law, G726_PACKING_NONE); - if (itu_test_sets[test].conditioning_pcm_file[0]) - { - conditioning_samples = get_test_vector(itu_test_sets[test].conditioning_pcm_file, xlaw, MAX_TEST_VECTOR_LEN); - printf("Test %d: Homing %d samples at %dbps\n", test, conditioning_samples, itu_test_sets[test].rate); - } - else - { - conditioning_samples = 0; - } - samples = get_test_vector(itu_test_sets[test].pcm_file, xlaw + conditioning_samples, MAX_TEST_VECTOR_LEN); - memcpy(itudata, xlaw, samples + conditioning_samples); - printf("Test %d: Compressing %d samples at %dbps\n", test, samples, itu_test_sets[test].rate); - len2 = g726_encode(&enc_state, adpcmdata, itudata, conditioning_samples + samples); - } - /* Test the decode side */ - g726_init(&dec_state, itu_test_sets[test].rate, itu_test_sets[test].decompression_law, G726_PACKING_NONE); - if (itu_test_sets[test].conditioning_adpcm_file[0]) - { - conditioning_adpcm = get_test_vector(itu_test_sets[test].conditioning_adpcm_file, unpacked, MAX_TEST_VECTOR_LEN); - printf("Test %d: Homing %d octets at %dbps\n", test, conditioning_adpcm, itu_test_sets[test].rate); - } - else - { - conditioning_adpcm = 0; - } - adpcm = get_test_vector(itu_test_sets[test].adpcm_file, unpacked + conditioning_adpcm, MAX_TEST_VECTOR_LEN); - if (itu_test_sets[test].compression_law != G726_ENCODING_NONE) - { - /* Test our compressed version against the reference compressed version */ - printf("Test %d: Compressed data check - %d/%d octets\n", test, conditioning_adpcm + adpcm, len2); - if (conditioning_adpcm + adpcm == len2) - { - for (bad_samples = 0, i = conditioning_samples; i < len2; i++) - { - if (adpcmdata[i] != unpacked[i]) - { - bad_samples++; - printf("Test %d: Compressed mismatch %d %x %x\n", test, i, adpcmdata[i], unpacked[i]); - } - } - if (bad_samples > 0) - { - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - } - else - { - printf("Test %d: Length mismatch - ref = %d, processed = %d\n", test, conditioning_adpcm + adpcm, len2); - exit(2); - } - } - - len3 = g726_decode(&dec_state, outdata, unpacked, conditioning_adpcm + adpcm); - - /* Get the output reference data */ - samples = get_test_vector(itu_test_sets[test].output_file, xlaw, MAX_TEST_VECTOR_LEN); - memcpy(itu_ref, xlaw, samples); - /* Test our decompressed version against the reference decompressed version */ - printf("Test %d: Decompressed data check - %d/%d samples\n", test, samples, len3 - conditioning_adpcm); - if (samples == len3 - conditioning_adpcm) - { - for (bad_samples = 0, i = 0; i < len3; i++) - { - if (itu_ref[i] != ((uint8_t *) outdata)[i + conditioning_adpcm]) - { - bad_samples++; - printf("Test %d: Decompressed mismatch %d %x %x\n", test, i, itu_ref[i], ((uint8_t *) outdata)[i + conditioning_adpcm]); - } - } - if (bad_samples > 0) - { - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - } - else - { - printf("Test %d: Length mismatch - ref = %d, processed = %d\n", test, samples, len3 - conditioning_adpcm); - exit(2); - } - } - - printf("Tests passed.\n"); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - g726_state_t *enc_state; - g726_state_t *dec_state; - int opt; - bool itutests; - int bit_rate; - SNDFILE *inhandle; - SNDFILE *outhandle; - int16_t amp[1024]; - int frames; - int adpcm; - int packing; - - bit_rate = 32000; - itutests = true; - packing = G726_PACKING_NONE; - while ((opt = getopt(argc, argv, "b:LR")) != -1) - { - switch (opt) - { - case 'b': - bit_rate = atoi(optarg); - if (bit_rate != 16000 && bit_rate != 24000 && bit_rate != 32000 && bit_rate != 40000) - { - fprintf(stderr, "Invalid bit rate selected. Only 16000, 24000, 32000 and 40000 are valid.\n"); - exit(2); - } - itutests = false; - break; - case 'L': - packing = G726_PACKING_LEFT; - break; - case 'R': - packing = G726_PACKING_RIGHT; - break; - default: - //usage(); - exit(2); - } - } - - if (itutests) - { - itu_compliance_tests(); - } - else - { - if ((inhandle = sf_open_telephony_read(IN_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME); - exit(2); - } - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - printf("ADPCM packing is %d\n", packing); - enc_state = g726_init(NULL, bit_rate, G726_ENCODING_LINEAR, packing); - dec_state = g726_init(NULL, bit_rate, G726_ENCODING_LINEAR, packing); - - while ((frames = sf_readf_short(inhandle, amp, 159))) - { - adpcm = g726_encode(enc_state, adpcmdata, amp, frames); - frames = g726_decode(dec_state, amp, adpcmdata, adpcm); - sf_writef_short(outhandle, amp, frames); - } - if (sf_close_telephony(inhandle)) - { - printf(" Cannot close audio file '%s'\n", IN_FILE_NAME); - exit(2); - } - if (sf_close_telephony(outhandle)) - { - printf(" Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - printf("'%s' transcoded to '%s' at %dbps.\n", IN_FILE_NAME, OUT_FILE_NAME, bit_rate); - g726_free(enc_state); - g726_free(dec_state); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/gsm0610_tests.c b/libs/spandsp/tests/gsm0610_tests.c deleted file mode 100644 index 06177fd9fd..0000000000 --- a/libs/spandsp/tests/gsm0610_tests.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * gsm0610_tests.c - Test the GSM 06.10 FR codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 gsm0610_tests_page GSM 06.10 full rate codec tests -\section gsm0610_tests_page_sec_1 What does it do? -Two sets of tests are performed: - - The tests defined in the GSM 06.10 specification, using the test data files supplied with - the specification. - - A generally audio quality test, consisting of compressing and decompressing a speeech - file for audible comparison. - -\section gsm0610_tests_page_sec_2 How is it used? -To perform the tests in the GSM 06.10 specification you need to obtain the test data files from the -specification. These are copyright material, and so cannot be distributed with this test software. -They can, however, be freely downloaded from the ETSI web site. - -The files, containing test vectors, which are supplied with the GSM 06.10 specification, should be -copied to etsitests/gsm0610/unpacked so the files are arranged in the following directories. - -./fr_A: - Seq01-A.cod Seq01-A.inp Seq01-A.out - Seq02-A.cod Seq02-A.inp Seq02-A.out - Seq03-A.cod Seq03-A.inp Seq03-A.out - Seq04-A.cod Seq04-A.inp Seq04-A.out - Seq05-A.out - -./fr_L: - Seq01.cod Seq01.inp Seq01.out - Seq02.cod Seq02.inp Seq02.out - Seq03.cod Seq03.inp Seq03.out - Seq04.cod Seq04.inp Seq04.out - Seq05.cod Seq05.out - -./fr_U: - Seq01-U.cod Seq01-U.inp Seq01-U.out - Seq02-U.cod Seq02-U.inp Seq02-U.out - Seq03-U.cod Seq03-U.inp Seq03-U.out - Seq04-U.cod Seq04-U.inp Seq04-U.out - Seq05-U.out - -./fr_homing_A: - Homing01_A.out - Seq01H_A.cod Seq01H_A.inp Seq01H_A.out - Seq02H_A.cod Seq02H_A.inp Seq02H_A.out - Seq03H_A.cod Seq03H_A.inp Seq03H_A.out - Seq04H_A.cod Seq04H_A.inp Seq04H_A.out - Seq05H_A.out - Seq06H_A.cod Seq06H_A.inp - -./fr_homing_L: - Homing01.cod Homing01.out - Seq01h.cod Seq01h.inp Seq01h.out - Seq02h.cod Seq02h.inp Seq02h.out - Seq03h.cod Seq03h.inp Seq03h.out - Seq04h.cod Seq04h.inp Seq04h.out - Seq05h.cod Seq05h.out - Seq06h.cod Seq06h.inp - -./fr_homing_U: - Homing01_U.out - Seq01H_U.cod Seq01H_U.inp Seq01H_U.out - Seq02H_U.cod Seq02H_U.inp Seq02H_U.out - Seq03H_U.cod Seq03H_U.inp Seq03H_U.out - Seq04H_U.cod Seq04H_U.inp Seq04H_U.out - Seq05H_U.out - Seq06H_U.cod Seq06H_U.inp - -./fr_sync_A: - Seqsync_A.inp - Sync000_A.cod --to-- Sync159_A.cod - -./fr_sync_L: - Bitsync.inp - Seqsync.inp - Sync000.cod --to-- Sync159.cod - -./fr_sync_U: - Seqsync_U.inp - Sync000_U.cod --to-- Sync159_U.cod - -This is different from the directory structure in which they are supplied. Also, the files names are a little -different. The supplied names are messy, and inconsistent across the sets. The names required by these tests -just clean up these inconsistencies. Note that you will need a Windows machine to unpack some of the supplied -files. - -To perform a general audio quality test, gsm0610_tests should be run. The file ../test-data/local/short_nb_voice.wav -will be compressed to GSM 06.10 data, decompressed, and the resulting audio stored in post_gsm0610.wav. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define BLOCK_LEN 160 - -#define TESTDATA_DIR "../test-data/etsi/gsm0610/unpacked/fr_" - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUT_FILE_NAME "post_gsm0610.wav" - -#define HIST_LEN 1000 - -uint8_t law_in_vector[1000000]; -int16_t in_vector[1000000]; -uint16_t code_vector_buf[1000000]; -uint8_t code_vector[1000000]; -uint8_t ref_code_vector[1000000]; -uint8_t decoder_code_vector[1000000]; -uint8_t law_out_vector[1000000]; -int16_t out_vector[1000000]; -int16_t ref_out_vector[1000000]; -uint8_t ref_law_out_vector[1000000]; -int vector_len; - -static int get_test_vector(int full, int disk, const char *name) -{ - char buf[500]; - int in; - int len; - int i; - - if (full) - { - sprintf(buf, "%s%c/%s.inp", TESTDATA_DIR, 'L', name); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, in_vector, 1000000); - close(in); - len /= sizeof(int16_t); - vector_len = len; - } - - sprintf(buf, "%s%c/%s.out", TESTDATA_DIR, 'L', name); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, ref_out_vector, 1000000); - close(in); - len /= sizeof(int16_t); - if (full) - { - if (len != vector_len) - { - fprintf(stderr, "Input and reference vector lengths do not match - %d %d\n", vector_len, len); - exit(2); - } - } - else - { - vector_len = len; - } - - sprintf(buf, "%s%c/%s.cod", TESTDATA_DIR, 'L', name); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, code_vector_buf, 1000000); - close(in); - len /= sizeof(int16_t); - for (i = 0; i < len; i++) - { - ref_code_vector[i] = code_vector_buf[i]; - decoder_code_vector[i] = code_vector_buf[i]; - } - if (len*BLOCK_LEN != vector_len*76) - { - fprintf(stderr, "Input and code vector lengths do not match - %d %d\n", vector_len, len); - exit(2); - } - - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int get_law_test_vector(int full, int law, const char *name) -{ - char buf[500]; - int in; - int len; - int i; - int law_uc; - - law_uc = toupper(law); - - if (full) - { - sprintf(buf, "%s%c/%s-%c.inp", TESTDATA_DIR, law_uc, name, law_uc); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, law_in_vector, 1000000); - close(in); - vector_len = len; - - sprintf(buf, "%s%c/%s-%c.cod", TESTDATA_DIR, law_uc, name, law_uc); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, code_vector_buf, 1000000); - close(in); - len /= sizeof(int16_t); - for (i = 0; i < len; i++) - ref_code_vector[i] = code_vector_buf[i]; - if (len*BLOCK_LEN != vector_len*76) - { - fprintf(stderr, "Input and code vector lengths do not match - %d %d\n", vector_len, len); - exit(2); - } - } - - sprintf(buf, "%s%c/%s-%c.out", TESTDATA_DIR, law_uc, name, law_uc); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, ref_law_out_vector, 1000000); - close(in); - if (full) - { - if (len != vector_len) - { - fprintf(stderr, "Input and reference vector lengths do not match - %d %d\n", vector_len, len); - exit(2); - } - } - else - { - vector_len = len; - } - - sprintf(buf, "%s%c/%s.cod", TESTDATA_DIR, 'L', name); - if ((in = open(buf, O_RDONLY)) < 0) - { - fprintf(stderr, "Cannot open %s\n", buf); - exit(2); - } - len = read(in, code_vector_buf, 1000000); - close(in); - len /= sizeof(int16_t); - for (i = 0; i < len; i++) - decoder_code_vector[i] = code_vector_buf[i]; - - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_linear_test(int full, int disk, const char *name) -{ - gsm0610_state_t *gsm0610_enc_state; - gsm0610_state_t *gsm0610_dec_state; - int i; - int xxx; - int mismatches; - - printf("Performing linear test '%s' from disk %d\n", name, disk); - - get_test_vector(full, disk, name); - - if (full) - { - if ((gsm0610_enc_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) - { - fprintf(stderr, " Cannot create encoder\n"); - exit(2); - } - xxx = gsm0610_encode(gsm0610_enc_state, code_vector, in_vector, vector_len); - - printf("Check code vector of length %d\n", xxx); - for (i = 0, mismatches = 0; i < xxx; i++) - { - if (code_vector[i] != ref_code_vector[i]) - { - printf("%8d/%3d: %6d %6d\n", i/76, i%76, code_vector[i], ref_code_vector[i]); - mismatches++; - } - } - gsm0610_free(gsm0610_enc_state); - if (mismatches) - { - printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx); - exit(2); - } - printf("Test passed\n"); - } - - if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - xxx = gsm0610_decode(gsm0610_dec_state, out_vector, decoder_code_vector, vector_len); - printf("Check output vector of length %d\n", vector_len); - for (i = 0, mismatches = 0; i < vector_len; i++) - { - if (out_vector[i] != ref_out_vector[i]) - { - printf("%8d: %6d %6d\n", i, out_vector[i], ref_out_vector[i]); - mismatches++; - } - } - if (mismatches) - { - printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len); - exit(2); - } - gsm0610_free(gsm0610_dec_state); - printf("Test passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_law_test(int full, int law, const char *name) -{ - gsm0610_state_t *gsm0610_enc_state; - gsm0610_state_t *gsm0610_dec_state; - int i; - int xxx; - int mismatches; - - if (law == 'a') - printf("Performing A-law test '%s'\n", name); - else - printf("Performing u-law test '%s'\n", name); - - get_law_test_vector(full, law, name); - - if (full) - { - if ((gsm0610_enc_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) - { - fprintf(stderr, " Cannot create encoder\n"); - exit(2); - } - if (law == 'a') - { - for (i = 0; i < vector_len; i++) - in_vector[i] = alaw_to_linear(law_in_vector[i]); - } - else - { - for (i = 0; i < vector_len; i++) - in_vector[i] = ulaw_to_linear(law_in_vector[i]); - } - xxx = gsm0610_encode(gsm0610_enc_state, code_vector, in_vector, vector_len); - - printf("Check code vector of length %d\n", xxx); - for (i = 0, mismatches = 0; i < xxx; i++) - { - if (code_vector[i] != ref_code_vector[i]) - { - printf("%8d/%3d: %6d %6d %6d\n", i/76, i%76, code_vector[i], ref_code_vector[i], decoder_code_vector[i]); - mismatches++; - } - } - if (mismatches) - { - printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx); - exit(2); - } - printf("Test passed\n"); - gsm0610_free(gsm0610_enc_state); - } - - if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - xxx = gsm0610_decode(gsm0610_dec_state, out_vector, decoder_code_vector, vector_len); - if (law == 'a') - { - for (i = 0; i < vector_len; i++) - law_out_vector[i] = linear_to_alaw(out_vector[i]); - } - else - { - for (i = 0; i < vector_len; i++) - law_out_vector[i] = linear_to_ulaw(out_vector[i]); - } - printf("Check output vector of length %d\n", vector_len); - for (i = 0, mismatches = 0; i < vector_len; i++) - { - if (law_out_vector[i] != ref_law_out_vector[i]) - { - printf("%8d: %6d %6d\n", i, law_out_vector[i], ref_law_out_vector[i]); - mismatches++; - } - } - if (mismatches) - { - printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len); - exit(2); - } - gsm0610_free(gsm0610_dec_state); - printf("Test passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int repack_gsm0610_voip_to_wav49(uint8_t c[], const uint8_t d[]) -{ - gsm0610_frame_t frame[2]; - int n; - - n = gsm0610_unpack_voip(&frame[0], d); - gsm0610_unpack_voip(&frame[1], d + n); - n = gsm0610_pack_wav49(c, frame); - return n; -} -/*- End of function --------------------------------------------------------*/ - -static int repack_gsm0610_wav49_to_voip(uint8_t d[], const uint8_t c[]) -{ - gsm0610_frame_t frame[2]; - int n[2]; - - gsm0610_unpack_wav49(frame, c); - n[0] = gsm0610_pack_voip(d, &frame[0]); - n[1] = gsm0610_pack_voip(d + n[0], &frame[1]); - return n[0] + n[1]; -} -/*- End of function --------------------------------------------------------*/ - -static int perform_pack_unpack_test(void) -{ - uint8_t a[66]; - uint8_t b[66]; - uint8_t c[66]; - int i; - int j; - - printf("Performing packing/unpacking tests (not part of the ETSI conformance tests).\n"); - /* Try trans-packing a lot of random data looking for before/after mismatch. */ - for (j = 0; j < 1000; j++) - { - for (i = 0; i < 65; i++) - a[i] = rand(); - repack_gsm0610_wav49_to_voip(b, a); - repack_gsm0610_voip_to_wav49(c, b); - if (memcmp(a, c, 65)) - { - printf("Test failed: data mismatch\n"); - exit(2); - } - - for (i = 0; i < 66; i++) - a[i] = rand(); - /* Insert the magic code */ - a[0] = (a[0] & 0xF) | 0xD0; - a[33] = (a[33] & 0xF) | 0xD0; - repack_gsm0610_voip_to_wav49(b, a); - repack_gsm0610_wav49_to_voip(c, b); - //for (i = 0; i < 66; i++) - // printf("%2d: 0x%02X 0x%02X\n", i, a[i], c[i]); - if (memcmp(a, c, 66)) - { - printf("Test failed: data mismatch\n"); - exit(2); - } - } - printf("Test passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -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"); - /* This is not actually an ETSI test */ - perform_pack_unpack_test(); - - printf("Tests passed.\n"); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - SNDFILE *inhandle; - SNDFILE *outhandle; - int frames; - int bytes; - int16_t pre_amp[HIST_LEN]; - int16_t post_amp[HIST_LEN]; - uint8_t gsm0610_data[HIST_LEN]; - gsm0610_state_t *gsm0610_enc_state; - gsm0610_state_t *gsm0610_dec_state; - int opt; - int etsitests; - int packing; - - etsitests = true; - packing = GSM0610_PACKING_NONE; - while ((opt = getopt(argc, argv, "lp:")) != -1) - { - switch (opt) - { - case 'l': - etsitests = false; - break; - case 'p': - packing = atoi(optarg); - break; - default: - //usage(); - exit(2); - } - } - - if (etsitests) - { - etsi_compliance_tests(); - } - else - { - if ((inhandle = sf_open_telephony_read(IN_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME); - exit(2); - } - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - if ((gsm0610_enc_state = gsm0610_init(NULL, packing)) == NULL) - { - fprintf(stderr, " Cannot create encoder\n"); - exit(2); - } - - if ((gsm0610_dec_state = gsm0610_init(NULL, packing)) == NULL) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - - while ((frames = sf_readf_short(inhandle, pre_amp, 2*BLOCK_LEN))) - { - bytes = gsm0610_encode(gsm0610_enc_state, gsm0610_data, pre_amp, frames); - gsm0610_decode(gsm0610_dec_state, post_amp, gsm0610_data, bytes); - sf_writef_short(outhandle, post_amp, frames); - } - - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME); - exit(2); - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - gsm0610_free(gsm0610_enc_state); - gsm0610_free(gsm0610_dec_state); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/hdlc_tests.c b/libs/spandsp/tests/hdlc_tests.c deleted file mode 100644 index 93a364f4f5..0000000000 --- a/libs/spandsp/tests/hdlc_tests.c +++ /dev/null @@ -1,868 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * hdlc_tests.c - * - * 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 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 hdlc_tests_page HDLC tests -\section hdlc_tests_page_sec_1 What does it do? -The HDLC tests exercise the HDLC module, and verifies correct operation -using both 16 and 32 bit CRCs. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp/private/hdlc.h" - -int ref_len; -uint8_t buf[1000]; - -bool abort_reported; -bool frame_handled; -bool frame_failed; -int frame_len_errors; -int frame_data_errors; -bool underflow_reported; -bool framing_ok_reported; -int framing_ok_reports; - -hdlc_rx_state_t rx; -hdlc_tx_state_t tx; - -int frames_sent; -int bytes_sent; -uint64_t start; -uint64_t end; - -/* Use a local random generator, so the results are consistent across platforms. We have hard coded - correct results for a message sequence generated by this particular PRNG. */ -static int my_rand(void) -{ - static int rndnum = 1234567; - - return (rndnum = 1664525U*rndnum + 1013904223U) >> 8; -} -/*- End of function --------------------------------------------------------*/ - -static int cook_up_msg(uint8_t *buf) -{ - int i; - int len; - - /* Use medium length messages, with some randomised length variation. */ - /* TODO: this doesn't exercise extremely short or long messages. */ - len = (my_rand() & 0x3F) + 100; - for (i = 0; i < len; i++) - buf[i] = my_rand(); - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void frame_handler(void *user_data, const uint8_t *pkt, int len, int ok) -{ - if (len < 0) - { - /* Special conditions */ - printf("HDLC rx status is %s (%d)\n", signal_status_to_str(len), len); - switch (len) - { - case SIG_STATUS_FRAMING_OK: - framing_ok_reported = true; - framing_ok_reports++; - break; - case SIG_STATUS_ABORT: - abort_reported = true; - break; - } - return; - } - if (ok) - { - if (len != ref_len) - { - printf("Len error - %d %d\n", len, ref_len); - frame_len_errors++; - return; - } - if (memcmp(pkt, buf, len)) - { - printf("Frame data error\n"); - frame_data_errors++; - return; - } - frame_handled = true; - } - else - { - frame_failed = true; - } -} -/*- End of function --------------------------------------------------------*/ - -static void underflow_handler(void *user_data) -{ - //printf("Underflow reported\n"); - underflow_reported = true; -} -/*- End of function --------------------------------------------------------*/ - -static void check_result(void) -{ - hdlc_rx_stats_t rx_stats; - - hdlc_rx_get_stats(&rx, &rx_stats); - printf("%lu bytes\n", rx_stats.bytes); - printf("%lu good frames\n", rx_stats.good_frames); - printf("%lu CRC errors\n", rx_stats.crc_errors); - printf("%lu length errors\n", rx_stats.length_errors); - printf("%lu aborts\n", rx_stats.aborts); - printf("%d frame length errors\n", frame_len_errors); - printf("%d frame data errors\n", frame_data_errors); - printf("Test duration %" PRIu64 " ticks\n", end - start); - if (rx_stats.bytes != bytes_sent - || - rx_stats.good_frames != frames_sent - || - rx_stats.crc_errors != 0 - || - rx_stats.length_errors != 0 - || - rx_stats.aborts != 0 - || - frame_len_errors != 0 - || - frame_data_errors != 0) - { - printf("Tests failed.\n"); - exit(2); - } - printf("Test passed.\n\n"); -} -/*- End of function --------------------------------------------------------*/ - -static int test_hdlc_modes(void) -{ - int i; - int j; - int len; - int nextbyte; - int progress; - int progress_delay; - uint8_t bufx[100]; - - /* Try sending HDLC messages with CRC-16 */ - 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; - - 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; - frames_sent = 0; - bytes_sent = 0; - for (i = 0; i < 1000000; i++) - { - nextbyte = hdlc_tx_get_byte(&tx); - hdlc_rx_put_byte(&rx, nextbyte); - if (underflow_reported) - { - underflow_reported = false; - nextbyte = hdlc_tx_get_byte(&tx); - hdlc_rx_put_byte(&rx, nextbyte); - frames_sent++; - bytes_sent += ref_len; - if (!frame_handled) - { - printf("Frame not received.\n"); - return -1; - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = false; - } - } - end = rdtscll(); - check_result(); - - /* Now try sending HDLC messages with CRC-16 */ - 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; - - 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; - frames_sent = 0; - bytes_sent = 0; - for (i = 0; i < 10000; i++) - { - len = hdlc_tx_get(&tx, bufx, 100); - hdlc_rx_put(&rx, bufx, len); - if (underflow_reported) - { - underflow_reported = false; - len = hdlc_tx_get(&tx, bufx, 100); - hdlc_rx_put(&rx, bufx, len); - frames_sent++; - bytes_sent += ref_len; - if (!frame_handled) - { - printf("Frame not received.\n"); - return -1; - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = false; - } - } - end = rdtscll(); - check_result(); - - /* Now try sending HDLC messages with CRC-16 bit by bit */ - 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; - - 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; - frames_sent = 0; - bytes_sent = 0; - ref_len = 0; - for (i = 0; i < 8*1000000; i++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (underflow_reported) - { - underflow_reported = false; - for (j = 0; j < 20; j++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - } - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (!frame_handled) - { - printf("Frame not received.\n"); - return -1; - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = false; - } - } - end = rdtscll(); - check_result(); - - /* Now try sending HDLC messages with CRC-32 */ - 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; - - 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; - frames_sent = 0; - bytes_sent = 0; - ref_len = 0; - for (i = 0; i < 1000000; i++) - { - nextbyte = hdlc_tx_get_byte(&tx); - hdlc_rx_put_byte(&rx, nextbyte); - if (underflow_reported) - { - underflow_reported = false; - nextbyte = hdlc_tx_get_byte(&tx); - hdlc_rx_put_byte(&rx, nextbyte); - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (!frame_handled) - { - printf("Frame not received.\n"); - return -1; - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = false; - } - } - end = rdtscll(); - check_result(); - - /* Now try progressive mode with CRC-16 */ - 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; - - 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; - progress = 9999; - progress_delay = 9999; - frames_sent = 0; - bytes_sent = 0; - ref_len = 0; - for (i = 0; i < 1000000; i++) - { - nextbyte = hdlc_tx_get_byte(&tx); - hdlc_rx_put_byte(&rx, nextbyte); - if (underflow_reported) - { - underflow_reported = false; - nextbyte = hdlc_tx_get_byte(&tx); - hdlc_rx_put_byte(&rx, nextbyte); - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (!frame_handled) - { - printf("Frame not received.\n"); - return -1; - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, 10); - progress = 10; - progress_delay = 8; - frame_handled = false; - } - if (progress < ref_len && progress_delay-- <= 0) - { - if (hdlc_tx_frame(&tx, buf + progress, (progress + 10 <= ref_len) ? 10 : ref_len - progress) < 0) - { - printf("Failed to add progressively\n"); - return -1; - } - progress += 10; - progress_delay = 8; - } - } - end = rdtscll(); - check_result(); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int test_hdlc_frame_length_error_handling(void) -{ - int i; - int j; - int nextbyte; - - 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_rx_set_max_frame_len(&rx, 100); - 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; - frames_sent = 0; - bytes_sent = 0; - ref_len = 0; - for (i = 0; i < 8*1000000; i++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = false; - } - if (underflow_reported) - { - underflow_reported = false; - for (j = 0; j < 20; j++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = false; - } - } - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (!frame_handled) - { - /* We should get a failure when the length reaches 101 */ - if (ref_len == 101) - { - printf("Tests passed.\n"); - return 0; - } - if (frame_failed) - printf("Frame failed.\n"); - printf("Frame not received at length %d.\n", ref_len); - return -1; - } - else - { - /* We should get a failure when the length reaches 101 */ - if (ref_len > 100) - { - printf("Tests failed.\n"); - return -1; - } - } - ref_len++; - hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = false; - } - } - /* We shouldn't reach here */ - printf("Tests failed.\n"); - return -1; -} -/*- End of function --------------------------------------------------------*/ - -static int test_hdlc_crc_error_handling(void) -{ - int i; - int j; - int nextbyte; - int corrupt; - - 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; - 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; - frames_sent = 0; - bytes_sent = 0; - ref_len = 100; - corrupt = false; - for (i = 0; i < 8*1000000; i++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = false; - } - if (underflow_reported) - { - underflow_reported = false; - for (j = 0; j < 20; j++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = false; - } - } - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (!frame_handled) - { - if (!corrupt) - { - printf("Frame not received when it should be correct.\n"); - return -1; - } - } - else - { - if (corrupt) - { - printf("Frame received when it should be corrupt.\n"); - return -1; - } - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - if ((corrupt = rand() & 1)) - hdlc_tx_corrupt_frame(&tx); - frame_handled = false; - } - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int test_hdlc_abort_handling(void) -{ - int i; - int j; - int nextbyte; - int abort; - - 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; - 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; - frames_sent = 0; - bytes_sent = 0; - ref_len = 0; - abort = false; - abort_reported = false; - for (i = 0; i < 8*1000000; i++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = false; - } - if (underflow_reported) - { - underflow_reported = false; - for (j = 0; j < 20; j++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = false; - } - } - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (abort) - { - if (abort && !abort_reported) - { - printf("Abort not received when sent\n"); - return -1; - } - if (frame_handled) - { - if (frame_failed) - printf("Frame failed.\n"); - printf("Frame received when abort sent.\n"); - return -1; - } - } - else - { - if (abort_reported) - { - printf("Abort received when not sent\n"); - return -1; - } - if (!frame_handled) - { - if (frame_failed) - printf("Frame failed.\n"); - printf("Frame not received.\n"); - return -1; - } - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - if ((abort = rand() & 1)) - hdlc_tx_abort(&tx); - frame_handled = false; - abort_reported = false; - } - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -static int test_hdlc_octet_count_handling(void) -{ - int i; - int j; - int nextbyte; - - 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_rx_set_max_frame_len(&rx, 50); - hdlc_rx_set_octet_counting_report_interval(&rx, 16); - 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; - frames_sent = 0; - bytes_sent = 0; - ref_len = 0; - for (i = 0; i < 8*1000000; i++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = false; - } - if (underflow_reported) - { - underflow_reported = false; - for (j = 0; j < 20; j++) - { - nextbyte = hdlc_tx_get_bit(&tx); - hdlc_rx_put_bit(&rx, nextbyte); - if (framing_ok_reported) - { - printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = false; - } - } - if (ref_len) - { - frames_sent++; - bytes_sent += ref_len; - } - if (!frame_handled) - { - if (frame_failed) - printf("Frame failed.\n"); - printf("Frame not received.\n"); - return -1; - } - ref_len = cook_up_msg(buf); - hdlc_tx_frame(&tx, buf, ref_len); - hdlc_tx_abort(&tx); - //hdlc_tx_corrupt_frame(&tx); - frame_handled = false; - } - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static void hdlc_tests(void) -{ - printf("HDLC module tests\n"); - - if (test_hdlc_modes()) - { - printf("Tests failed\n"); - exit(2); - } - if (test_hdlc_frame_length_error_handling()) - { - printf("Tests failed\n"); - exit(2); - } - if (test_hdlc_crc_error_handling()) - { - printf("Tests failed\n"); - exit(2); - } - if (test_hdlc_abort_handling()) - { - printf("Tests failed\n"); - exit(2); - } -#if 0 - if (test_hdlc_octet_count_handling()) - { - printf("Tests failed\n"); - exit(2); - } -#endif - printf("Tests passed.\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void decode_handler(void *user_data, const uint8_t *pkt, int len, int ok) -{ - int i; - - if (len < 0) - { - /* Special conditions */ - printf("HDLC rx status is %s (%d)\n", signal_status_to_str(len), len); - return; - } - if (ok) - { - printf("Good frame, len = %d\n", len); - printf("HDLC: "); - for (i = 0; i < len; i++) - printf("%02X ", pkt[i]); - printf("\n"); - } - else - { - printf("Bad frame, len = %d\n", len); - } -} -/*- End of function --------------------------------------------------------*/ - -static void decode_bitstream(const char *in_file_name) -{ - char buf[1024]; - int bit; - int num; - hdlc_rx_state_t rx; - FILE *in; - - if ((in = fopen(in_file_name, "r")) == NULL) - { - fprintf(stderr, "Failed to open '%s'\n", in_file_name); - exit(2); - } - - 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) - { - //printf("Rx bit %d - %d\n", num, bit); - //printf("Rx bit %d\n", bit); - hdlc_rx_put_bit(&rx, bit); - } - } - fclose(in); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int opt; - const char *in_file_name; - - in_file_name = NULL; - while ((opt = getopt(argc, argv, "d:")) != -1) - { - switch (opt) - { - case 'd': - in_file_name = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - if (in_file_name) - decode_bitstream(in_file_name); - else - hdlc_tests(); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/ima_adpcm_tests.c b/libs/spandsp/tests/ima_adpcm_tests.c deleted file mode 100644 index 46645f09f0..0000000000 --- a/libs/spandsp/tests/ima_adpcm_tests.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * ima_adpcm_tests.c - Test the IMA/DVI/Intel ADPCM encode and decode - * software. - * - * 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 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 ima_adpcm_tests_page IMA ADPCM tests -\section ima_adpcm_tests_page_sec_1 What does it do? -To perform a general audio quality test, ima_adpcm_tests should be run. The test file -../test-data/local/short_nb_voice.wav will be compressed to the specified bit rate, -decompressed, and the resulting audio stored in post_ima_adpcm.wav. A simple SNR test -is automatically performed. Listening tests may be used for a more detailed evaluation -of the degradation in quality caused by the compression. - -\section ima_adpcm_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUT_FILE_NAME "post_ima_adpcm.wav" - -#define HIST_LEN 2000 - -int main(int argc, char *argv[]) -{ - int i; - SNDFILE *inhandle; - SNDFILE *outhandle; - int frames; - int dec_frames; - int ima_bytes; - double pre_energy; - double post_energy; - double diff_energy; - int16_t pre_amp[HIST_LEN]; - int16_t post_amp[HIST_LEN]; - uint8_t ima_data[HIST_LEN]; - int16_t history[HIST_LEN]; - int hist_in; - int hist_out; - ima_adpcm_state_t *ima_enc_state; - ima_adpcm_state_t *ima_dec_state; - int xx; - int total_pre_samples; - int total_compressed_bytes; - int total_post_samples; - int variant; - int chunk_size; - int enc_chunk_size; - 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; - while ((opt = getopt(argc, argv, "ac:i:lv")) != -1) - { - switch (opt) - { - case 'a': - variant = IMA_ADPCM_IMA4; - chunk_size = 505; - break; - case 'c': - enc_chunk_size = atoi(optarg); - break; - case 'i': - in_file_name = optarg; - break; - case 'l': - log_encoded_data = true; - break; - case 'v': - variant = IMA_ADPCM_VDVI; - break; - default: - //usage(); - exit(2); - break; - } - } - - if ((inhandle = sf_open_telephony_read(in_file_name, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", in_file_name); - exit(2); - } - - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - if ((ima_enc_state = ima_adpcm_init(NULL, variant, enc_chunk_size)) == NULL) - { - fprintf(stderr, " Cannot create encoder\n"); - exit(2); - } - - if ((ima_dec_state = ima_adpcm_init(NULL, variant, enc_chunk_size)) == NULL) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - - hist_in = 0; - hist_out = 0; - pre_energy = 0.0; - post_energy = 0.0; - diff_energy = 0.0; - total_pre_samples = 0; - total_compressed_bytes = 0; - total_post_samples = 0; - while ((frames = sf_readf_short(inhandle, pre_amp, chunk_size))) - { - total_pre_samples += frames; - ima_bytes = ima_adpcm_encode(ima_enc_state, ima_data, pre_amp, frames); - if (log_encoded_data) - write(1, ima_data, ima_bytes); - total_compressed_bytes += ima_bytes; - dec_frames = ima_adpcm_decode(ima_dec_state, post_amp, ima_data, ima_bytes); - total_post_samples += dec_frames; - for (i = 0; i < frames; i++) - { - history[hist_in++] = pre_amp[i]; - if (hist_in >= HIST_LEN) - hist_in = 0; - pre_energy += (double) pre_amp[i] * (double) pre_amp[i]; - } - for (i = 0; i < dec_frames; i++) - { - post_energy += (double) post_amp[i] * (double) post_amp[i]; - xx = post_amp[i] - history[hist_out++]; - if (hist_out >= HIST_LEN) - hist_out = 0; - diff_energy += (double) xx * (double) xx; - } - sf_writef_short(outhandle, post_amp, dec_frames); - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", in_file_name); - exit(2); - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - ima_adpcm_free(ima_enc_state); - ima_adpcm_free(ima_dec_state); - - printf("Pre samples: %d\n", total_pre_samples); - printf("Compressed bytes: %d\n", total_compressed_bytes); - printf("Post samples: %d\n", total_post_samples); - - printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy); - printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy); - if (fabs(1.0 - post_energy/pre_energy) > 0.05 - || - fabs(diff_energy/post_energy) > 0.03) - { - printf("Tests failed.\n"); - exit(2); - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/image_translate_tests.c b/libs/spandsp/tests/image_translate_tests.c deleted file mode 100644 index 9ec0691fbe..0000000000 --- a/libs/spandsp/tests/image_translate_tests.c +++ /dev/null @@ -1,842 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * image_translate_tests.c - Tests for the image translation routines. - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 image_translate_tests_page Image translation tests -\section image_translate_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define INPUT_TIFF_FILE_NAME "../test-data/local/lenna-colour.tif" - -typedef struct -{ - const uint8_t *image; - int width; - int length; - int current_row; - int bytes_per_pixel; -} image_descriptor_t; - -static void display_row(int row, int width, uint8_t buf[]) -{ - int i; - int test_pixel; - - printf("%3d: ", row); - for (i = 0; i < width; i++) - { - test_pixel = (buf[i >> 3] >> (7 - (i & 7))) & 0x01; - printf("%c", (test_pixel) ? ' ' : '@'); - } - printf("\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void create_undithered_50_by_50(image_descriptor_t *im, uint8_t buf[], int bytes_per_pixel) -{ - unsigned int i; - unsigned int j; - uint8_t *image8; - uint16_t *image16; - int samples_per_pixel; - - im->image = (const uint8_t *) buf; - im->width = 50; - im->length = 50; - im->bytes_per_pixel = bytes_per_pixel; - im->current_row = 0; - - switch (bytes_per_pixel) - { - case 1: - samples_per_pixel = 1; - image8 = buf; - for (i = 0; i < im->length; i++) - { - 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 < im->length; i++) - { - 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 < 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; -#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); -#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 < 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; -#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); -#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 - } - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int test_dithered_50_by_50(int row, int width, uint8_t buf[]) -{ - static const char *image[50] = - { - " 0: @ @ @ @ @ @ @ @ ", - " 1: @ @ @ @ @ @ @ @ @ @ @ @ @ @", - " 2: @ @ @ @ @ @ @ @ @ @ @ @ @", - " 3: @ @ @ @ @ @ @ @ @ @ @ @ @ @ ", - " 4: @ @ @ @ @ @ @ @ @ @ @ @ @ @", - " 5: @ @ @ @ @ @ @ @ @ @ @ @ @ ", - " 6: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@", - " 7: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ ", - " 8: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ ", - " 9: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @", - " 10: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@", - " 11: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ ", - " 12: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ @", - " 13: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @", - " 14: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @@", - " 15: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @@ ", - " 16: @ @ @ @ @ @ @ @ @ @ @@ @ @@@ @@", - " 17: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @", - " 18: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@ @@@ ", - " 19: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @", - " 20: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@@ @@@@@", - " 21: @ @ @ @ @ @ @ @ @ @@ @ @ @ @ @ @ @ @@ @ @", - " 22: @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@@ @ @@ @@", - " 23: @ @ @ @ @ @ @ @ @ @@ @ @ @ @ @ @ @@@ @@ @", - " 24: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@@ @ @ @@ @@", - " 25: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@ @@@@", - " 26: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@@ @ @ @@@ @ @", - " 27: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@ @@ @@@@@", - " 28: @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@ @@ @ @", - " 29: @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@ @@@@@ @@@ @@@@", - " 30: @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@ @ @@@ @@@ @@", - " 31: @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @ @@ @@@ @@@@", - " 32: @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@ @@ @@@ @@", - " 33: @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @@ @ @ @ @@@@@ @@@@", - " 34: @ @ @ @ @ @ @ @ @ @@ @ @ @ @@ @@@@@@@ @ @@@@ @@", - " 35: @ @ @ @ @ @ @ @ @ @@ @@ @@ @@ @ @ @@@@@@ @@@@", - " 36: @ @ @ @ @ @ @ @ @ @ @ @@ @@ @@ @@@ @@ @ @@@@@@ @", - " 37: @ @ @ @ @ @ @ @ @@ @@ @ @ @@ @@ @ @@@@@@@ @@ @@@", - " 38: @ @ @ @ @ @ @ @ @ @ @ @@@ @@ @@ @@@@ @ @@@@@@@@@@", - " 39: @ @ @ @ @ @ @ @@ @@ @@ @@ @@@@ @@@@ @@ @@ @@@", - " 40: @ @ @ @ @@ @ @ @@ @ @ @ @ @@ @@ @ @@ @@@@@@@@@@@@", - " 41: @ @ @ @ @ @ @ @@ @ @@@ @@@ @@@ @@@@@@@@@ @@ @@ @@", - " 42: @ @ @ @ @@ @ @ @ @@ @ @@ @@ @@@@ @ @ @@@@@@@@@@@@", - " 43: @ @ @ @ @ @ @@ @@ @ @@ @@ @@@ @ @@@@@@@ @@ @@@@@@", - " 44: @ @ @ @ @ @ @ @ @@ @@ @@ @@ @@@@@ @@ @@@@@@@@ @@@", - " 45: @ @ @ @ @ @ @@ @@ @@ @@ @@ @@@ @ @@@@@@@@ @@@@@@@@", - " 46: @ @ @ @ @ @ @@ @ @ @@ @@ @@ @@@@@ @ @@ @@@@@@@@@@", - " 47: @ @ @ @ @ @@ @ @ @@@@ @@@@ @@@@@ @@@@@@@@@@@ @@@@@", - " 48: @ @ @ @@ @ @@ @@ @ @@ @ @@@ @ @@@@@ @@@@@@@@@@@@@", - " 49: @ @ @ @ @ @@ @@ @@ @@ @@@@ @@@@@@@ @@@@@@ @@@@@@@@" - }; - int i; - int match; - int ref_pixel; - int test_pixel; - - match = 0; - for (i = 0; i < width; i++) - { - ref_pixel = (image[row][i + 5] == ' '); - test_pixel = (buf[i >> 3] >> (7 - (i & 7))) & 0x01; - if (ref_pixel != test_pixel) - match = -1; - } - return match; -} -/*- End of function --------------------------------------------------------*/ - -static int row_read(void *user_data, uint8_t buf[], size_t len) -{ - image_descriptor_t *im; - - im = (image_descriptor_t *) user_data; - if (im->current_row >= im->length) - return 0; - memcpy(buf, &im->image[im->current_row*im->width*im->bytes_per_pixel], len); - im->current_row++; - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void get_bilevel_image(image_translate_state_t *s, int compare) -{ - int i; - int len; - uint8_t row_buf[s->output_length*s->output_width/8]; - - for (i = 0; i < s->output_length; i++) - { - if ((len = image_translate_row(s, row_buf, (s->output_width + 7)/8)) != (s->output_width + 7)/8) - { - printf("Image finished early - %d %d\n", len, (s->output_width + 7)/8); - exit(2); - } - display_row(i, s->output_width, row_buf); - if (compare) - { - if (test_dithered_50_by_50(i, s->output_width, row_buf)) - { - printf("Dithered image mismatch at row %d\n", i); - //exit(2); - } - } - } - if ((len = image_translate_row(s, row_buf, (s->output_width + 7)/8)) != 0) - { - printf("Image finished late - %d %d\n", len, (s->output_width + 7)/8); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void get_gray8_image(image_translate_state_t *s, int compare) -{ - unsigned int i; - unsigned int j; - int len; - uint8_t row_buf[s->output_length*s->output_width]; - - for (i = 0; i < s->output_length; i++) - { - if ((len = image_translate_row(s, row_buf, s->output_width)) != s->output_width) - { - printf("Image finished early - %d %d\n", len, s->output_width); - exit(2); - } - if (compare) - { - for (j = 0; j < 50; j++) - { - if (row_buf[j] != (((i + j)*655) >> 8)) - { - printf("Image mismatch - %dx%d - %d %d\n", j, i, ((i + j)*655) >> 8, row_buf[j]); - //exit(2); - } - } - } - } - if ((len = image_translate_row(s, row_buf, s->output_width)) != 0) - { - printf("Image finished late - %d %d\n", len, s->output_width); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void get_gray16_image(image_translate_state_t *s, int compare) -{ - unsigned int i; - unsigned int j; - int len; - uint16_t row_buf[s->output_length*s->output_width]; - - for (i = 0; i < s->output_length; i++) - { - if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*s->output_width)) != 2*s->output_width) - { - printf("Image finished early - %d %d\n", len, 2*s->output_width); - exit(2); - } - if (compare) - { - for (j = 0; j < s->output_width; j++) - { - if (row_buf[j] != (i + j)*655) - { - printf("Image mismatch - %dx%d - %d %d\n", j, i, (i + j)*655, row_buf[j]); - //exit(2); - } - } - } - } - if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*s->output_width)) != 0) - { - printf("Image finished late - %d %d\n", len, 2*s->output_width); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -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[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, samples_per_pixel*s->output_width)) != samples_per_pixel*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 < s->output_width; j++) - { -#if 0 - r = ((i + j)*655) >> 8; - g = ((i + j)*655) >> 8; - b = ((i + j)*655) >> 8; -#else - r = saturateu8((((i + j)*655U)*36532U) >> 23); - g = saturateu8((((i + j)*655U)*37216U) >> 24); - b = saturateu8((((i + j)*655U)*47900U) >> 22); -#endif - 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[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, samples_per_pixel*s->output_width)) != 0) - { - printf("Image finished late - %d %d\n", len, samples_per_pixel*s->output_width); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -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[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, 2*samples_per_pixel*s->output_width)) != 2*samples_per_pixel*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 < s->output_width; j++) - { -#if 0 - r = (i + j)*655; - g = (i + j)*655; - b = (i + j)*655; -#else - r = saturateu16((((i + j)*655U)*36532U) >> 15); - g = saturateu16((((i + j)*655U)*37216U) >> 16); - b = saturateu16((((i + j)*655U)*47900U) >> 14); -#endif - 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[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, 2*samples_per_pixel*s->output_width)) != 0) - { - printf("Image finished late - %d %d\n", len, 2*samples_per_pixel*s->output_width); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void translate_tests_gray8(void) -{ - image_translate_state_t *s; - uint8_t image[50*50]; - image_descriptor_t im; - - 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_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, -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_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_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_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_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_BILEVEL, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, 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_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, 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, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, 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_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 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); -} -/*- End of function --------------------------------------------------------*/ - -static void translate_tests_colour8(void) -{ - image_translate_state_t *s; - 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_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_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_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, -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_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); -} -/*- End of function --------------------------------------------------------*/ - -static void grow_tests_colour8(void) -{ - image_translate_state_t *s; - 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_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 --------------------------------------------------------*/ - -static int row_read2(void *user_data, uint8_t buf[], size_t len) -{ - image_translate_state_t *s; - - s = (image_translate_state_t *) user_data; - image_translate_row(s, buf, len); - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void lenna_tests(int output_width, int output_length_scaling, const char *file) -{ - TIFF *in_file; - TIFF *out_file; - int image_width; - int image_length; - int output_length; - int len; - int total; - 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; - - if (output_length_scaling >= 0) - printf("Dithering Lenna from colour to bi-level test\n"); - else - printf("Processing Lenna test\n"); - if ((in_file = TIFFOpen(INPUT_TIFF_FILE_NAME, "r")) == NULL) - return; - image_width = 0; - TIFFGetField(in_file, TIFFTAG_IMAGEWIDTH, &image_width); - if (image_width <= 0) - return; - image_length = 0; - TIFFGetField(in_file, TIFFTAG_IMAGELENGTH, &image_length); - if (image_length <= 0) - return; - x_resolution = 200.0; - TIFFGetField(in_file, TIFFTAG_XRESOLUTION, &x_resolution); - y_resolution = 200.0; - TIFFGetField(in_file, TIFFTAG_YRESOLUTION, &y_resolution); - res_unit = RESUNIT_INCH; - TIFFGetField(in_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); - bits_per_sample = 0; - TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); - samples_per_pixel = 0; - TIFFGetField(in_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); - printf("Original image is %d x %d, %.2f x %.2f resolution, %d bits per sample, %d samples per pixel\n", image_width, image_length, x_resolution, y_resolution, bits_per_sample, samples_per_pixel); - if ((image = malloc(image_width*image_length*samples_per_pixel)) == NULL) - return; - for (total = 0, i = 0; i < 1000; i++) - { - len = TIFFReadEncodedStrip(in_file, i, &image[total], image_width*image_length*samples_per_pixel - total); - if (len <= 0) - break; - total += len; - if (total == image_width*image_length*samples_per_pixel) - { - printf("Done\n"); - break; - } - } - printf("Input image size %d %d\n", total, image_width*image_length*samples_per_pixel); - TIFFClose(in_file); - - if (output_length_scaling > 0) - output_length = (double) image_length*output_length_scaling*output_width/image_width; - else - output_length = -1; - - im.image = image; - im.width = image_width; - im.length = image_length; - im.current_row = 0; - im.bytes_per_pixel = samples_per_pixel; - - s2 = NULL; - switch (output_length_scaling) - { - case -2: - 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_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, 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_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; - } - - if ((out_file = TIFFOpen(file, "w")) == NULL) - return; - TIFFSetField(out_file, TIFFTAG_IMAGEWIDTH, output_width); - TIFFSetField(out_file, TIFFTAG_IMAGELENGTH, output_length); - TIFFSetField(out_file, TIFFTAG_RESOLUTIONUNIT, res_unit); - - switch (output_length_scaling) - { - case -2: - case -1: - TIFFSetField(out_file, TIFFTAG_BITSPERSAMPLE, 8); - TIFFSetField(out_file, TIFFTAG_SAMPLESPERPIXEL, 3); - TIFFSetField(out_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - break; - default: - TIFFSetField(out_file, TIFFTAG_BITSPERSAMPLE, 1); - TIFFSetField(out_file, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField(out_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); - break; - } - if (output_length_scaling > 0) - y_resolution *= output_length_scaling; - TIFFSetField(out_file, TIFFTAG_XRESOLUTION, x_resolution); - TIFFSetField(out_file, TIFFTAG_YRESOLUTION, y_resolution); - TIFFSetField(out_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(out_file, TIFFTAG_ROWSPERSTRIP, -1); - TIFFSetField(out_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(out_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); - TIFFSetField(out_file, TIFFTAG_PAGENUMBER, 0, 1); - - printf("Input %d x %d, output %d x %d\n", image_width, image_length, output_width, output_length); - switch (output_length_scaling) - { - case -2: - if ((image2 = malloc(output_width*output_length*3)) == NULL) - return; - memset(image2, 0, output_width*output_length*3); - n = 0; - for (i = 0; i < output_length; i++) - n += image_translate_row(s2, &image2[n], output_width*3); - TIFFWriteEncodedStrip(out_file, 0, image2, n); - break; - case -1: - if ((image2 = malloc(output_width*output_length*3)) == NULL) - return; - memset(image2, 0, output_width*output_length*3); - n = 0; - for (i = 0; i < output_length; i++) - n += image_translate_row(s, &image2[n], output_width*3); - TIFFWriteEncodedStrip(out_file, 0, image2, n); - break; - default: - if ((image2 = malloc(output_width*output_length/8)) == NULL) - return; - memset(image2, 0, output_width*output_length/8); - n = 0; - for (i = 0; i < output_length; i++) - n += image_translate_row(s, &image2[n], output_width/8); - TIFFWriteEncodedStrip(out_file, 0, image2, n); - break; - } - TIFFWriteDirectory(out_file); - TIFFClose(out_file); - image_translate_free(s); - free(image); - free(image2); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char **argv) -{ -#if 1 - translate_tests_gray16(); - translate_tests_gray8(); - translate_tests_colour16(); - translate_tests_colour8(); -#endif -#if 1 - grow_tests_colour8(); -#endif -#if 1 - lenna_tests(0, 0, "lenna-bw.tif"); - lenna_tests(200, 0, "lenna-bw-200.tif"); - lenna_tests(1728, 0, "lenna-bw-1728.tif"); - lenna_tests(1728, 2, "lenna-bw-1728-superfine.tif"); - lenna_tests(1728, -1, "lenna-colour-1728.tif"); - lenna_tests(1728, -2, "lenna-gray-1728.tif"); -#endif - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/line_model_monitor.cpp b/libs/spandsp/tests/line_model_monitor.cpp deleted file mode 100644 index 0d3059359d..0000000000 --- a/libs/spandsp/tests/line_model_monitor.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * line_model_monitor.cpp - Model activity in a telephone line model, using the FLTK toolkit. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) - -#define __STDC_LIMIT_MACROS - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_FFTW3_H) -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "line_model_monitor.h" - -struct line_model_monitor_s -{ - Fl_Double_Window *w; - - Fl_Audio_Meter *audio_meter; - - Fl_Group *c_spec; - Fl_Group *c_right; - Fl_Group *c_can; - Fl_Group *c_line_model; - - Ca_Canvas *canvas_spec; - Ca_X_Axis *spec_freq; - Ca_Y_Axis *spec_amp; - Ca_Line *spec_re; - double spec_re_plot[2*512]; - - Ca_Canvas *canvas_can; - Ca_X_Axis *can_x; - Ca_Y_Axis *can_y; - Ca_Line *can_re; - double can_re_plot[512]; - - Ca_Canvas *canvas_line_model; - Ca_X_Axis *line_model_x; - Ca_Y_Axis *line_model_y; - Ca_Line *line_model_re; - double line_model_re_plot[512]; - - int in_ptr; -#if defined(HAVE_FFTW3_H) - double in[1024][2]; - double out[1024][2]; -#else - fftw_complex in[1024]; - fftw_complex out[1024]; -#endif - fftw_plan p; -}; - -static int skip = 0; -static struct line_model_monitor_s model; -static struct line_model_monitor_s *s = &model; - -int line_model_monitor_can_update(const float *coeffs, int len) -{ - int i; - float min; - float max; - - if (s->can_re) - delete s->can_re; - - s->canvas_can->current(s->canvas_can); - i = 0; - min = coeffs[i]; - max = coeffs[i]; - for (i = 0; i < len; i++) - { - s->can_re_plot[2*i] = i; - s->can_re_plot[2*i + 1] = coeffs[i]; - if (min > coeffs[i]) - min = coeffs[i]; - if (max < coeffs[i]) - max = coeffs[i]; - } - s->can_y->maximum((max == min) ? max + 0.2 : max); - s->can_y->minimum(min); - s->can_re = new Ca_Line(len, s->can_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - if (++skip >= 100) - { - skip = 0; - Fl::check(); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int line_model_monitor_line_model_update(const float *coeffs, int len) -{ - int i; - float min; - float max; - - if (s->line_model_re) - delete s->line_model_re; - - s->canvas_line_model->current(s->canvas_line_model); - i = 0; - min = coeffs[i]; - max = coeffs[i]; - for (i = 0; i < len; i++) - { - s->line_model_re_plot[2*i] = i; - s->line_model_re_plot[2*i + 1] = coeffs[i]; - if (min > coeffs[i]) - min = coeffs[i]; - if (max < coeffs[i]) - max = coeffs[i]; - } - s->line_model_y->maximum((max == min) ? max + 0.2 : max); - s->line_model_y->minimum(min); - s->line_model_re = new Ca_Line(len, s->line_model_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - if (++skip >= 100) - { - skip = 0; - Fl::check(); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int line_model_monitor_line_spectrum_update(const int16_t amp[], int len) -{ - int i; - int x; - - for (i = 0; i < len; i++) - s->audio_meter->sample(amp[i]/32768.0); - - if (s->in_ptr + len < 512) - { - /* Just add this fragment to the buffer. */ - for (i = 0; i < len; i++) -#if defined(HAVE_FFTW3_H) - s->in[s->in_ptr + i][0] = amp[i]; -#else - s->in[s->in_ptr + i].re = amp[i]; -#endif - s->in_ptr += len; - return 0; - } - if (len >= 512) - { - /* We have enough for a whole block. Use the last 512 samples - we have. */ - x = len - 512; - for (i = 0; i < 512; i++) -#if defined(HAVE_FFTW3_H) - s->in[i][0] = amp[x + i]; -#else - s->in[i].re = amp[x + i]; -#endif - } - else - { - /* We want the last 512 samples. */ - x = 512 - len; - for (i = 0; i < x; i++) -#if defined(HAVE_FFTW3_H) - s->in[i][0] = s->in[s->in_ptr - x + i][0]; -#else - s->in[i].re = s->in[s->in_ptr - x + i].re; -#endif - for (i = x; i < 512; i++) -#if defined(HAVE_FFTW3_H) - s->in[i][0] = amp[i - x]; -#else - s->in[i].re = amp[i - x]; -#endif - } - s->in_ptr = 0; -#if defined(HAVE_FFTW3_H) - fftw_execute(s->p); -#else - fftw_one(s->p, s->in, s->out); -#endif - if (s->spec_re) - delete s->spec_re; - s->canvas_spec->current(s->canvas_spec); - for (i = 0; i < 512; i++) - { - s->spec_re_plot[2*i] = i*4000.0/512.0; -#if defined(HAVE_FFTW3_H) - s->spec_re_plot[2*i + 1] = 10.0*log10((s->out[i][0]*s->out[i][0] + s->out[i][1]*s->out[i][1])/(256.0*32768*256.0*32768) + 1.0e-10) + 3.14; -#else - s->spec_re_plot[2*i + 1] = 10.0*log10((s->out[i].re*s->out[i].re + s->out[i].im*s->out[i].im)/(256.0*32768*256.0*32768) + 1.0e-10) + 3.14; -#endif - } - s->spec_re = new Ca_Line(512, s->spec_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int start_line_model_monitor(int len) -{ - char buf[132 + 1]; - float x; - float y; - int i; - - s->w = new Fl_Double_Window(850, 400, "Telephone line model monitor"); - - s->c_spec = new Fl_Group(0, 0, 380, 400); - s->c_spec->box(FL_DOWN_BOX); - s->c_spec->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - - s->canvas_spec = new Ca_Canvas(60, 30, 300, 300, "Spectrum"); - s->canvas_spec->box(FL_PLASTIC_DOWN_BOX); - s->canvas_spec->color(7); - s->canvas_spec->align(FL_ALIGN_TOP); - s->canvas_spec->border(15); - - s->spec_freq = new Ca_X_Axis(65, 330, 290, 30, "Freq (Hz)"); - s->spec_freq->align(FL_ALIGN_BOTTOM); - s->spec_freq->minimum(0); - s->spec_freq->maximum(4000); - s->spec_freq->label_format("%g"); - s->spec_freq->minor_grid_color(fl_gray_ramp(20)); - s->spec_freq->major_grid_color(fl_gray_ramp(15)); - s->spec_freq->label_grid_color(fl_gray_ramp(10)); - s->spec_freq->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->spec_freq->minor_grid_style(FL_DOT); - s->spec_freq->major_step(5); - s->spec_freq->label_step(1); - s->spec_freq->axis_color(FL_BLACK); - s->spec_freq->axis_align(CA_BOTTOM | CA_LINE); - - s->spec_amp = new Ca_Y_Axis(20, 35, 40, 290, "Amp (dBmO)"); - s->spec_amp->align(FL_ALIGN_LEFT); - s->spec_amp->minimum(-80.0); - s->spec_amp->maximum(10.0); - s->spec_amp->minor_grid_color(fl_gray_ramp(20)); - s->spec_amp->major_grid_color(fl_gray_ramp(15)); - s->spec_amp->label_grid_color(fl_gray_ramp(10)); - //s->spec_amp->grid_visible(CA_MINOR_TICK | CA_MAJOR_TICK | CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->spec_amp->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->spec_amp->minor_grid_style(FL_DOT); - s->spec_amp->major_step(5); - s->spec_amp->label_step(1); - s->spec_amp->axis_color(FL_BLACK); - - s->spec_amp->current(); - s->spec_re = NULL; - - s->c_spec->end(); - - s->c_right = new Fl_Group(440, 0, 465, 405); - - s->c_can = new Fl_Group(380, 0, 415, 200); - s->c_can->box(FL_DOWN_BOX); - s->c_can->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_can->current(); - - s->canvas_can = new Ca_Canvas(460, 35, 300, 100, "??? coefficients"); - s->canvas_can->box(FL_PLASTIC_DOWN_BOX); - s->canvas_can->color(7); - s->canvas_can->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_can); - s->canvas_can->border(15); - - s->can_x = new Ca_X_Axis(465, 135, 290, 30, "Tap"); - s->can_x->align(FL_ALIGN_BOTTOM); - s->can_x->minimum(0.0); - s->can_x->maximum((float) len); - s->can_x->label_format("%g"); - s->can_x->minor_grid_color(fl_gray_ramp(20)); - s->can_x->major_grid_color(fl_gray_ramp(15)); - s->can_x->label_grid_color(fl_gray_ramp(10)); - s->can_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->can_x->minor_grid_style(FL_DOT); - s->can_x->major_step(5); - s->can_x->label_step(1); - s->can_x->axis_align(CA_BOTTOM | CA_LINE); - s->can_x->axis_color(FL_BLACK); - s->can_x->current(); - - s->can_y = new Ca_Y_Axis(420, 40, 40, 90, "Amp"); - s->can_y->align(FL_ALIGN_LEFT); - s->can_y->minimum(-0.1); - s->can_y->maximum(0.1); - s->can_y->minor_grid_color(fl_gray_ramp(20)); - s->can_y->major_grid_color(fl_gray_ramp(15)); - s->can_y->label_grid_color(fl_gray_ramp(10)); - s->can_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->can_y->minor_grid_style(FL_DOT); - s->can_y->major_step(5); - s->can_y->label_step(1); - s->can_y->axis_color(FL_BLACK); - s->can_y->current(); - - s->c_can->end(); - - s->can_re = NULL; - - s->c_line_model = new Fl_Group(380, 200, 415, 200); - s->c_line_model->box(FL_DOWN_BOX); - s->c_line_model->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_line_model->current(); - - s->canvas_line_model = new Ca_Canvas(460, 235, 300, 100, "Line impulse response model"); - s->canvas_line_model->box(FL_PLASTIC_DOWN_BOX); - s->canvas_line_model->color(7); - s->canvas_line_model->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_line_model); - s->canvas_line_model->border(15); - - s->line_model_x = new Ca_X_Axis(465, 335, 290, 30, "Tap"); - s->line_model_x->align(FL_ALIGN_BOTTOM); - s->line_model_x->minimum(0.0); - s->line_model_x->maximum((float) len); - s->line_model_x->label_format("%g"); - s->line_model_x->minor_grid_color(fl_gray_ramp(20)); - s->line_model_x->major_grid_color(fl_gray_ramp(15)); - s->line_model_x->label_grid_color(fl_gray_ramp(10)); - s->line_model_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->line_model_x->minor_grid_style(FL_DOT); - s->line_model_x->major_step(5); - s->line_model_x->label_step(1); - s->line_model_x->axis_align(CA_BOTTOM | CA_LINE); - s->line_model_x->axis_color(FL_BLACK); - s->line_model_x->current(); - - s->line_model_y = new Ca_Y_Axis(420, 240, 40, 90, "Amp"); - s->line_model_y->align(FL_ALIGN_LEFT); - s->line_model_y->minimum(-0.1); - s->line_model_y->maximum(0.1); - s->line_model_y->minor_grid_color(fl_gray_ramp(20)); - s->line_model_y->major_grid_color(fl_gray_ramp(15)); - s->line_model_y->label_grid_color(fl_gray_ramp(10)); - s->line_model_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->line_model_y->minor_grid_style(FL_DOT); - s->line_model_y->major_step(5); - s->line_model_y->label_step(1); - s->line_model_y->axis_color(FL_BLACK); - s->line_model_y->current(); - s->line_model_re = NULL; - - s->c_line_model->end(); - - s->audio_meter = new Fl_Audio_Meter(810, 40, 10, 250, ""); - s->audio_meter->box(FL_PLASTIC_UP_BOX); - s->audio_meter->type(FL_VERT_AUDIO_METER); - - s->c_right->end(); - - Fl_Group::current()->resizable(s->c_right); - s->w->end(); - s->w->show(); - -#if defined(HAVE_FFTW3_H) - s->p = fftw_plan_dft_1d(1024, s->in, s->out, FFTW_BACKWARD, FFTW_ESTIMATE); - for (i = 0; i < 1024; i++) - { - s->in[i][0] = 0.0; - s->in[i][1] = 0.0; - } -#else - s->p = fftw_create_plan(1024, FFTW_BACKWARD, FFTW_ESTIMATE); - for (i = 0; i < 1024; i++) - { - s->in[i].re = 0.0; - s->in[i].im = 0.0; - } -#endif - s->in_ptr = 0; - - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -void line_model_monitor_wait_to_end(void) -{ - fd_set rfds; - int res; - struct timeval tv; - - fprintf(stderr, "Processing complete. Press the key to end\n"); - do - { - usleep(100000); - Fl::check(); - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_usec = 100000; - tv.tv_sec = 0; - res = select(1, &rfds, NULL, NULL, &tv); - } - while (res <= 0); -} -/*- End of function --------------------------------------------------------*/ - -void line_model_monitor_update_display(void) -{ - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); -} -/*- End of function --------------------------------------------------------*/ -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/line_model_monitor.h b/libs/spandsp/tests/line_model_monitor.h deleted file mode 100644 index 96c0074a7d..0000000000 --- a/libs/spandsp/tests/line_model_monitor.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * line_model_monitor.h - Model activity in a telephone line model, using the FLTK toolkit. - * - * 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 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. - */ - -/*! \page line_model_monitor_page Telephone line model monitoring -\section line_model_monitor_page_sec_1 What does it do? -This code controls a GUI window, which provides monitoring of the internal status -of a telephone line modem. It shows, graphically: - - - the spectrum of the received signal. - - the line model in use (when a known line model is being used). - - the adapted coefficients of the canceller. - -\section line_model_monitor_page_sec_2 How does it work? -This code uses the FLTK cross platform GUI toolkit. It works on X11 and Windows platforms. -In addition to the basic FLTK toolkit, fltk_cartesian is also required. -*/ - -#if !defined(_LINE_MODEL_MONITOR_H_) -#define _LINE_MODEL_MONITOR_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -int start_line_model_monitor(int len); -int line_model_monitor_can_update(const float *coeffs, int len); -int line_model_monitor_line_model_update(const float *coeffs, int len); -int line_model_monitor_line_spectrum_update(const int16_t amp[], int len); -void line_model_monitor_wait_to_end(void); -void line_model_monitor_update_display(void); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/line_model_tests.c b/libs/spandsp/tests/line_model_tests.c deleted file mode 100644 index b44f9771de..0000000000 --- a/libs/spandsp/tests/line_model_tests.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * line_model_tests.c - Tests for the telephone line model. - * - * 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 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. - */ - -/*! \page line_model_tests_page Telephony line model tests -\section line_model_tests_page_sec_1 What does it do? -???. - -\section line_model_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if !defined(NULL) -#define NULL (void *) 0 -#endif - -#define BLOCK_LEN 160 - -#define OUT_FILE_COMPLEXIFY "complexify.wav" -#define IN_FILE_NAME1 "line_model_test_in1.wav" -#define IN_FILE_NAME2 "line_model_test_in2.wav" -#define OUT_FILE_NAME1 "line_model_one_way_test_out.wav" -#define OUT_FILE_NAME2 "line_model_two_way_test_out.wav" - -int channel_codec; -int rbs_pattern; - -static void complexify_tests(void) -{ - complexify_state_t *s; - complexf_t cc; - int16_t amp; - int i; - SNDFILE *outhandle; - int outframes; - int16_t out[40000]; - awgn_state_t noise1; - - if ((outhandle = sf_open_telephony_write(OUT_FILE_COMPLEXIFY, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_COMPLEXIFY); - exit(2); - } - awgn_init_dbm0(&noise1, 1234567, -10.0f); - s = complexify_init(); - for (i = 0; i < 20000; i++) - { - amp = awgn(&noise1); - cc = complexify(s, amp); - out[2*i] = cc.re; - out[2*i + 1] = cc.im; - } - awgn_release(&noise1); - complexify_free(s); - outframes = sf_writef_short(outhandle, out, 20000); - if (outframes != 20000) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_COMPLEXIFY); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void test_one_way_model(int line_model_no, int speech_test) -{ - one_way_line_model_state_t *model; - int16_t input1[BLOCK_LEN]; - int16_t output1[BLOCK_LEN]; - int16_t amp[2*BLOCK_LEN]; - SNDFILE *inhandle1; - SNDFILE *outhandle; - int outframes; - int samples; - int i; - int j; - awgn_state_t noise1; - - if ((model = one_way_line_model_init(line_model_no, -50, channel_codec, rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - awgn_init_dbm0(&noise1, 1234567, -10.0f); - - if (speech_test) - { - if ((inhandle1 = sf_open_telephony_read(IN_FILE_NAME1, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME1); - exit(2); - } - } - else - { - inhandle1 = NULL; - } - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME1, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME1); - exit(2); - } - for (i = 0; i < 10000; i++) - { - if (speech_test) - { - samples = sf_readf_short(inhandle1, input1, BLOCK_LEN); - if (samples == 0) - break; - } - else - { - for (j = 0; j < BLOCK_LEN; j++) - input1[j] = awgn(&noise1); - samples = BLOCK_LEN; - } - for (j = 0; j < samples; j++) - { - one_way_line_model(model, - &output1[j], - &input1[j], - 1); - amp[j] = output1[j]; - } - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - if (speech_test) - { - if (sf_close_telephony(inhandle1)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME1); - exit(2); - } - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME1); - exit(2); - } - one_way_line_model_free(model); -} -/*- End of function --------------------------------------------------------*/ - -static void test_both_ways_model(int line_model_no, int speech_test) -{ - both_ways_line_model_state_t *model; - int16_t input1[BLOCK_LEN]; - int16_t input2[BLOCK_LEN]; - int16_t output1[BLOCK_LEN]; - int16_t output2[BLOCK_LEN]; - int16_t amp[2*BLOCK_LEN]; - SNDFILE *inhandle1; - SNDFILE *inhandle2; - SNDFILE *outhandle; - int outframes; - int samples; - int i; - int j; - awgn_state_t noise1; - awgn_state_t noise2; - - if ((model = both_ways_line_model_init(line_model_no, - -50, - -15.0f, - -15.0f, - line_model_no + 1, - -35, - -15.0f, - -15.0f, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - awgn_init_dbm0(&noise1, 1234567, -10.0f); - awgn_init_dbm0(&noise2, 1234567, -10.0f); - - if (speech_test) - { - if ((inhandle1 = sf_open_telephony_read(IN_FILE_NAME1, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME1); - exit(2); - } - if ((inhandle2 = sf_open_telephony_read(IN_FILE_NAME2, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME2); - exit(2); - } - } - else - { - inhandle1 = - inhandle2 = NULL; - } - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME2, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME2); - exit(2); - } - for (i = 0; i < 10000; i++) - { - if (speech_test) - { - samples = sf_readf_short(inhandle1, input1, BLOCK_LEN); - if (samples == 0) - break; - samples = sf_readf_short(inhandle2, input2, samples); - if (samples == 0) - break; - } - else - { - for (j = 0; j < BLOCK_LEN; j++) - { - input1[j] = awgn(&noise1); - input2[j] = awgn(&noise2); - } - samples = BLOCK_LEN; - } - for (j = 0; j < samples; j++) - { - both_ways_line_model(model, - &output1[j], - &input1[j], - &output2[j], - &input2[j], - 1); - amp[2*j] = output1[j]; - amp[2*j + 1] = output2[j]; - } - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - if (speech_test) - { - if (sf_close_telephony(inhandle1)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME1); - exit(2); - } - if (sf_close_telephony(inhandle2)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME2); - exit(2); - } - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME2); - exit(2); - } - both_ways_line_model_free(model); -} -/*- End of function --------------------------------------------------------*/ - -static void test_line_filter(int line_model_no) -{ - float out; - double sumin; - double sumout; - double gain; - int i; - int j; - int p; - int ptr; - int len; - swept_tone_state_t *s; - float filter[129]; - int16_t buf[BLOCK_LEN]; - - s = swept_tone_init(NULL, 200.0f, 3900.0f, -10.0f, 120*SAMPLE_RATE, 0); - for (j = 0; j < 129; j++) - filter[j] = 0.0f; - ptr = 0; - for (;;) - { - if ((len = swept_tone(s, buf, BLOCK_LEN)) <= 0) - break; - sumin = 0.0; - sumout = 0.0; - for (i = 0; i < len; i++) - { - /* Add the sample in the filter buffer */ - p = ptr; - filter[p] = buf[i]; - if (++p == 129) - p = 0; - ptr = p; - - /* Apply the filter */ - out = 0.0f; - for (j = 0; j < 129; j++) - { - out += line_models[line_model_no][128 - j]*filter[p]; - if (++p >= 129) - p = 0; - } - sumin += buf[i]*buf[i]; - sumout += out*out; - } - /*endfor*/ - gain = (sumin != 0.0) ? 10.0*log10(sumout/sumin + 1.0e-10) : 0.0; - printf("%7.1f %f\n", swept_tone_current_frequency(s), gain); - } - /*endfor*/ - swept_tone_free(s); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int line_model_no; - int opt; - bool speech_test; - - channel_codec = MUNGE_CODEC_NONE; - line_model_no = 0; - rbs_pattern = 0; - speech_test = false; - while ((opt = getopt(argc, argv, "c:m:r:s:")) != -1) - { - switch (opt) - { - case 'c': - channel_codec = atoi(optarg); - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'r': - rbs_pattern = atoi(optarg); - break; - case 's': - speech_test = atoi(optarg); - break; - default: - //usage(); - exit(2); - } - } - complexify_tests(); - test_one_way_model(line_model_no, speech_test); - test_both_ways_model(line_model_no, speech_test); - test_line_filter(line_model_no); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/logging_tests.c b/libs/spandsp/tests/logging_tests.c deleted file mode 100644 index 2ba4bac9db..0000000000 --- a/libs/spandsp/tests/logging_tests.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * logging_tests.c - Tests for the logging functions. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -/*! \page logging_tests_page Logging tests -\section logging_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#define _POSIX_SOURCE -#define _POSIX_C_SOURCE 200112L - -#include -#include -#include -#include -#include - -#include "spandsp.h" - -static bool tests_failed = false; - -static int msg_step = 0; -static int msg2_step = 0; -static bool msg_done = false; -static bool msg2_done = false; - -static void message_handler(void *user_data, int level, const char *text) -{ - const char *ref[] = - { - "TAG Log with tag 1 2 3\n", - "Log with protocol 1 2 3\n", - "ERROR Log with severity log 1 2 3\n", - "FLOW NewTag Log with new tag 1 2 3\n", - "FLOW Protocol NewTag Log with protocol 1 2 3\n", - "FLOW Protocol NewTag Buf 00 01 02 03 04 05 06 07 08 09\n", - "FLOW Protocol NewTag Buf 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09\n", - "00:00:00.000 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.020 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.040 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.060 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.080 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.100 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.120 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.140 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.160 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "00:00:00.180 FLOW Protocol NewTag Time tagged log 1 2 3\n", - "" - }; - - if (ref[msg_step][0] == '\0') - return; - if (strcmp(ref[msg_step], text)) - { - printf(">>>: %s", ref[msg_step]); - tests_failed = true; - } - if (ref[++msg_step][0] == '\0') - msg_done = true; - printf("MSG: %s", text); -} -/*- End of function --------------------------------------------------------*/ - -static void message_handler2(void *user_data, int level, const char *text) -{ - /* TODO: This doesn't check if the date/time field makes sense */ - if (strcmp(" FLOW Protocol NewTag Date/time tagged log 1 2 3\n", text + 23)) - { - printf(">>>: %s", text + 23); - tests_failed = true; - } - if (++msg2_step == 10) - msg2_done = true; - printf("MSG: %s", text); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - logging_state_t *log; - int i; - uint8_t buf[1000]; - struct timespec delay; - - /* Set up a logger */ - if ((log = span_log_init(NULL, 123, "TAG")) == NULL) - { - fprintf(stderr, "Failed to initialise log.\n"); - exit(2); - } - /* Try it */ - span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); - if (span_log(log, SPAN_LOG_FLOW, "Logging to fprintf, as simple as %d %d %d\n", 1, 2, 3)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - - /* Now set a custom log handler */ - span_log_set_message_handler(log, &message_handler, NULL); - span_log_set_sample_rate(log, 44100); - - /* Try the different logging elements */ - span_log_set_level(log, SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); - if (span_log(log, SPAN_LOG_FLOW, "Log with tag %d %d %d\n", 1, 2, 3)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - span_log_set_level(log, SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - if (span_log(log, SPAN_LOG_FLOW, "Log with protocol %d %d %d\n", 1, 2, 3)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_FLOW); - if (span_log(log, SPAN_LOG_ERROR, "Log with severity log %d %d %d\n", 1, 2, 3)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - - span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); - span_log_set_tag(log, "NewTag"); - if (span_log(log, SPAN_LOG_FLOW, "Log with new tag %d %d %d\n", 1, 2, 3)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - - span_log_set_protocol(log, "Protocol"); - if (span_log(log, SPAN_LOG_FLOW, "Log with protocol %d %d %d\n", 1, 2, 3)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - - /* Test logging of buffer contents */ - for (i = 0; i < 1000; i++) - buf[i] = i; - if (span_log_buf(log, SPAN_LOG_FLOW, "Buf", buf, 10)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - if (span_log_buf(log, SPAN_LOG_FLOW, "Buf", buf, 1000)) - fprintf(stderr, "Logged.\n"); - else - fprintf(stderr, "Not logged.\n"); - - /* Test the correct severities will be logged */ - for (i = 0; i < 10; i++) - { - if (!span_log_test(log, i)) - { - if (i != 6) - tests_failed = true; - break; - } - } - - /* Check timestamping by samples */ - span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW | SPAN_LOG_SHOW_SAMPLE_TIME); - for (i = 0; i < 10; i++) - { - span_log(log, SPAN_LOG_FLOW, "Time tagged log %d %d %d\n", 1, 2, 3); - span_log_bump_samples(log, 441*2); - } - - /* Check timestamping by current date and time */ - span_log_set_message_handler(log, &message_handler2, NULL); - span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW | SPAN_LOG_SHOW_DATE); - for (i = 0; i < 10; i++) - { - span_log(log, SPAN_LOG_FLOW, "Date/time tagged log %d %d %d\n", 1, 2, 3); - delay.tv_sec = 0; - delay.tv_nsec = 20000000; - nanosleep(&delay, NULL); - } - if (tests_failed || !msg_done) - { - printf("Tests failed - %d %d.\n", tests_failed, msg_done); - return 2; - } - - span_log_set_message_handler(log, &message_handler, NULL); - - span_log_free(log); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/lpc10_tests.c b/libs/spandsp/tests/lpc10_tests.c deleted file mode 100644 index a733659bc2..0000000000 --- a/libs/spandsp/tests/lpc10_tests.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * lpc10_tests.c - Test the LPC10 low bit rate speech codec. - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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 lpc10_tests_page LPC10 codec tests -\section lpc10_tests_page_sec_1 What does it do? - -\section lpc10_tests_page_sec_2 How is it used? -To perform a general audio quality test, lpc10 should be run. The file ../test-data/local/dam9.wav -will be compressed to LPC10 data, decompressed, and the resulting audio stored in post_lpc10.wav. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define BLOCK_LEN 180 - -#define BLOCKS_PER_READ 5 - -#define IN_FILE_NAME "../test-data/local/dam9.wav" -#define REF_FILE_NAME "../test-data/local/dam9_lpc55.wav" -#define COMPRESS_FILE_NAME "lpc10_out.lpc10" -#define DECOMPRESS_FILE_NAME "lpc10_in.lpc10" -#define OUT_FILE_NAME "post_lpc10.wav" - -int main(int argc, char *argv[]) -{ - SNDFILE *inhandle; - SNDFILE *refhandle; - SNDFILE *outhandle; - int frames; - double pre_energy; - double post_energy; - double ref_energy; - double diff_energy; - int16_t pre_amp[BLOCKS_PER_READ*BLOCK_LEN]; - int16_t post_amp[BLOCKS_PER_READ*BLOCK_LEN]; - int16_t ref_amp[BLOCKS_PER_READ*BLOCK_LEN]; - int16_t log_amp[BLOCKS_PER_READ*BLOCK_LEN*3]; - uint8_t lpc10_data[BLOCKS_PER_READ*7]; - double xx; - lpc10_encode_state_t *lpc10_enc_state; - lpc10_decode_state_t *lpc10_dec_state; - int i; - int block_no; - bool log_error; - bool compress; - bool decompress; - const char *in_file_name; - int compress_file; - int decompress_file; - int len; - int opt; - int enc_len; - int dec_len; - - 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; - break; - case 'd': - decompress = true; - break; - case 'i': - in_file_name = optarg; - break; - case 'l': - log_error = false; - break; - default: - //usage(); - exit(2); - } - } - - compress_file = -1; - decompress_file = -1; - inhandle = NULL; - refhandle = NULL; - outhandle = NULL; - if (!decompress) - { - if ((inhandle = sf_open_telephony_read(in_file_name, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", in_file_name); - exit(2); - } - - if ((refhandle = sf_open_telephony_read(REF_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", REF_FILE_NAME); - exit(2); - } - } - else - { - if ((decompress_file = open(DECOMPRESS_FILE_NAME, O_RDONLY)) < 0) - { - fprintf(stderr, " Cannot open decompressed data file '%s'\n", DECOMPRESS_FILE_NAME); - exit(2); - } - } - - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - 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) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - - if (compress) - { - if ((compress_file = open(COMPRESS_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) - { - fprintf(stderr, " Cannot create compressed data file '%s'\n", COMPRESS_FILE_NAME); - exit(2); - } - } - - pre_energy = 0.0; - post_energy = 0.0; - ref_energy = 0.0; - diff_energy = 0.0; - - if (decompress) - { - while ((len = read(decompress_file, lpc10_data, BLOCKS_PER_READ*7)) > 0) - { - lpc10_decode(lpc10_dec_state, post_amp, lpc10_data, len/7); - sf_writef_short(outhandle, post_amp, BLOCK_LEN*len/7); - } - } - else - { - block_no = 0; - while ((frames = sf_readf_short(inhandle, pre_amp, BLOCKS_PER_READ*BLOCK_LEN)) == BLOCKS_PER_READ*BLOCK_LEN - && - (frames = sf_readf_short(refhandle, ref_amp, BLOCKS_PER_READ*BLOCK_LEN)) == BLOCKS_PER_READ*BLOCK_LEN) - { - enc_len = lpc10_encode(lpc10_enc_state, lpc10_data, pre_amp, BLOCKS_PER_READ*BLOCK_LEN); - if (compress) - write(compress_file, lpc10_data, enc_len); - dec_len = lpc10_decode(lpc10_dec_state, post_amp, lpc10_data, enc_len); - for (i = 0; i < dec_len; i++) - { - pre_energy += (double) pre_amp[i]*(double) pre_amp[i]; - post_energy += (double) post_amp[i]*(double) post_amp[i]; - ref_energy += (double) ref_amp[i]*(double) ref_amp[i]; - /* The reference file has some odd clipping, so eliminate this from the - energy measurement. */ - if (ref_amp[i] == 32767 || ref_amp[i] == -32768) - xx = 0.0; - else - xx = post_amp[i] - ref_amp[i]; - diff_energy += (double) xx*(double) xx; - log_amp[i] = xx; - } - block_no++; - if (log_error) - sf_writef_short(outhandle, log_amp, dec_len); - else - sf_writef_short(outhandle, post_amp, dec_len); - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", in_file_name); - exit(2); - } - if (sf_close_telephony(refhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", REF_FILE_NAME); - exit(2); - } - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - if (compress) - close(compress_file); - if (decompress) - close(decompress_file); - lpc10_encode_free(lpc10_enc_state); - lpc10_decode_free(lpc10_dec_state); - - if (!decompress) - { - printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy); - printf("Difference energy is %f%% of the total.\n", 100.0*diff_energy/ref_energy); - if (fabs(1.0 - post_energy/pre_energy) > 0.05 - || - fabs(diff_energy/post_energy) > 0.03) - { - printf("Tests failed.\n"); - exit(2); - } - printf("Tests passed.\n"); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/make_g168_css.c b/libs/spandsp/tests/make_g168_css.c deleted file mode 100644 index 0cb065783d..0000000000 --- a/libs/spandsp/tests/make_g168_css.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * makecss.c - Create the composite source signal (CSS) for G.168 testing. - * - * 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 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. - */ - -/*! \page makecss_page CSS construction for G.168 testing -\section makecss_page_sec_1 What does it do? -???. - -\section makecss_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_FFTW3_H) -#include -#else -#include -#endif - -#include "spandsp.h" -#include "spandsp/g168models.h" - -#if !defined(NULL) -#define NULL (void *) 0 -#endif - -#define FAST_SAMPLE_RATE 44100.0 - -#define C1_VOICED_SAMPLES 2144 /* 48.62ms at 44100 samples/second => 2144.142 */ -#define C1_NOISE_SAMPLES 8820 /* 200ms at 44100 samples/second => 8820.0 */ -#define C1_SILENCE_SAMPLES 4471 /* 101.38ms at 44100 samples/second => 4470.858 */ - -#define C3_VOICED_SAMPLES 3206 /* 72.69ms at 44100 samples/second => 3205.629 */ -#define C3_NOISE_SAMPLES 8820 /* 200ms at 44100 samples/second => 8820.0 */ -#define C3_SILENCE_SAMPLES 5614 /* 127.31ms at 44100 samples/second => 5614.371 */ - -static double scaling(double f, double start, double end, double start_gain, double end_gain) -{ - double scale; - - scale = start_gain + (f - start)*(end_gain - start_gain)/(end - start); - return scale; -} -/*- End of function --------------------------------------------------------*/ - -static double peak(const int16_t amp[], int len) -{ - int16_t peak; - int i; - - peak = 0; - for (i = 0; i < len; i++) - { - if (abs(amp[i]) > peak) - peak = abs(amp[i]); - } - return peak/32767.0; -} -/*- End of function --------------------------------------------------------*/ - -static double rms(const int16_t amp[], int len) -{ - double ms; - int i; - - ms = 0.0; - for (i = 0; i < len; i++) - ms += amp[i]*amp[i]; - return sqrt(ms/len)/32767.0; -} -/*- End of function --------------------------------------------------------*/ - -static double rms_to_dbm0(double rms) -{ - return 20.0*log10(rms) + DBM0_MAX_POWER; -} -/*- End of function --------------------------------------------------------*/ - -static double rms_to_db(double rms) -{ - return 20.0*log10(rms); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ -#if defined(HAVE_FFTW3_H) - double in[8192][2]; - double out[8192][2]; -#else - fftw_complex in[8192]; - fftw_complex out[8192]; -#endif - fftw_plan p; - int16_t voiced_sound[8192]; - int16_t noise_sound[8830]; - int16_t silence_sound[8192]; - int i; - int voiced_length; - int randy; - double f; - double pk; - double ms; - double scale; - SNDFILE *filehandle; - SF_INFO info; - awgn_state_t *noise_source; - - memset(&info, 0, sizeof(info)); - info.frames = 0; - info.samplerate = FAST_SAMPLE_RATE; - info.channels = 1; - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - info.sections = 1; - info.seekable = 1; - if ((filehandle = sf_open("sound_c1.wav", SFM_WRITE, &info)) == NULL) - { - fprintf(stderr, " Failed to open result file\n"); - exit(2); - } - - printf("Generate C1\n"); - /* The sequence is - 48.62ms of voiced sound from table C.1 of G.168 - 200.0ms of pseudo-noise - 101.38ms of silence - The above is then repeated phase inverted. - - The voice comes straight from C.1, repeated enough times to - fill out the 48.62ms period - i.e. 16 copies of the sequence. - - The pseudo noise section is random numbers filtered by the spectral - pattern in Figure C.2 */ - - /* The set of C1 voice samples is ready for use in the output file. */ - voiced_length = sizeof(css_c1)/sizeof(css_c1[0]); - for (i = 0; i < voiced_length; i++) - voiced_sound[i] = css_c1[i]; - pk = peak(voiced_sound, voiced_length); - ms = rms(voiced_sound, voiced_length); - printf("Voiced level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms)); - -#if defined(HAVE_FFTW3_H) - p = fftw_plan_dft_1d(8192, in, out, FFTW_BACKWARD, FFTW_ESTIMATE); -#else - p = fftw_create_plan(8192, FFTW_BACKWARD, FFTW_ESTIMATE); -#endif - for (i = 0; i < 8192; i++) - { -#if defined(HAVE_FFTW3_H) - in[i][0] = 0.0; - in[i][1] = 0.0; -#else - in[i].re = 0.0; - in[i].im = 0.0; -#endif - } - for (i = 1; i <= 3715; i++) - { - f = FAST_SAMPLE_RATE*i/8192.0; - -#if 1 - if (f < 50.0) - scale = -60.0; - else if (f < 100.0) - scale = scaling(f, 50.0, 100.0, -25.8, -12.8); - else if (f < 200.0) - scale = scaling(f, 100.0, 200.0, -12.8, 17.4); - else if (f < 215.0) - scale = scaling(f, 200.0, 215.0, 17.4, 17.8); - else if (f < 500.0) - scale = scaling(f, 215.0, 500.0, 17.8, 12.2); - else if (f < 1000.0) - scale = scaling(f, 500.0, 1000.0, 12.2, 7.2); - else if (f < 2850.0) - scale = scaling(f, 1000.0, 2850.0, 7.2, 0.0); - else if (f < 3600.0) - scale = scaling(f, 2850.0, 3600.0, 0.0, -2.0); - else if (f < 3660.0) - scale = scaling(f, 3600.0, 3660.0, -2.0, -20.0); - else if (f < 3680.0) - scale = scaling(f, 3600.0, 3680.0, -20.0, -30.0); - else - scale = -60.0; -#else - scale = 0.0; -#endif - randy = ((rand() >> 10) & 0x1) ? 1.0 : -1.0; -#if defined(HAVE_FFTW3_H) - in[i][0] = randy*pow(10.0, scale/20.0)*35.0; - in[8192 - i][0] = -in[i][0]; -#else - in[i].re = randy*pow(10.0, scale/20.0)*35.0; - in[8192 - i].re = -in[i].re; -#endif - } -#if defined(HAVE_FFTW3_H) - fftw_execute(p); -#else - fftw_one(p, in, out); -#endif - for (i = 0; i < 8192; i++) - { -#if defined(HAVE_FFTW3_H) - noise_sound[i] = out[i][1]; -#else - noise_sound[i] = out[i].im; -#endif - } - pk = peak(noise_sound, 8192); - ms = rms(noise_sound, 8192); - printf("Filtered noise level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms)); - - for (i = 0; i < 8192; i++) - silence_sound[i] = 0.0; - - for (i = 0; i < 16; i++) - sf_writef_short(filehandle, voiced_sound, voiced_length); - printf("%d samples of voice\n", 16*voiced_length); - sf_writef_short(filehandle, noise_sound, 8192); - sf_writef_short(filehandle, noise_sound, C1_NOISE_SAMPLES - 8192); - printf("%d samples of noise\n", C1_NOISE_SAMPLES); - sf_writef_short(filehandle, silence_sound, C1_SILENCE_SAMPLES); - printf("%d samples of silence\n", C1_SILENCE_SAMPLES); - - /* Now phase invert the C1 set of samples. */ - voiced_length = sizeof(css_c1)/sizeof(css_c1[0]); - for (i = 0; i < voiced_length; i++) - voiced_sound[i] = -css_c1[i]; - for (i = 0; i < 8192; i++) - noise_sound[i] = -noise_sound[i]; - - for (i = 0; i < 16; i++) - sf_writef_short(filehandle, voiced_sound, voiced_length); - printf("%d samples of voice\n", 16*voiced_length); - sf_writef_short(filehandle, noise_sound, 8192); - sf_writef_short(filehandle, noise_sound, C1_NOISE_SAMPLES - 8192); - printf("%d samples of noise\n", C1_NOISE_SAMPLES); - sf_writef_short(filehandle, silence_sound, C1_SILENCE_SAMPLES); - printf("%d samples of silence\n", C1_SILENCE_SAMPLES); - - if (sf_close(filehandle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", "sound_c1.wav"); - exit(2); - } - - memset(&info, 0, sizeof(info)); - info.frames = 0; - info.samplerate = FAST_SAMPLE_RATE; - info.channels = 1; - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - info.sections = 1; - info.seekable = 1; - if ((filehandle = sf_open("sound_c3.wav", SFM_WRITE, &info)) == NULL) - { - fprintf(stderr, " Failed to open result file\n"); - exit(2); - } - - printf("Generate C3\n"); - /* The sequence is - 72.69ms of voiced sound from table C.3 of G.168 - 200.0ms of pseudo-noise - 127.31ms of silence - The above is then repeated phase inverted. - - The voice comes straight from C.3, repeated enough times to - fill out the 72.69ms period - i.e. 14 copies of the sequence. - - The pseudo noise section is AWGN filtered by the spectral - pattern in Figure C.2. Since AWGN has the quality of being its - own Fourier transform, we can use an approach like the one above - for the C1 signal, using AWGN samples instead of randomly alternating - ones and zeros. */ - - /* Take the supplied set of C3 voice samples. */ - voiced_length = (sizeof(css_c3)/sizeof(css_c3[0])); - for (i = 0; i < voiced_length; i++) - voiced_sound[i] = css_c3[i]; - pk = peak(voiced_sound, voiced_length); - ms = rms(voiced_sound, voiced_length); - printf("Voiced level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms)); - - noise_source = awgn_init_dbm0(NULL, 7162534, rms_to_dbm0(ms)); - for (i = 0; i < 8192; i++) - noise_sound[i] = awgn(noise_source); - pk = peak(noise_sound, 8192); - ms = rms(noise_sound, 8192); - printf("Unfiltered noise level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms)); - - /* Now filter them */ -#if defined(HAVE_FFTW3_H) - p = fftw_plan_dft_1d(8192, in, out, FFTW_BACKWARD, FFTW_ESTIMATE); -#else - p = fftw_create_plan(8192, FFTW_BACKWARD, FFTW_ESTIMATE); -#endif - for (i = 0; i < 8192; i++) - { -#if defined(HAVE_FFTW3_H) - in[i][0] = 0.0; - in[i][1] = 0.0; -#else - in[i].re = 0.0; - in[i].im = 0.0; -#endif - } - for (i = 1; i <= 3715; i++) - { - f = FAST_SAMPLE_RATE*i/8192.0; - -#if 1 - if (f < 50.0) - scale = -60.0; - else if (f < 100.0) - scale = scaling(f, 50.0, 100.0, -25.8, -12.8); - else if (f < 200.0) - scale = scaling(f, 100.0, 200.0, -12.8, 17.4); - else if (f < 215.0) - scale = scaling(f, 200.0, 215.0, 17.4, 17.8); - else if (f < 500.0) - scale = scaling(f, 215.0, 500.0, 17.8, 12.2); - else if (f < 1000.0) - scale = scaling(f, 500.0, 1000.0, 12.2, 7.2); - else if (f < 2850.0) - scale = scaling(f, 1000.0, 2850.0, 7.2, 0.0); - else if (f < 3600.0) - scale = scaling(f, 2850.0, 3600.0, 0.0, -2.0); - else if (f < 3660.0) - scale = scaling(f, 3600.0, 3660.0, -2.0, -20.0); - else if (f < 3680.0) - scale = scaling(f, 3600.0, 3680.0, -20.0, -30.0); - else - scale = -60.0; -#else - scale = 0.0; -#endif -#if defined(HAVE_FFTW3_H) - in[i][0] = noise_sound[i]*pow(10.0, scale/20.0)*0.0106; - in[8192 - i][0] = -in[i][0]; -#else - in[i].re = noise_sound[i]*pow(10.0, scale/20.0)*0.0106; - in[8192 - i].re = -in[i].re; -#endif - } -#if defined(HAVE_FFTW3_H) - fftw_execute(p); -#else - fftw_one(p, in, out); -#endif - for (i = 0; i < 8192; i++) - { -#if defined(HAVE_FFTW3_H) - noise_sound[i] = out[i][1]; -#else - noise_sound[i] = out[i].im; -#endif - } - pk = peak(noise_sound, 8192); - ms = rms(noise_sound, 8192); - printf("Filtered noise level = %.2fdB, crest factor = %.2fdB\n", rms_to_dbm0(ms), rms_to_db(pk/ms)); - - for (i = 0; i < 14; i++) - sf_writef_short(filehandle, voiced_sound, voiced_length); - printf("%d samples of voice\n", 14*voiced_length); - sf_writef_short(filehandle, noise_sound, 8192); - sf_writef_short(filehandle, noise_sound, C3_NOISE_SAMPLES - 8192); - printf("%d samples of noise\n", C3_NOISE_SAMPLES); - sf_writef_short(filehandle, silence_sound, C3_SILENCE_SAMPLES); - printf("%d samples of silence\n", C3_SILENCE_SAMPLES); - - /* Now phase invert the C3 set of samples. */ - voiced_length = (sizeof(css_c3)/sizeof(css_c3[0])); - for (i = 0; i < voiced_length; i++) - voiced_sound[i] = -css_c3[i]; - for (i = 0; i < 8192; i++) - noise_sound[i] = -noise_sound[i]; - - for (i = 0; i < 14; i++) - sf_writef_short(filehandle, voiced_sound, voiced_length); - printf("%d samples of voice\n", 14*voiced_length); - sf_writef_short(filehandle, noise_sound, 8192); - sf_writef_short(filehandle, noise_sound, C3_NOISE_SAMPLES - 8192); - printf("%d samples of noise\n", C3_NOISE_SAMPLES); - sf_writef_short(filehandle, silence_sound, C3_SILENCE_SAMPLES); - printf("%d samples of silence\n", C3_SILENCE_SAMPLES); - - if (sf_close(filehandle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", "sound_c3.wav"); - exit(2); - } - - fftw_destroy_plan(p); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/math_fixed_tests.c b/libs/spandsp/tests/math_fixed_tests.c deleted file mode 100644 index 22f9a3a733..0000000000 --- a/libs/spandsp/tests/math_fixed_tests.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * math_fixed_tests.c - Test the fixed point math functions. - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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 math_fixed_tests_page Fixed point math function tests -\section math_fixed_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -static void fixed_reciprocal16_tests(void) -{ - int x; - uint16_t yu16; - uint32_t yu32; - double z; - double ratio; - double max; - double min; - int shift; - - /* The reciprocal should be with about 0.4%, except for 0, which is obviously a - special case. */ - printf("fixed_reciprocal16() function tests\n"); - if (fixed_reciprocal16(0, &shift) != 0xFFFF || shift != 0) - { - printf("Test failed\n"); - exit(2); - } - min = 999999.0; - max = -999999.0; - for (x = 1; x < 65536; x++) - { - yu16 = fixed_reciprocal16(x, &shift); - yu32 = ((uint32_t) yu16) << shift; - z = 32768.0*32768.0/x; - ratio = z/yu32; - //printf("%6x %15d %f %f\n", x, yu32, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < 0.996 || ratio > 1.004) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_divide16_tests(void) -{ - int x; - int y; - uint16_t yu16; - double z; - double ratio; - double max; - double min; - - printf("fixed_divide16() function tests\n"); - if (fixed_divide16(12345, 0) != 0xFFFF) - { - printf("Test failed\n"); - exit(2); - } - min = 999999.0; - max = -999999.0; - for (y = 32; y < 65536; y += 16) - { - for (x = y*16; x < 65536; x += 16) - { - yu16 = fixed_divide16(y, x); - z = 32768.0*y/x; - ratio = z/yu16; - //printf("%6d %6d %6d %f %f\n", x, y, yu16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < 0.996 || ratio > 1.07) - { - printf("Test failed\n"); - exit(2); - } - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_divide32_tests(void) -{ - uint32_t xu32; - uint16_t yu16; - uint32_t yu32; - double z; - double ratio; - double max; - double min; - - printf("fixed_divide32() function tests\n"); - if (fixed_divide32(12345, 0) != 0xFFFF) - { - printf("Test failed\n"); - exit(2); - } - min = 999999.0; - max = -999999.0; - for (yu32 = 32; yu32 < 65536; yu32 += 16) - { - for (xu32 = yu32*16; xu32 < 65535; xu32 += 16) - { - yu16 = fixed_divide32(yu32, xu32); - z = 32768.0*yu32/xu32; - ratio = z/yu16; - //printf("%6u %6u %6u %f %f\n", xu32, yu32, yu16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < 0.996 || ratio > 1.07) - { - printf("Test failed\n"); - exit(2); - } - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_log10_16_tests(void) -{ - int x; - int16_t yi16; - double z; - double ratio; - double max; - double min; - - printf("Log10 16 bit function tests\n"); - min = 999999.0; - max = -999999.0; - for (x = 1; x < 32500; x++) - { - yi16 = fixed_log10_16(x); - z = 4096.0*log10(x/32768.0); - ratio = z - yi16; - //printf("%6d %15d %f %f\n", x, yi16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < -8.0 || ratio > 8.0) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_log10_32_tests(void) -{ - int x; - int32_t yi32; - double z; - double ratio; - double max; - double min; - - printf("fixed_log10_32() function tests\n"); - min = 999999.0; - max = -999999.0; - for (x = 1; x < 32767*65536; x += 0x4000) - { - yi32 = fixed_log10_32(x); - z = 4096.0*log10(x/(32768.0*65536.0)); - ratio = z - yi32; - //printf("%6d %15d %f %f\n", x, yi32, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < -8.0 || ratio > 8.0) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_sqrt16_tests(void) -{ - int x; - uint16_t yu16; - double z; - double ratio; - double max; - double min; - - printf("fixed_sqrt16() function tests\n"); - min = 999999.0; - max = -999999.0; - for (x = 1; x < 65536; x++) - { - yu16 = fixed_sqrt16(x); - z = sqrt(x)*256.0; - ratio = z/yu16; - //printf("%6d %6d %f %f\n", x, yu16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < 0.999 || ratio > 1.008) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_sqrt32_tests(void) -{ - uint32_t xu32; - uint16_t yu16; - double z; - double ratio; - double max; - double min; - - printf("fixed_sqrt32() function tests\n"); - min = 999999.0; - max = -999999.0; - for (xu32 = 20000; xu32 < 0xFFFF0000; xu32 += 10000) - { - yu16 = fixed_sqrt32(xu32); - z = sqrt(xu32); - ratio = z/yu16; - //printf("%10u %6d %f %f\n", xu32, yu16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < 0.999 || ratio > 1.009) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_sin_tests(void) -{ - int x; - int16_t yi16; - double z; - double ratio; - double max; - double min; - - printf("fixed_sin() function tests\n"); - min = 999999.0; - max = -999999.0; - for (x = 0; x < 65536; x++) - { - yi16 = fixed_sin(x); - z = sin(2.0*3.1415926535*x/65536.0)*32768.0; - ratio = z - yi16; - //printf("%6d %6d %f %f\n", x, yi16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < -2.0 || ratio > 2.0) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_cos_tests(void) -{ - int x; - int16_t yi16; - double z; - double ratio; - double max; - double min; - - printf("fixed_cos() function tests\n"); - min = 999999.0; - max = -999999.0; - for (x = 0; x < 65536; x++) - { - yi16 = fixed_cos(x); - z = cos(2.0*3.1415926535*x/65536.0)*32768.0; - ratio = z - yi16; - //printf("%6d %6d %f %f\n", x, yi16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < -2.0 || ratio > 2.0) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void fixed_atan2_tests(void) -{ - int i; - int x; - int y; - uint16_t yu16; - double z; - double ratio; - double max; - double min; - - printf("fixed_atan2() function tests\n"); - min = 999999.0; - max = -999999.0; - for (i = 0; i < 65536; i++) - { - x = 16384.0*cos(i*2.0*3.1415926535/65536.0); - y = 16384.0*sin(i*2.0*3.1415926535/65536.0); - yu16 = fixed_atan2(y, x); - z = atan2(y/32768.0, x/32768.0)*65536.0/(2.0*3.1415926535); - if (z < 0.0) - z += 65536.0; - ratio = z - yu16; - //printf("%6d %6d %6d %6d %f %f\n", i, x, y, yu16, z, ratio); - if (ratio < min) - min = ratio; - if (ratio > max) - max = ratio; - if (ratio < -43.0 || ratio > 43.0) - { - printf("Test failed\n"); - exit(2); - } - } - printf("min %f, max %f\n", min, max); - printf("Test passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - fixed_reciprocal16_tests(); - fixed_divide16_tests(); - fixed_divide32_tests(); - fixed_log10_16_tests(); - fixed_log10_32_tests(); - fixed_sqrt16_tests(); - fixed_sqrt32_tests(); - fixed_sin_tests(); - fixed_cos_tests(); - fixed_atan2_tests(); - - printf("Tests passed\n"); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/media_monitor.cpp b/libs/spandsp/tests/media_monitor.cpp deleted file mode 100644 index be983e64f8..0000000000 --- a/libs/spandsp/tests/media_monitor.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * media_monitor.cpp - Display IP streaming media status, using the FLTK toolkit. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) - -#define __STDC_LIMIT_MACROS - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "media_monitor.h" - -struct line_model_monitor_s -{ - Fl_Double_Window *w; - - Fl_Group *c_right; - Fl_Group *c_sent; - Fl_Group *c_received; - - Ca_Canvas *canvas_sent; - Ca_X_Axis *sent_x; - Ca_Y_Axis *sent_y; - Ca_Line *sent_re; - double sent_re_plot[1000]; - double sent_re_plot_min; - double sent_re_plot_max; - - Ca_Canvas *canvas_received; - Ca_X_Axis *received_x; - Ca_Y_Axis *received_y; - Ca_Line *received_delays; - double received_delays_plot[4000]; - double received_delays_plot_max; - int min_diff; - int max_diff; - - int highest_seq_no_seen; -}; - -static int skip = 0; -static struct line_model_monitor_s media; -static struct line_model_monitor_s *s = &media; - -void media_monitor_rx(int seq_no, double departure_time, double arrival_time) -{ - double fdiff; - int diff; - int i; - - if (s->received_delays) - delete s->received_delays; - - s->canvas_received->current(s->canvas_received); - fdiff = (arrival_time - departure_time)*1000.0; - diff = (int) fdiff; - if (diff < 0) - diff = 0; - else if (diff > 1999) - diff = 1999; - s->received_delays_plot[2*diff + 1]++; - if (s->received_delays_plot[2*diff + 1] > s->received_delays_plot_max) - { - s->received_delays_plot_max = s->received_delays_plot[2*diff + 1]; - s->received_y->maximum(s->received_delays_plot_max); - } - if (diff > s->max_diff) - { - s->max_diff = diff; - s->received_x->maximum((double) s->max_diff); - } - if (diff < s->min_diff) - { - s->min_diff = diff - 1; - s->received_x->minimum((double) s->min_diff); - } - - s->received_delays = new Ca_Line(2000, s->received_delays_plot, 0, 0, FL_BLUE, CA_NO_POINT); - - if (s->sent_re) - delete s->sent_re; - - s->canvas_sent->current(s->canvas_sent); - - if (seq_no > s->highest_seq_no_seen + 1) - { - for (i = s->highest_seq_no_seen + 1; i < seq_no; i++) - s->sent_re_plot[2*(i%500) + 1] = 0.0; - } - s->sent_re_plot[2*(seq_no%500) + 1] = fdiff; - - if (fdiff > s->sent_re_plot_max) - { - s->sent_re_plot_max = fdiff; - s->sent_y->maximum(s->sent_re_plot_max); - } - if (fdiff < s->sent_re_plot_min) - { - s->sent_re_plot_min = fdiff - 1.0; - s->sent_y->minimum(s->sent_re_plot_min); - } - s->sent_re = new Ca_Line(500, s->sent_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - - if (seq_no > s->highest_seq_no_seen) - s->highest_seq_no_seen = seq_no; - - if (++skip >= 100) - { - skip = 0; - Fl::check(); - } -} -/*- End of function --------------------------------------------------------*/ - -int start_media_monitor(void) -{ - char buf[132 + 1]; - float x; - float y; - int i; - int len; - - len = 128; - - s->w = new Fl_Double_Window(465, 400, "IP streaming media monitor"); - - s->c_right = new Fl_Group(0, 0, 465, 405); - - s->c_sent = new Fl_Group(0, 0, 465, 200); - s->c_sent->box(FL_DOWN_BOX); - s->c_sent->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_sent->current(); - - s->canvas_sent = new Ca_Canvas(110, 35, 300, 100, "Packet delays"); - s->canvas_sent->box(FL_PLASTIC_DOWN_BOX); - s->canvas_sent->color(7); - s->canvas_sent->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_sent); - s->canvas_sent->border(15); - - s->sent_x = new Ca_X_Axis(115, 135, 290, 30, "Packet"); - s->sent_x->align(FL_ALIGN_BOTTOM); - s->sent_x->minimum(0.0); - s->sent_x->maximum(500.0); - s->sent_x->label_format("%g"); - s->sent_x->minor_grid_color(fl_gray_ramp(20)); - s->sent_x->major_grid_color(fl_gray_ramp(15)); - s->sent_x->label_grid_color(fl_gray_ramp(10)); - s->sent_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->sent_x->minor_grid_style(FL_DOT); - s->sent_x->major_step(5); - s->sent_x->label_step(1); - s->sent_x->axis_align(CA_BOTTOM | CA_LINE); - s->sent_x->axis_color(FL_BLACK); - s->sent_x->current(); - - s->sent_y = new Ca_Y_Axis(60, 40, 50, 90, "Delay\n(ms)"); - s->sent_y->align(FL_ALIGN_LEFT); - s->sent_y->minimum(0.0); - s->sent_y->maximum(2000.0); - s->sent_y->minor_grid_color(fl_gray_ramp(20)); - s->sent_y->major_grid_color(fl_gray_ramp(15)); - s->sent_y->label_grid_color(fl_gray_ramp(10)); - s->sent_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->sent_y->minor_grid_style(FL_DOT); - s->sent_y->major_step(5); - s->sent_y->label_step(1); - s->sent_y->axis_color(FL_BLACK); - s->sent_y->current(); - - s->c_sent->end(); - - s->c_received = new Fl_Group(0, 200, 465, 200); - s->c_received->box(FL_DOWN_BOX); - s->c_received->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_received->current(); - - s->canvas_received = new Ca_Canvas(110, 235, 300, 100, "Delay spread"); - s->canvas_received->box(FL_PLASTIC_DOWN_BOX); - s->canvas_received->color(7); - s->canvas_received->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_received); - s->canvas_received->border(15); - - s->received_x = new Ca_X_Axis(115, 335, 290, 30, "Delay (ms)"); - s->received_x->align(FL_ALIGN_BOTTOM); - s->received_x->minimum(0.0); - s->received_x->maximum(2000.0); - s->received_x->label_format("%g"); - s->received_x->minor_grid_color(fl_gray_ramp(20)); - s->received_x->major_grid_color(fl_gray_ramp(15)); - s->received_x->label_grid_color(fl_gray_ramp(10)); - s->received_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->received_x->minor_grid_style(FL_DOT); - s->received_x->major_step(5); - s->received_x->label_step(1); - s->received_x->axis_align(CA_BOTTOM | CA_LINE); - s->received_x->axis_color(FL_BLACK); - s->received_x->current(); - - s->received_y = new Ca_Y_Axis(60, 240, 50, 90, "Freq"); - s->received_y->align(FL_ALIGN_LEFT); - s->received_y->minimum(0.0); - s->received_y->maximum(50.0); - s->received_y->minor_grid_color(fl_gray_ramp(20)); - s->received_y->major_grid_color(fl_gray_ramp(15)); - s->received_y->label_grid_color(fl_gray_ramp(10)); - s->received_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->received_y->minor_grid_style(FL_DOT); - s->received_y->major_step(5); - s->received_y->label_step(1); - s->received_y->axis_color(FL_BLACK); - s->received_y->current(); - - for (i = 0; i < 2000; i++) - s->received_delays_plot[2*i] = i; - s->received_delays_plot_max = 0.0; - s->min_diff = 2000; - s->max_diff = 0; - - s->received_delays = NULL; - s->highest_seq_no_seen = -1; - - for (i = 0; i < 500; i++) - s->sent_re_plot[2*i] = i; - s->sent_re_plot_min = 99999.0; - s->sent_re_plot_max = 0.0; - s->sent_re = NULL; - - s->c_received->end(); - - s->c_right->end(); - - Fl_Group::current()->resizable(s->c_right); - s->w->end(); - s->w->show(); - - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -void media_monitor_wait_to_end(void) -{ - fd_set rfds; - int res; - struct timeval tv; - - fprintf(stderr, "Processing complete. Press the key to end\n"); - do - { - usleep(100000); - Fl::check(); - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_usec = 100000; - tv.tv_sec = 0; - res = select(1, &rfds, NULL, NULL, &tv); - } - while (res <= 0); -} -/*- End of function --------------------------------------------------------*/ - -void media_monitor_update_display(void) -{ - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); - Fl::check(); -} -/*- End of function --------------------------------------------------------*/ -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/media_monitor.h b/libs/spandsp/tests/media_monitor.h deleted file mode 100644 index 5144913054..0000000000 --- a/libs/spandsp/tests/media_monitor.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * media_monitor.h - Display IP streaming media status, using the FLTK toolkit. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -/*! \page media_monitor_page IP streaming media performance monitoring -\section media_monitor_page_sec_1 What does it do? -This code controls a GUI window, which provides monitoring of the status -of an IP media stream. It shows, graphically: - -\section media_monitor_page_sec_2 How does it work? -This code uses the FLTK cross platform GUI toolkit. It works on X11 and Windows platforms. -In addition to the basic FLTK toolkit, fltk_cartesian is also required. -*/ - -#if !defined(_MEDIA_MONITOR_H_) -#define _MEDIA_MONITOR_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -int start_media_monitor(void); -void media_monitor_rx(int seq_no, double departure_time, double arrival_time); -void media_monitor_wait_to_end(void); -void media_monitor_update_display(void); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/modem_connect_tones_tests.c b/libs/spandsp/tests/modem_connect_tones_tests.c deleted file mode 100644 index 1f99201b55..0000000000 --- a/libs/spandsp/tests/modem_connect_tones_tests.c +++ /dev/null @@ -1,1748 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_connect_tones_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -/*! \page modem_connect_tones_tests_page Modem connect tones tests -\section modem_connect_tones_rx_tests_page_sec_1 What does it do? -These tests... -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define SAMPLES_PER_CHUNK 160 - -#define OUTPUT_FILE_NAME "modem_connect_tones.wav" - -#define MITEL_DIR "../test-data/mitel/" -#define BELLCORE_DIR "../test-data/bellcore/" - -#define LEVEL_MAX -5 -#define LEVEL_MIN -48 -#define LEVEL_MIN_ACCEPT -43 -#define LEVEL_MIN_REJECT -44 - -/* The 1100Hz tone is supposed to be within 38Hz, according to T.30. Allow another 8Hz for FDM, even though - you rarely see that used today. */ -#define CED_FREQ_TOLERANCE (38 + 8) -#define CED_FREQ_BLACKOUT (80) -/* The 2100Hz tone is supposed to be within 15Hz, according to T.30. Allow another 8Hz for FDM, even though - you rarely see that used today. */ -#define CNG_FREQ_TOLERANCE (15 + 8) -#define CNG_FREQ_BLACKOUT (80) -#define AM_FREQ_TOLERANCE (1) -/* The 2225Hz tone is supposed to be within 15Hz. Allow another 8Hz for FDM, even though - you rarely see that used today. */ -#define BELL_ANS_FREQ_TOLERANCE (15 + 8) -#define BELL_ANS_FREQ_BLACKOUT (80) -/* The 1300Hz tone is supposed to be within 15Hz, according to V.25. Allow another 8Hz for FDM, even though - you rarely see that used today. */ -#define CALLING_TONE_FREQ_TOLERANCE (15 + 8) -#define CALLING_TONE_FREQ_BLACKOUT (80) - -const char *bellcore_files[] = -{ - MITEL_DIR "mitel-cm7291-talkoff.wav", - BELLCORE_DIR "tr-tsy-00763-1.wav", - BELLCORE_DIR "tr-tsy-00763-2.wav", - BELLCORE_DIR "tr-tsy-00763-3.wav", - BELLCORE_DIR "tr-tsy-00763-4.wav", - BELLCORE_DIR "tr-tsy-00763-5.wav", - BELLCORE_DIR "tr-tsy-00763-6.wav", - "" -}; - -enum -{ - PERFORM_TEST_1A = (1 << 1), - PERFORM_TEST_1B = (1 << 2), - PERFORM_TEST_1C = (1 << 3), - PERFORM_TEST_1D = (1 << 4), - PERFORM_TEST_1E = (1 << 5), - PERFORM_TEST_1F = (1 << 6), - PERFORM_TEST_1G = (1 << 7), - PERFORM_TEST_2A = (1 << 8), - PERFORM_TEST_2B = (1 << 9), - PERFORM_TEST_2C = (1 << 10), - PERFORM_TEST_2D = (1 << 11), - PERFORM_TEST_2E = (1 << 12), - PERFORM_TEST_2F = (1 << 13), - PERFORM_TEST_2G = (1 << 14), - PERFORM_TEST_3A = (1 << 15), - PERFORM_TEST_3B = (1 << 16), - PERFORM_TEST_3C = (1 << 17), - PERFORM_TEST_3D = (1 << 18), - PERFORM_TEST_3E = (1 << 19), - PERFORM_TEST_3F = (1 << 20), - PERFORM_TEST_3G = (1 << 21), - PERFORM_TEST_4 = (1 << 22), - PERFORM_TEST_5A = (1 << 23), - PERFORM_TEST_5B = (1 << 24), - PERFORM_TEST_6A = (1 << 25), - PERFORM_TEST_6B = (1 << 26), - PERFORM_TEST_7A = (1 << 27), - PERFORM_TEST_7B = (1 << 28), - PERFORM_TEST_8 = (1 << 29) -}; - -int preamble_count = 0; -int preamble_on_at = -1; -int preamble_off_at = -1; -int hits = 0; -int when = 0; - -static int preamble_get_bit(void *user_data) -{ - static int bit_no = 0; - int bit; - - /* Generate a section of HDLC flag octet preamble. Then generate some random - bits, which should not look like preamble. */ - if (++preamble_count < 255) - { - bit = (bit_no < 2) ? 0 : 1; - if (++bit_no >= 8) - bit_no = 0; -#if 0 - /* Inject some bad bits */ - if (rand()%15 == 0) - return bit ^ 1; -#endif - } - else - { - bit = rand() & 1; - } - return bit; -} -/*- End of function --------------------------------------------------------*/ - -static void cng_detected(void *user_data, int tone, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); - if (tone == MODEM_CONNECT_TONES_FAX_CNG) - hits++; -} -/*- End of function --------------------------------------------------------*/ - -static void preamble_detected(void *user_data, int tone, int level, int delay) -{ - printf("%s (%d) declared at bit %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, preamble_count, level); - if (tone == MODEM_CONNECT_TONES_FAX_PREAMBLE) - preamble_on_at = preamble_count; - else - preamble_off_at = preamble_count; - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void ced_detected(void *user_data, int tone, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); - if (tone == MODEM_CONNECT_TONES_FAX_PREAMBLE - || - tone == MODEM_CONNECT_TONES_ANS) - { - hits++; - } -} -/*- End of function --------------------------------------------------------*/ - -static void ans_pr_detected(void *user_data, int tone, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); - if (tone == MODEM_CONNECT_TONES_ANS_PR) - hits++; -} -/*- End of function --------------------------------------------------------*/ - -static void bell_ans_detected(void *user_data, int tone, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); - if (tone == MODEM_CONNECT_TONES_BELL_ANS) - hits++; -} -/*- End of function --------------------------------------------------------*/ - -static void calling_tone_detected(void *user_data, int tone, int level, int delay) -{ - printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); - if (tone == MODEM_CONNECT_TONES_CALLING_TONE) - hits++; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int i; - int j; - int pitch; - int depth; - int level; - int interval; - int cycle; - int16_t amp[8000]; - modem_connect_tones_rx_state_t cng_rx; - modem_connect_tones_rx_state_t ced_rx; - modem_connect_tones_rx_state_t ans_pr_rx; - modem_connect_tones_tx_state_t modem_tone_tx; - modem_connect_tones_rx_state_t calling_tone_rx; - modem_connect_tones_rx_state_t bell_ans_rx; - awgn_state_t chan_noise_source; - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int frames; - int samples; - int hit; - 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; - - test_list = 0; - decode_test_file = NULL; - while ((opt = getopt(argc, argv, "d:")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - for (i = 0; i < argc; i++) - { - if (strcasecmp(argv[i], "1a") == 0) - test_list |= PERFORM_TEST_1A; - else if (strcasecmp(argv[i], "1b") == 0) - test_list |= PERFORM_TEST_1B; - else if (strcasecmp(argv[i], "1c") == 0) - test_list |= PERFORM_TEST_1C; - else if (strcasecmp(argv[i], "1d") == 0) - test_list |= PERFORM_TEST_1D; - else if (strcasecmp(argv[i], "1e") == 0) - test_list |= PERFORM_TEST_1E; - else if (strcasecmp(argv[i], "1f") == 0) - test_list |= PERFORM_TEST_1F; - else if (strcasecmp(argv[i], "1g") == 0) - test_list |= PERFORM_TEST_1G; - else if (strcasecmp(argv[i], "2a") == 0) - test_list |= PERFORM_TEST_2A; - else if (strcasecmp(argv[i], "2b") == 0) - test_list |= PERFORM_TEST_2B; - else if (strcasecmp(argv[i], "2c") == 0) - test_list |= PERFORM_TEST_2C; - else if (strcasecmp(argv[i], "2d") == 0) - test_list |= PERFORM_TEST_2D; - else if (strcasecmp(argv[i], "2e") == 0) - test_list |= PERFORM_TEST_2E; - else if (strcasecmp(argv[i], "2f") == 0) - test_list |= PERFORM_TEST_2F; - else if (strcasecmp(argv[i], "2g") == 0) - test_list |= PERFORM_TEST_2G; - else if (strcasecmp(argv[i], "3a") == 0) - test_list |= PERFORM_TEST_3A; - else if (strcasecmp(argv[i], "3b") == 0) - test_list |= PERFORM_TEST_3B; - else if (strcasecmp(argv[i], "3c") == 0) - test_list |= PERFORM_TEST_3C; - else if (strcasecmp(argv[i], "3d") == 0) - test_list |= PERFORM_TEST_3D; - else if (strcasecmp(argv[i], "3e") == 0) - test_list |= PERFORM_TEST_3E; - else if (strcasecmp(argv[i], "3f") == 0) - test_list |= PERFORM_TEST_3F; - else if (strcasecmp(argv[i], "3g") == 0) - test_list |= PERFORM_TEST_3G; - else if (strcasecmp(argv[i], "4") == 0) - test_list |= PERFORM_TEST_4; - else if (strcasecmp(argv[i], "5a") == 0) - test_list |= PERFORM_TEST_5A; - else if (strcasecmp(argv[i], "5b") == 0) - test_list |= PERFORM_TEST_5B; - else if (strcasecmp(argv[i], "6a") == 0) - test_list |= PERFORM_TEST_6A; - else if (strcasecmp(argv[i], "6b") == 0) - test_list |= PERFORM_TEST_6B; - else if (strcasecmp(argv[i], "7a") == 0) - test_list |= PERFORM_TEST_7A; - else if (strcasecmp(argv[i], "7b") == 0) - test_list |= PERFORM_TEST_7B; - else if (strcasecmp(argv[i], "8") == 0) - test_list |= PERFORM_TEST_8; - else - { - fprintf(stderr, "Unknown test '%s' specified\n", argv[i]); - exit(2); - } - } - if (decode_test_file == NULL && test_list == 0) - test_list = 0xFFFFFFFF; - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - if ((test_list & PERFORM_TEST_1A)) - { - printf("Test 1a: CNG generation to a file\n"); - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_FAX_CNG); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if ((test_list & PERFORM_TEST_1B)) - { - printf("Test 1b: CED/ANS generation to a file\n"); - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_FAX_CED); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if ((test_list & PERFORM_TEST_1C)) - { - printf("Test 1c: ANSam (Modulated ANS) generation to a file\n"); - /* Some with modulation */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANSAM); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if ((test_list & PERFORM_TEST_1D)) - { - printf("Test 1d: ANS/ (EC-disable) generation to a file\n"); - /* Some without modulation, but with phase reversals */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if ((test_list & PERFORM_TEST_1E)) - { - printf("Test 1e: ANSam/ (Modulated EC-disable) generation to a file\n"); - /* Some with modulation and phase reversals */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANSAM_PR); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if ((test_list & PERFORM_TEST_1F)) - { - printf("Test 1f: Bell answer tone generation to a file\n"); - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_BELL_ANS); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if ((test_list & PERFORM_TEST_1G)) - { - printf("Test 1g: Calling tone generation to a file\n"); - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_CALLING_TONE); - for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - outframes = sf_writef_short(outhandle, amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - } - /*endif*/ - - if (sf_close_telephony(outhandle)) - { - printf(" Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2A)) - { - 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; - for (pitch = 1100 - 500; pitch <= 1100 + 500; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&cng_rx, tone_type, NULL, NULL); - level2 = 0; - max_level2 = 0; - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - { - amp[j] += awgn(&chan_noise_source); - level2 += ((abs(amp[j]) - level2) >> 5); - if (level2 > max_level2) - max_level2 = level2; - } - /*endfor*/ - modem_connect_tones_rx(&cng_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&cng_rx); - if (pitch < (1100 - CED_FREQ_BLACKOUT) || pitch > (1100 + CED_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (pitch > (1100 - CED_FREQ_TOLERANCE) && pitch < (1100 + CED_FREQ_TOLERANCE)) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, cng_rx.channel_level, cng_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2B)) - { - printf("Test 2b: CED/ANS detection with frequency\n"); - awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = false; - false_miss = false; - for (pitch = 2100 - 500; pitch < 2100 + 500; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ced_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ced_rx); - if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - 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; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ced_rx.channel_level, ced_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2C)) - { - 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; - for (pitch = 2100 - 100; pitch <= 2100 + 100; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2D)) - { - 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; - for (pitch = 2100 - 100; pitch <= 2100 + 100; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2E)) - { - 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; - for (pitch = 2100 - 100; pitch <= 2100 + 100; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2F)) - { - 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; - for (pitch = 2225 - 500; pitch <= 2225 + 500; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&bell_ans_rx, tone_type, NULL, NULL); - level2 = 0; - max_level2 = 0; - for (i = 0; i < 8000; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - { - amp[j] += awgn(&chan_noise_source); - level2 += ((abs(amp[j]) - level2) >> 5); - if (level2 > max_level2) - max_level2 = level2; - } - /*endfor*/ - modem_connect_tones_rx(&bell_ans_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&bell_ans_rx); - if (pitch < (2225 - BELL_ANS_FREQ_BLACKOUT) || pitch > (2225 + BELL_ANS_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - 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; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, bell_ans_rx.channel_level, bell_ans_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_2G)) - { - 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; - for (pitch = 1300 - 500; pitch <= 1300 + 500; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&calling_tone_rx, tone_type, NULL, NULL); - level2 = 0; - max_level2 = 0; - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - { - amp[j] += awgn(&chan_noise_source); - level2 += ((abs(amp[j]) - level2) >> 5); - if (level2 > max_level2) - max_level2 = level2; - } - /*endfor*/ - modem_connect_tones_rx(&calling_tone_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&calling_tone_rx); - if (pitch < (1300 - CALLING_TONE_FREQ_BLACKOUT) || pitch > (1300 + CALLING_TONE_FREQ_BLACKOUT)) - { - if (hit != MODEM_CONNECT_TONES_NONE) - 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; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, calling_tone_rx.channel_level, calling_tone_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3A)) - { - 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; - for (pitch = 1100 - CED_FREQ_TOLERANCE; pitch <= 1100 + CED_FREQ_TOLERANCE; pitch += 2*CED_FREQ_TOLERANCE) - { - for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&cng_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&cng_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&cng_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, cng_rx.channel_level, cng_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3B)) - { - 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; - for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) - { - for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ced_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ced_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, ced_rx.channel_level, ced_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3C)) - { - 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; - for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) - { - //for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) - for (level = -26; level >= -26; level--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_tone_tx.mod_level = modem_tone_tx.level*20/100; - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3D)) - { - 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; - for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) - { - for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3E)) - { - 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; - for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) - { - for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_tone_tx.mod_level = modem_tone_tx.level*20/100; - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3F)) - { - 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; - 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--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&calling_tone_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&calling_tone_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&calling_tone_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, calling_tone_rx.channel_level, calling_tone_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_3G)) - { - 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; - 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--) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); - modem_tone_tx.level = dds_scaling_dbm0(level); - modem_connect_tones_rx_init(&calling_tone_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&calling_tone_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&calling_tone_rx); - if (level < LEVEL_MIN_REJECT) - { - if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = true; - /*endif*/ - } - else if (level > LEVEL_MIN_ACCEPT) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, level, calling_tone_rx.channel_level, calling_tone_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_4)) - { - printf("Test 4: CED detection, when stimulated with V.21 preamble\n"); - 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. */ - fsk_tx_init(&preamble_tx, &preset_fsk_specs[FSK_V21CH2], preamble_get_bit, NULL); - modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, preamble_detected, NULL); - for (i = 0; i < 2*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = fsk_tx(&preamble_tx, amp, SAMPLES_PER_CHUNK); - modem_connect_tones_rx(&ced_rx, amp, samples); - } - /*endfor*/ - for (i = 0; i < SAMPLE_RATE/10; i += SAMPLES_PER_CHUNK) - { - memset(amp, 0, sizeof(int16_t)*SAMPLES_PER_CHUNK); - modem_connect_tones_rx(&ced_rx, amp, SAMPLES_PER_CHUNK); - } - /*endfor*/ - if (preamble_on_at < 40 || preamble_on_at > 50 - || - preamble_off_at < 580 || preamble_off_at > 620) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_5A)) - { - 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; - for (interval = 400; interval < 800; interval++) - { - printf("Reversal interval = %d\n", interval); - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, ans_pr_detected, NULL); - hits = 0; - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - when = i; - samples = SAMPLES_PER_CHUNK; - for (j = 0; j < samples; j++) - { - if (--modem_tone_tx.hop_timer <= 0) - { - modem_tone_tx.hop_timer = ms_to_samples(interval); - modem_tone_tx.tone_phase += 0x80000000; - } - /*endif*/ - amp[j] = dds_mod(&modem_tone_tx.tone_phase, modem_tone_tx.tone_phase_rate, modem_tone_tx.level, 0); - } - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - if (interval < (450 - 25) || interval > (450 + 25)) - { - if (hits != 0) - false_hit = true; - /*endif*/ - } - else if (interval > (450 - 25) && interval < (450 + 25)) - { - if (hits == 0) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hits) - printf("Detected at %5dHz %4ddB %dms %12" PRId32 " %12" PRId32 " %d\n", 2100, -11, interval, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hits); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_5B)) - { - 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; - interval = 450; - printf("Reversal interval = %d\n", interval); - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, ans_pr_detected, NULL); - cycle = 0; - hits = 0; - for (i = 0; i < 60*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - when = i; - samples = SAMPLES_PER_CHUNK; - for (j = 0; j < samples; j++) - { - if (--modem_tone_tx.hop_timer <= 0) - { - if (++cycle == 10) - interval = 1000; - if (cycle == 20) - interval = 450; - modem_tone_tx.hop_timer = ms_to_samples(interval); - modem_tone_tx.tone_phase += 0x80000000; - } - amp[j] = dds_mod(&modem_tone_tx.tone_phase, modem_tone_tx.tone_phase_rate, modem_tone_tx.level, 0); - } - /*endfor*/ - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - /* TODO: Add test result detection logic. */ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_6A)) - { - 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; - for (pitch = 5; pitch < 25; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.mod_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (pitch < (15 - 10) || pitch > (15 + 10)) - { - if (hit == tone_type) - false_hit = true; - /*endif*/ - } - else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_6B)) - { - 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; - for (pitch = 5; pitch < 25; pitch++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.mod_phase_rate = dds_phase_rate(pitch); - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (pitch < (15 - 10) || pitch > (15 + 10)) - { - if (hit == tone_type) - false_hit = true; - /*endif*/ - } - else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_7A)) - { - printf("Test 7a: ANSam detection with AM depth\n"); - tone_type = MODEM_CONNECT_TONES_ANSAM; - pitch = 2100; - awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = false; - false_miss = false; - for (depth = 0; depth < 40; depth++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.mod_level = modem_tone_tx.level*depth/100; - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (depth < 10) - { - if (hit == tone_type) - false_hit = true; - /*endif*/ - } - else if (depth > 15) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_7B)) - { - printf("Test 7b: ANSam/ (Modulated EC-disable) detection with AM depth\n"); - tone_type = MODEM_CONNECT_TONES_ANSAM_PR; - pitch = 2100; - awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = false; - false_miss = false; - for (depth = 0; depth < 40; depth++) - { - /* Use the transmitter to test the receiver */ - modem_connect_tones_tx_init(&modem_tone_tx, tone_type); - /* Fudge things for the test */ - modem_tone_tx.mod_level = modem_tone_tx.level*depth/100; - modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); - for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) - { - samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); - for (j = 0; j < samples; j++) - amp[j] += awgn(&chan_noise_source); - /*endfor*/ - modem_connect_tones_rx(&ans_pr_rx, amp, samples); - } - /*endfor*/ - hit = modem_connect_tones_rx_get(&ans_pr_rx); - if (depth < 10) - { - if (hit == tone_type) - false_hit = true; - /*endif*/ - } - else if (depth > 15) - { - if (hit != tone_type) - false_miss = true; - /*endif*/ - } - /*endif*/ - if (hit != MODEM_CONNECT_TONES_NONE) - printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %s (%d)\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, modem_connect_tone_to_str(hit), hit); - /*endif*/ - } - /*endfor*/ - if (false_hit || false_miss) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if ((test_list & PERFORM_TEST_8)) - { - /* Talk-off test */ - /* Here we use the BellCore and Mitel talk off test tapes, intended for DTMF - detector testing. Presumably they should also have value here, but I am not - sure. If those voice snippets were chosen to be tough on DTMF detectors, they - might go easy on detectors looking for different pitches. However, the - Mitel DTMF test tape is known (the hard way) to exercise 2280Hz tone - detectors quite well. */ - printf("Test 8: Talk-off test\n"); - modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); - modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); - modem_connect_tones_rx_init(&bell_ans_rx, MODEM_CONNECT_TONES_BELL_ANS, NULL, NULL); - modem_connect_tones_rx_init(&calling_tone_rx, MODEM_CONNECT_TONES_CALLING_TONE, NULL, NULL); - for (j = 0; bellcore_files[j][0]; j++) - { - if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) - { - fprintf(stderr, " Cannot open speech file '%s'\n", bellcore_files[j]); - exit (2); - } - /*endif*/ - - when = 0; - hits = 0; - while ((frames = sf_readf_short(inhandle, amp, 8000))) - { - when++; - modem_connect_tones_rx(&cng_rx, amp, frames); - modem_connect_tones_rx(&ced_rx, amp, frames); - modem_connect_tones_rx(&ans_pr_rx, amp, frames); - modem_connect_tones_rx(&bell_ans_rx, amp, frames); - modem_connect_tones_rx(&calling_tone_rx, amp, frames); - if (modem_connect_tones_rx_get(&cng_rx) != MODEM_CONNECT_TONES_NONE) - { - /* This is not a true measure of hits, as there might be more - than one in a block of data. However, since the only good - result is no hits, this approximation is OK. */ - printf("Hit CNG at %ds\n", when); - hits++; - modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); - } - /*endif*/ - if (modem_connect_tones_rx_get(&ced_rx) != MODEM_CONNECT_TONES_NONE) - { - printf("Hit CED at %ds\n", when); - hits++; - modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); - } - /*endif*/ - if (modem_connect_tones_rx_get(&ans_pr_rx) != MODEM_CONNECT_TONES_NONE) - { - printf("Hit EC disable at %ds\n", when); - hits++; - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); - } - /*endif*/ - if (modem_connect_tones_rx_get(&bell_ans_rx) != MODEM_CONNECT_TONES_NONE) - { - printf("Hit calling tone at %ds\n", when); - hits++; - modem_connect_tones_rx_init(&bell_ans_rx, MODEM_CONNECT_TONES_BELL_ANS, NULL, NULL); - } - /*endif*/ - if (modem_connect_tones_rx_get(&calling_tone_rx) != MODEM_CONNECT_TONES_NONE) - { - printf("Hit calling tone at %ds\n", when); - hits++; - modem_connect_tones_rx_init(&calling_tone_rx, MODEM_CONNECT_TONES_CALLING_TONE, NULL, NULL); - } - /*endif*/ - } - /*endwhile*/ - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", bellcore_files[j]); - exit(2); - } - /*endif*/ - printf(" File %d gave %d false hits.\n", j + 1, hits); - } - /*endfor*/ - if (hits > 0) - { - printf("Test failed.\n"); - exit(2); - } - /*endif*/ - printf("Test passed.\n"); - } - /*endif*/ - - if (decode_test_file) - { - printf("Decode file '%s'\n", decode_test_file); - modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, cng_detected, NULL); - modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, ced_detected, NULL); - modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, ans_pr_detected, NULL); - modem_connect_tones_rx_init(&bell_ans_rx, MODEM_CONNECT_TONES_BELL_ANS, bell_ans_detected, NULL); - modem_connect_tones_rx_init(&calling_tone_rx, MODEM_CONNECT_TONES_CALLING_TONE, calling_tone_detected, NULL); - hits = 0; - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open speech file '%s'\n", decode_test_file); - exit (2); - } - /*endif*/ - - when = 0; - hits = 0; - while ((frames = sf_readf_short(inhandle, amp, 8000))) - { - when++; - modem_connect_tones_rx(&cng_rx, amp, frames); - modem_connect_tones_rx(&ced_rx, amp, frames); - modem_connect_tones_rx(&ans_pr_rx, amp, frames); - modem_connect_tones_rx(&bell_ans_rx, amp, frames); - modem_connect_tones_rx(&calling_tone_rx, amp, frames); - } - /*endwhile*/ - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", decode_test_file); - exit(2); - } - /*endif*/ - printf(" File gave %d hits.\n", hits); - } - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/modem_echo_tests.c b/libs/spandsp/tests/modem_echo_tests.c deleted file mode 100644 index 2cc50f4294..0000000000 --- a/libs/spandsp/tests/modem_echo_tests.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_echo_tests.c - * - * 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 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. - */ - -/*! \page modem_echo_can_tests_page Line echo cancellation for modems tests -\section modem_echo_can_tests_page_sec_1 What does it do? -Currently the echo cancellation tests only provide simple exercising of the -cancellor in the way it might be used for line echo cancellation. The test code -is in echotests.c. - -The goal is to test the echo cancellor again the G.16X specs. Clearly, that also -means the goal for the cancellor itself is to comply with those specs. Right -now, the only aspect of these tests implemented is the line impulse response -models in g168tests.c. - -\section modem_echo_can_tests_page_sec_2 How does it work? -The current test consists of feeding an audio file of real speech to the echo -cancellor as the transmit signal. A very simple model of a telephone line is -used to simulate a simple echo from the transmit signal. A second audio file of -real speech is also used to simulate a signal received form the far end of the -line. This is gated so it is only placed for one second every 10 seconds, -simulating the double talk condition. The resulting echo cancelled signal can -either be store in a file for further analysis, or played back as the data is -processed. - -A number of modified versions of this test have been performed. The signal level -of the two speech sources has been varied. Several simple models of the -telephone line have been used. Although the current cancellor design has known -limitations, it seems stable for all these test conditions. No instability has -been observed in the current version due to arithmetic overflow when the speech -is very loud (with earlier versions, well, ....:) ). The lack of saturating -arithmetic in general purpose CPUs is a huge disadvantage here, as software -saturation logic would cause a major slow down. Floating point would be good, -but is not usable in the Linux kernel. Anyway, the bottom line seems to be the -current design is genuinely useful, if imperfect. - -\section modem_echo_can_tests_page_sec_2 How do I use it? - -Build the tests with the command "./build". Currently there is no proper make -setup, or way to build individual tests. "./build" will built all the tests -which currently exist for the DSP functions. The echo cancellation test assumes -there are two audio files containing mono, 16 bit signed PCM speech data, sampled -at 8kHz. These should be called local_sound.wav and far_sound.wav. A third wave -file will be produced. This very crudely starts with the first 256 bytes from -the local_sound.wav file, followed by the results of the echo cancellation. The -resulting audio is also played to the /dev/dsp device. A printf near the end of -echo_tests.c is commented out with a \#if. If this is enabled, detailed -information about the results of the echo cancellation will be written to -stdout. By saving this into a file, Grace (recommended), GnuPlot, or some other -plotting package may be used to graphically display the functioning of the -cancellor. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#if defined(HAVE_MATH_H) -#define GEN_CONST -#endif - -#include "spandsp.h" -#include "spandsp/g168models.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "echo_monitor.h" -#endif - -#if !defined(NULL) -#define NULL (void *) 0 -#endif - -typedef struct -{ - const char *name; - int max; - int cur; - SNDFILE *handle; - int16_t signal[8000]; -} signal_source_t; - -signal_source_t local_css; - -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; - -static const int16_t tone_1khz[] = {10362, 7327, 0, -7327, -10362, -7327, 0, 7327}; - -static inline void put_residue(int16_t tx, int16_t residue) -{ - int outframes; - - residue_sound[residue_cur++] = tx; - residue_sound[residue_cur++] = residue; - if (residue_cur >= 8000) - { - residue_cur >>= 1; - outframes = sf_writef_short(resulthandle, residue_sound, residue_cur); - if (outframes != residue_cur) - { - fprintf(stderr, " Error writing residue sound\n"); - exit(2); - } - residue_cur = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_load(signal_source_t *sig, const char *name) -{ - sig->name = name; - if ((sig->handle = sf_open_telephony_read(sig->name, 1)) == NULL) - { - fprintf(stderr, " Cannot open sound file '%s'\n", sig->name); - exit(2); - } - sig->max = sf_readf_short(sig->handle, sig->signal, 8000); - if (sig->max < 0) - { - fprintf(stderr, " Error reading sound file '%s'\n", sig->name); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_free(signal_source_t *sig) -{ - if (sf_close_telephony(sig->handle)) - { - fprintf(stderr, " Cannot close sound file '%s'\n", sig->name); - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void signal_restart(signal_source_t *sig) -{ - sig->cur = 0; -} -/*- End of function --------------------------------------------------------*/ - -static int16_t signal_amp(signal_source_t *sig) -{ - int16_t tx; - - tx = sig->signal[sig->cur++]; - if (sig->cur >= sig->max) - sig->cur = 0; - return tx; -} -/*- End of function --------------------------------------------------------*/ - -static inline int16_t codec_munger(int16_t amp) -{ - if (do_codec_munge) - return alaw_to_linear(linear_to_alaw(amp)); - return amp; -} -/*- End of function --------------------------------------------------------*/ - -static void channel_model_create(int model) -{ - static const int32_t *line_models[] = - { - line_model_d2_coeffs, - line_model_d3_coeffs, - line_model_d4_coeffs, - line_model_d5_coeffs, - line_model_d6_coeffs, - line_model_d7_coeffs, - line_model_d8_coeffs, - line_model_d9_coeffs - }; - - static int line_model_sizes[] = - { - sizeof(line_model_d2_coeffs)/sizeof(int32_t), - sizeof(line_model_d3_coeffs)/sizeof(int32_t), - sizeof(line_model_d4_coeffs)/sizeof(int32_t), - sizeof(line_model_d5_coeffs)/sizeof(int32_t), - sizeof(line_model_d6_coeffs)/sizeof(int32_t), - sizeof(line_model_d7_coeffs)/sizeof(int32_t), - sizeof(line_model_d8_coeffs)/sizeof(int32_t), - sizeof(line_model_d9_coeffs)/sizeof(int32_t) - }; - - fir32_create(&line_model, line_models[model], line_model_sizes[model]); -} -/*- End of function --------------------------------------------------------*/ - -static int16_t channel_model(int16_t local, int16_t far) -{ - int16_t echo; - int16_t rx; - - /* Channel modelling is merely simulating the effects of A-law distortion - and using one of the echo models from G.168 */ - - /* The local tx signal will have gone through an A-law munging before - it reached the line's analogue area where the echo occurs. */ - echo = fir32(&line_model, codec_munger(local/8)); - /* The far end signal will have been through an A-law munging, although - this should not affect things. */ - rx = echo + codec_munger(far); - /* This mixed echo and far end signal will have been through an A-law munging when it came back into - the digital network. */ - rx = codec_munger(rx); - return rx; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - modem_echo_can_state_t *ctx; - //awgn_state_t local_noise_source; - awgn_state_t far_noise_source; - int i; - int clean; - int16_t rx; - int16_t tx; - int line_model_no; - time_t now; - power_meter_t power_before; - power_meter_t power_after; - float unadapted_output_power; - float unadapted_echo_power; - float adapted_output_power; - float adapted_echo_power; -#if defined(ENABLE_GUI) - int16_t amp[2]; -#endif - - line_model_no = 0; - use_gui = false; - for (i = 1; i < argc; i++) - { - if (strcmp(argv[i], "-g") == 0) - { - use_gui = true; - continue; - } - line_model_no = atoi(argv[1]); - } - time(&now); - ctx = modem_echo_can_init(256); - awgn_init_dbm0(&far_noise_source, 7162534, -50.0f); - - signal_load(&local_css, "sound_c1_8k.wav"); - - if ((resulthandle = sf_open_telephony_write("modem_echo.wav", 2)) == NULL) - { - fprintf(stderr, " Failed to open result file\n"); - exit(2); - } - -#if defined(ENABLE_GUI) - if (use_gui) - start_echo_can_monitor(256); -#endif - - channel_model_create(line_model_no); -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_line_model_update(line_model.coeffs, line_model.taps); -#endif - - modem_echo_can_flush(ctx); - - power_meter_init(&power_before, 5); - power_meter_init(&power_after, 5); - - /* Measure the echo power before adaption */ - modem_echo_can_adaption_mode(ctx, false); - for (i = 0; i < 8000*5; i++) - { - tx = tone_1khz[i & 7]; - rx = channel_model(tx, 0); - clean = modem_echo_can_update(ctx, tx, rx); - power_meter_update(&power_before, rx); - power_meter_update(&power_after, clean); - } - unadapted_output_power = power_meter_current_dbm0(&power_before); - unadapted_echo_power = power_meter_current_dbm0(&power_after); - printf("Pre-adaption: output power %10.5fdBm0, echo power %10.5fdBm0\n", unadapted_output_power, unadapted_echo_power); - - /* Converge the canceller */ - signal_restart(&local_css); - modem_echo_can_adaption_mode(ctx, true); - for (i = 0; i < 800*2; i++) - { - clean = modem_echo_can_update(ctx, 0, 0); - put_residue(0, clean); - } - - for (i = 0; i < 8000*50; i++) - { - tx = signal_amp(&local_css); - rx = channel_model(tx, 0); - clean = modem_echo_can_update(ctx, tx, rx); - power_meter_update(&power_before, rx); - power_meter_update(&power_after, clean); -#if 0 - if (i%800 == 0) - printf("Powers %10.5fdBm0 %10.5fdBm0\n", power_meter_current_dbm0(&power_before), power_meter_current_dbm0(&power_after)); -#endif - put_residue(tx, clean); -#if defined(ENABLE_GUI) - if (use_gui) - { - echo_can_monitor_can_update(ctx->fir_taps16, 256); - amp[0] = tx; - echo_can_monitor_line_spectrum_update(amp, 1); - } -#endif - } - - /* Now lets see how well adapted we are */ - modem_echo_can_adaption_mode(ctx, false); - for (i = 0; i < 8000*5; i++) - { - tx = tone_1khz[i & 7]; - rx = channel_model(tx, 0); - clean = modem_echo_can_update(ctx, tx, rx); - power_meter_update(&power_before, rx); - power_meter_update(&power_after, clean); - } - adapted_output_power = power_meter_current_dbm0(&power_before); - adapted_echo_power = power_meter_current_dbm0(&power_after); - printf("Post-adaption: output power %10.5fdBm0, echo power %10.5fdBm0\n", adapted_output_power, adapted_echo_power); - - if (fabsf(adapted_output_power - unadapted_output_power) > 0.1f - || - adapted_echo_power > unadapted_echo_power - 30.0f) - { - printf("Tests failed.\n"); - exit(2); - } - - modem_echo_can_free(ctx); - signal_free(&local_css); - - if (sf_close_telephony(resulthandle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", "result_sound.wav"); - exit(2); - } - -#if defined(ENABLE_GUI) - if (use_gui) - echo_can_monitor_wait_to_end(); -#endif - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/modem_monitor.cpp b/libs/spandsp/tests/modem_monitor.cpp deleted file mode 100644 index 5ec46b63e0..0000000000 --- a/libs/spandsp/tests/modem_monitor.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * modem_monitor.cpp - Display QAM constellations, using the FLTK toolkit. - * - * 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 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) - -#define __STDC_LIMIT_MACROS - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -#define SYMBOL_TRACKER_POINTS 12000 -#define CARRIER_TRACKER_POINTS 12000 - -struct qam_monitor_s -{ - float constel_scaling; - - Fl_Double_Window *w; - Fl_Group *c_const; - Fl_Group *c_right; - Fl_Group *c_eq; - Fl_Group *c_symbol_track; - - /* Constellation stuff */ - Ca_Canvas *canvas_const; - Ca_X_Axis *sig_i; - Ca_Y_Axis *sig_q; - - Ca_Point *constel_point[100000]; - int constel_window; - int next_constel_point; - int skip; - - /* Equalizer stuff */ - Ca_Canvas *canvas_eq; - - Ca_X_Axis *eq_x; - Ca_Y_Axis *eq_y; - - Ca_Line *eq_re; - Ca_Line *eq_im; - - double eq_re_plot[200]; - double eq_im_plot[200]; - - /* Carrier and symbol tracking stuff */ - Ca_Canvas *canvas_track; - - Ca_X_Axis *track_x; - Ca_Y_Axis *symbol_track_y; - Ca_Y_Axis *carrier_y; - - Ca_Line *symbol_track; - Ca_Line *carrier; - - float symbol_tracker[SYMBOL_TRACKER_POINTS]; - double symbol_track_plot[SYMBOL_TRACKER_POINTS*2]; - int symbol_track_points; - int symbol_track_ptr; - int symbol_track_window; - - float carrier_tracker[CARRIER_TRACKER_POINTS]; - double carrier_plot[CARRIER_TRACKER_POINTS*2]; - int carrier_points; - int carrier_ptr; - int carrier_window; - - /* Audio meter stuff */ - Fl_Audio_Meter *audio_meter; - Fl_Output *audio_level; - int32_t power_reading; -}; - -#include "modem_monitor.h" - -int qam_monitor_clear_constel(qam_monitor_t *s) -{ - int i; - - s->canvas_const->current(s->canvas_const); - for (i = 0; i < s->constel_window; i++) - { - if (s->constel_point[i]) - { - delete s->constel_point[i]; - s->constel_point[i] = NULL; - } - } - s->next_constel_point = 0; - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int qam_monitor_update_constel(qam_monitor_t *s, const complexf_t *pt) -{ - int i; - - s->canvas_const->current(s->canvas_const); - if (s->constel_point[s->next_constel_point]) - delete s->constel_point[s->next_constel_point]; - s->constel_point[s->next_constel_point++] = new Ca_Point(pt->re, pt->im, FL_BLACK); - if (s->next_constel_point >= s->constel_window) - s->next_constel_point = 0; - if (++s->skip >= 100) - { - s->skip = 0; - Fl::check(); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int qam_monitor_update_equalizer(qam_monitor_t *s, const complexf_t *coeffs, int len) -{ - int i; - float min; - float max; - - /* Protect against screwy values */ - for (i = 0; i < len; i++) - { - if (isnan(coeffs[i].re) || isinf(coeffs[i].re)) - break; - if (isnan(coeffs[i].im) || isinf(coeffs[i].im)) - break; - if (coeffs[i].re < -20.0f || coeffs[i].re > 20.0f) - break; - if (coeffs[i].im < -20.0f || coeffs[i].im > 20.0f) - break; - } - if (i != len) - return -1; - - if (s->eq_re) - delete s->eq_re; - if (s->eq_im) - delete s->eq_im; - - s->canvas_eq->current(s->canvas_eq); - i = 0; - min = coeffs[i].re; - if (min > coeffs[i].im) - min = coeffs[i].im; - max = coeffs[i].re; - if (max < coeffs[i].im) - max = coeffs[i].im; - for (i = 0; i < len; i++) - { - s->eq_re_plot[2*i] = (i - len/2)/2.0; - s->eq_re_plot[2*i + 1] = coeffs[i].re*s->constel_scaling; - if (min > coeffs[i].re) - min = coeffs[i].re; - if (max < coeffs[i].re) - max = coeffs[i].re; - - s->eq_im_plot[2*i] = (i - len/2)/2.0; - s->eq_im_plot[2*i + 1] = coeffs[i].im*s->constel_scaling; - if (min > coeffs[i].im) - min = coeffs[i].im; - if (max < coeffs[i].im) - max = coeffs[i].im; - } - - s->eq_x->minimum(-len/4.0); - s->eq_x->maximum(len/4.0); - s->eq_y->maximum((max == min) ? max + 0.2 : max); - s->eq_y->minimum(min); - s->eq_re = new Ca_Line(len, s->eq_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - s->eq_im = new Ca_Line(len, s->eq_im_plot, 0, 0, FL_RED, CA_NO_POINT); - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int qam_monitor_update_int_equalizer(qam_monitor_t *s, const complexi16_t *coeffs, int len) -{ - int i; - float min; - float max; - - if (s->eq_re) - delete s->eq_re; - if (s->eq_im) - delete s->eq_im; - - s->canvas_eq->current(s->canvas_eq); - i = 0; - min = coeffs[i].re; - if (min > coeffs[i].im) - min = coeffs[i].im; - max = coeffs[i].re; - if (max < coeffs[i].im) - max = coeffs[i].im; - for (i = 0; i < len; i++) - { - if (min > coeffs[i].re) - min = coeffs[i].re; - if (max < coeffs[i].re) - max = coeffs[i].re; - s->eq_re_plot[2*i] = (i - len/2)/2.0f; - s->eq_re_plot[2*i + 1] = coeffs[i].re*s->constel_scaling; - - if (min > coeffs[i].im) - min = coeffs[i].im; - if (max < coeffs[i].im) - max = coeffs[i].im; - s->eq_im_plot[2*i] = (i - len/2)/2.0f; - s->eq_im_plot[2*i + 1] = coeffs[i].im*s->constel_scaling; - } - min *= s->constel_scaling; - max *= s->constel_scaling; - - s->eq_x->minimum(-len/4.0); - s->eq_x->maximum(len/4.0); - s->eq_y->maximum((max == min) ? max + 0.2 : max); - s->eq_y->minimum(min); - s->eq_re = new Ca_Line(len, s->eq_re_plot, 0, 0, FL_BLUE, CA_NO_POINT); - s->eq_im = new Ca_Line(len, s->eq_im_plot, 0, 0, FL_RED, CA_NO_POINT); - Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int qam_monitor_update_symbol_tracking(qam_monitor_t *s, float total_correction) -{ - int i; - int j; - float min; - float max; - - s->symbol_tracker[s->symbol_track_ptr++] = total_correction; - if (s->symbol_track_points < SYMBOL_TRACKER_POINTS) - s->symbol_track_points++; - if (s->symbol_track_ptr >= SYMBOL_TRACKER_POINTS) - s->symbol_track_ptr = 0; - - s->canvas_track->current(s->canvas_track); - if (s->symbol_track) - delete s->symbol_track; - s->track_x->current(); - s->symbol_track_y->current(); - - min = - max = s->symbol_tracker[0]; - for (i = s->symbol_track_ptr, j = 0; i < s->symbol_track_points; i++, j++) - { - if (min > s->symbol_tracker[i]) - min = s->symbol_tracker[i]; - if (max < s->symbol_tracker[i]) - max = s->symbol_tracker[i]; - s->symbol_track_plot[2*j] = j; - s->symbol_track_plot[2*j + 1] = s->symbol_tracker[i]; - } - for (i = 0; i < s->symbol_track_ptr; i++, j++) - { - if (min > s->symbol_tracker[i]) - min = s->symbol_tracker[i]; - if (max < s->symbol_tracker[i]) - max = s->symbol_tracker[i]; - s->symbol_track_plot[2*j] = j; - s->symbol_track_plot[2*j + 1] = s->symbol_tracker[i]; - } - s->symbol_track_y->maximum((fabs(max - min) < 0.05) ? max + 0.05 : max); - s->symbol_track_y->minimum(min); - - s->symbol_track = new Ca_Line(s->symbol_track_points, s->symbol_track_plot, 0, 0, FL_RED, CA_NO_POINT); - //Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int qam_monitor_update_audio_level(qam_monitor_t *s, const int16_t amp[], int len) -{ - int i; - char buf[11]; - double val; - - for (i = 0; i < len; i++) - { - s->audio_meter->sample(amp[i]/32768.0); - s->power_reading += ((amp[i]*amp[i] - s->power_reading) >> 10); - } - val = 10.0*log10((double) s->power_reading/(32767.0*32767.0) + 1.0e-10) + 3.14 + 3.02; - - snprintf(buf, sizeof(buf), "%5.1fdBm0", val); - s->audio_level->value(buf); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int qam_monitor_update_carrier_tracking(qam_monitor_t *s, float carrier_freq) -{ - int i; - int j; - float min; - float max; - - s->carrier_tracker[s->carrier_ptr++] = carrier_freq; - if (s->carrier_points < CARRIER_TRACKER_POINTS) - s->carrier_points++; - if (s->carrier_ptr >= CARRIER_TRACKER_POINTS) - s->carrier_ptr = 0; - - s->canvas_track->current(s->canvas_track); - if (s->carrier) - delete s->carrier; - s->track_x->current(); - s->carrier_y->current(); - - min = - max = s->carrier_tracker[0]; - for (i = s->carrier_ptr, j = 0; i < s->carrier_points; i++, j++) - { - s->carrier_plot[2*j] = j; - s->carrier_plot[2*j + 1] = s->carrier_tracker[i]; - if (min > s->carrier_tracker[i]) - min = s->carrier_tracker[i]; - if (max < s->carrier_tracker[i]) - max = s->carrier_tracker[i]; - } - for (i = 0; i < s->carrier_ptr; i++, j++) - { - s->carrier_plot[2*j] = j; - s->carrier_plot[2*j + 1] = s->carrier_tracker[i]; - if (min > s->carrier_tracker[i]) - min = s->carrier_tracker[i]; - if (max < s->carrier_tracker[i]) - max = s->carrier_tracker[i]; - } - - s->carrier_y->maximum((fabs(max - min) < 0.05) ? max + 0.05 : max); - s->carrier_y->minimum(min); - - s->carrier = new Ca_Line(s->carrier_points, s->carrier_plot, 0, 0, FL_BLUE, CA_NO_POINT); - //Fl::check(); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -qam_monitor_t *qam_monitor_init(float constel_width, float constel_scaling, const char *tag) -{ - char buf[132 + 1]; - float x; - float y; - qam_monitor_t *s; - - if ((s = (qam_monitor_t *) malloc(sizeof(*s))) == NULL) - return NULL; - - s->w = new Fl_Double_Window(905, 400, (tag) ? tag : "QAM monitor"); - - s->constel_scaling = 1.0/constel_scaling; - - s->c_const = new Fl_Group(0, 0, 380, 400); - s->c_const->box(FL_DOWN_BOX); - s->c_const->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - - s->canvas_const = new Ca_Canvas(60, 30, 300, 300, "Constellation"); - s->canvas_const->box(FL_PLASTIC_DOWN_BOX); - s->canvas_const->color(7); - s->canvas_const->align(FL_ALIGN_TOP); - s->canvas_const->border(15); - - s->sig_i = new Ca_X_Axis(65, 330, 290, 30, "I"); - s->sig_i->align(FL_ALIGN_BOTTOM); - s->sig_i->minimum(-constel_width); - s->sig_i->maximum(constel_width); - s->sig_i->label_format("%g"); - s->sig_i->minor_grid_color(fl_gray_ramp(20)); - s->sig_i->major_grid_color(fl_gray_ramp(15)); - s->sig_i->label_grid_color(fl_gray_ramp(10)); - s->sig_i->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->sig_i->minor_grid_style(FL_DOT); - s->sig_i->major_step(5); - s->sig_i->label_step(1); - s->sig_i->axis_color(FL_BLACK); - s->sig_i->axis_align(CA_BOTTOM | CA_LINE); - - s->sig_q = new Ca_Y_Axis(20, 35, 40, 290, "Q"); - s->sig_q->align(FL_ALIGN_LEFT); - s->sig_q->minimum(-constel_width); - s->sig_q->maximum(constel_width); - s->sig_q->minor_grid_color(fl_gray_ramp(20)); - s->sig_q->major_grid_color(fl_gray_ramp(15)); - s->sig_q->label_grid_color(fl_gray_ramp(10)); - //s->sig_q->grid_visible(CA_MINOR_TICK | CA_MAJOR_TICK | CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->sig_q->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->sig_q->minor_grid_style(FL_DOT); - s->sig_q->major_step(5); - s->sig_q->label_step(1); - s->sig_q->axis_color(FL_BLACK); - - s->sig_q->current(); - - s->c_const->end(); - - s->c_right = new Fl_Group(440, 0, 465, 405); - - s->c_eq = new Fl_Group(380, 0, 265, 200); - s->c_eq->box(FL_DOWN_BOX); - s->c_eq->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_eq->current(); - s->canvas_eq = new Ca_Canvas(460, 35, 150, 100, "Equalizer"); - s->canvas_eq->box(FL_PLASTIC_DOWN_BOX); - s->canvas_eq->color(7); - s->canvas_eq->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_eq); - s->canvas_eq->border(15); - - s->eq_x = new Ca_X_Axis(465, 135, 140, 30, "Symbol"); - s->eq_x->align(FL_ALIGN_BOTTOM); - s->eq_x->minimum(-8.0); - s->eq_x->maximum(8.0); - s->eq_x->label_format("%g"); - s->eq_x->minor_grid_color(fl_gray_ramp(20)); - s->eq_x->major_grid_color(fl_gray_ramp(15)); - s->eq_x->label_grid_color(fl_gray_ramp(10)); - s->eq_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->eq_x->minor_grid_style(FL_DOT); - s->eq_x->major_step(5); - s->eq_x->label_step(1); - s->eq_x->axis_align(CA_BOTTOM | CA_LINE); - s->eq_x->axis_color(FL_BLACK); - s->eq_x->current(); - - s->eq_y = new Ca_Y_Axis(420, 40, 40, 90, "Amp"); - s->eq_y->align(FL_ALIGN_LEFT); - s->eq_y->minimum(-0.1); - s->eq_y->maximum(0.1); - s->eq_y->minor_grid_color(fl_gray_ramp(20)); - s->eq_y->major_grid_color(fl_gray_ramp(15)); - s->eq_y->label_grid_color(fl_gray_ramp(10)); - s->eq_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->eq_y->minor_grid_style(FL_DOT); - s->eq_y->major_step(5); - s->eq_y->label_step(1); - s->eq_y->axis_color(FL_BLACK); - s->eq_y->current(); - - s->c_eq->end(); - - s->c_symbol_track = new Fl_Group(380, 200, 525, 200); - s->c_symbol_track->box(FL_DOWN_BOX); - s->c_symbol_track->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); - s->c_symbol_track->current(); - - s->canvas_track = new Ca_Canvas(490, 235, 300, 100, "Symbol and carrier tracking"); - s->canvas_track->box(FL_PLASTIC_DOWN_BOX); - s->canvas_track->color(7); - s->canvas_track->align(FL_ALIGN_TOP); - Fl_Group::current()->resizable(s->canvas_track); - s->canvas_track->border(15); - - s->track_x = new Ca_X_Axis(495, 335, 290, 30, "Time (symbols)"); - s->track_x->align(FL_ALIGN_BOTTOM); - s->track_x->minimum(0.0); - s->track_x->maximum(2400.0*5.0); - s->track_x->label_format("%g"); - s->track_x->minor_grid_color(fl_gray_ramp(20)); - s->track_x->major_grid_color(fl_gray_ramp(15)); - s->track_x->label_grid_color(fl_gray_ramp(10)); - s->track_x->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->track_x->minor_grid_style(FL_DOT); - s->track_x->major_step(5); - s->track_x->label_step(1); - s->track_x->axis_align(CA_BOTTOM | CA_LINE); - s->track_x->axis_color(FL_BLACK); - s->track_x->current(); - - s->symbol_track_y = new Ca_Y_Axis(420, 240, 70, 90, "Cor"); - s->symbol_track_y->align(FL_ALIGN_LEFT); - s->symbol_track_y->minimum(-0.1); - s->symbol_track_y->maximum(0.1); - s->symbol_track_y->minor_grid_color(fl_gray_ramp(20)); - s->symbol_track_y->major_grid_color(fl_gray_ramp(15)); - s->symbol_track_y->label_grid_color(fl_gray_ramp(10)); - s->symbol_track_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->symbol_track_y->minor_grid_style(FL_DOT); - s->symbol_track_y->major_step(5); - s->symbol_track_y->label_step(1); - s->symbol_track_y->axis_color(FL_RED); - s->symbol_track_y->current(); - - s->carrier_y = new Ca_Y_Axis(790, 240, 70, 90, "Freq"); - s->carrier_y->align(FL_ALIGN_RIGHT); - s->carrier_y->minimum(-0.1); - s->carrier_y->maximum(0.1); - s->carrier_y->minor_grid_color(fl_gray_ramp(20)); - s->carrier_y->major_grid_color(fl_gray_ramp(15)); - s->carrier_y->label_grid_color(fl_gray_ramp(10)); - s->carrier_y->grid_visible(CA_LABEL_GRID | CA_ALWAYS_VISIBLE); - s->carrier_y->minor_grid_style(FL_DOT); - s->carrier_y->major_step(5); - s->carrier_y->label_step(1); - s->carrier_y->axis_align(CA_RIGHT); - s->carrier_y->axis_color(FL_BLUE); - s->carrier_y->current(); - - s->c_symbol_track->end(); - - s->audio_meter = new Fl_Audio_Meter(672, 10, 16, 150, ""); - s->audio_meter->box(FL_PLASTIC_UP_BOX); - s->audio_meter->type(FL_VERT_AUDIO_METER); - - s->audio_level = new Fl_Output(650, 170, 60, 20, ""); - s->audio_level->textsize(10); - - s->c_right->end(); - - Fl_Group::current()->resizable(s->c_right); - s->w->end(); - s->w->show(); - - s->next_constel_point = 0; - s->constel_window = 10000; - - s->carrier_points = 0; - s->carrier_ptr = 0; - s->carrier_window = 100; - - s->symbol_track_points = 0; - s->symbol_track_window = 10000; - Fl::check(); - return s; -} -/*- End of function --------------------------------------------------------*/ - -void qam_wait_to_end(qam_monitor_t *s) -{ - fd_set rfds; - int res; - struct timeval tv; - - fprintf(stderr, "Processing complete. Press the key to end\n"); - do - { - usleep(100000); - Fl::check(); - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_usec = 100000; - tv.tv_sec = 0; - res = select(1, &rfds, NULL, NULL, &tv); - } - while (res <= 0); -} -/*- End of function --------------------------------------------------------*/ -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/modem_monitor.h b/libs/spandsp/tests/modem_monitor.h deleted file mode 100644 index 3a3f896b8a..0000000000 --- a/libs/spandsp/tests/modem_monitor.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * constel.h - Display QAM constellations, using the FLTK toolkit. - * - * 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 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. - */ - -/*! \page constel_page Modem performance monitoring -\section constel_page_sec_1 What does it do? -This code controls a GUI window, which provides monitoring of the internal status -of a modem. It shows, graphically: - - - the constellation, for PSK, QAM and other similar modulations. - - the equalizer status, for modems with adaptive equalizers. - - the carrier frequency. - - the symbol timing correction. - -\section constel_page_sec_2 How does it work? -This code uses the FLTK cross platform GUI toolkit. It works on X11 and Windows platforms. -In addition to the basic FLTK toolkit, fltk_cartesian is also required. -*/ - -#if !defined(_MODEM_MONITOR_H_) -#define _MODEM_MONITOR_H_ - -struct qam_monitor_s; - -typedef struct qam_monitor_s qam_monitor_t; - -#if defined(__cplusplus) -extern "C" -{ -#endif - -qam_monitor_t *qam_monitor_init(float constel_width, float constel_scaling, const char *tag); -int qam_monitor_clear_constel(qam_monitor_t *s); -int qam_monitor_update_constel(qam_monitor_t *s, const complexf_t *pt); -int qam_monitor_update_equalizer(qam_monitor_t *s, const complexf_t *coeffs, int len); -int qam_monitor_update_int_equalizer(qam_monitor_t *s, const complexi16_t *coeffs, int len); -int qam_monitor_update_symbol_tracking(qam_monitor_t *s, float total_correction); -int qam_monitor_update_carrier_tracking(qam_monitor_t *s, float carrier); -int qam_monitor_update_audio_level(qam_monitor_t *s, const int16_t amp[], int len); -void qam_wait_to_end(qam_monitor_t *s); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/noise_tests.c b/libs/spandsp/tests/noise_tests.c deleted file mode 100644 index 0c7ee99bbf..0000000000 --- a/libs/spandsp/tests/noise_tests.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * noise_tests.c - * - * 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 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. - */ - -/*! \page noise_tests_page Noise generator tests -\section noise_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if !defined(M_PI) -# define M_PI 3.14159265358979323846 /* pi */ -#endif - -#define OUT_FILE_NAME "noise.wav" - -/* Some simple sanity tests for the noise generation routines */ - -int main (int argc, char *argv[]) -{ - int i; - int j; - int level; - int clip_high; - int clip_low; - int quality; - int total_samples; - int seed = 1234567; - int outframes; - int16_t value; - double total; - double x; - double p; - double o; - int bins[65536]; - int16_t amp[1024]; - noise_state_t noise_source; - SNDFILE *outhandle; - - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - for (quality = 7; quality <= 20; quality += (20 - 7)) - { - /* Generate AWGN at several RMS levels between -50dBOv and 0dBOv. Noise is - generated for a large number of samples (1,000,000), and the RMS value - of the noise is calculated along the way. If the resulting level is - close to the requested RMS level, at least the scaling of the noise - should be Ok. At high levels some clipping may distort the result a - little. */ - printf("Testing AWGN power, with quality %d\n", quality); - for (level = -50; level <= 0; level += 5) - { - clip_high = 0; - clip_low = 0; - total = 0.0; - noise_init_dbov(&noise_source, seed, (float) level, NOISE_CLASS_AWGN, quality); - total_samples = 1000000; - for (i = 0; i < total_samples; i++) - { - value = noise(&noise_source); - if (value == 32767) - clip_high++; - else if (value == -32768) - clip_low++; - total += ((double) value)*((double) value); - } - printf ("RMS = %.3f (expected %d) %.2f%% error [clipped samples %d+%d]\n", - 10.0*log10((total/total_samples)/(32768.0*32768.0) + 1.0e-10), - level, - 100.0*(1.0 - sqrt(total/total_samples)/(pow(10.0, level/20.0)*32768.0)), - clip_low, - clip_high); - if (level < -5 && fabs(10.0*log10((total/total_samples)/(32768.0*32768.0) + 1.0e-10) - level) > 0.2) - { - printf("Test failed\n"); - exit(2); - } - } - } - - /* Now look at the statistical spread of the results, by collecting data in - bins from a large number of samples. Use a fairly high noise level, but - low enough to avoid significant clipping. Use the Gaussian model to - predict the real probability, and present the results for graphing. */ - quality = 7; - printf("Testing the statistical spread of AWGN, with quality %d\n", quality); - memset(bins, 0, sizeof(bins)); - clip_high = 0; - clip_low = 0; - level = -15; - noise_init_dbov(&noise_source, seed, (float) level, NOISE_CLASS_AWGN, quality); - total_samples = 10000000; - for (i = 0; i < total_samples; i++) - { - value = noise(&noise_source); - if (value == 32767) - clip_high++; - else if (value == -32768) - clip_low++; - bins[value + 32768]++; - } - /* Find the RMS power level to expect */ - o = pow(10.0, level/20.0)*(32768.0*0.70711); - for (i = 0; i < 65536 - 10; i++) - { - x = i - 32768; - /* Find the real probability for this bin */ - p = (1.0/(o*sqrt(2.0*M_PI)))*exp(-(x*x)/(2.0*o*o)); - /* Now do a little smoothing on the real data to get a reasonably - steady answer */ - x = 0; - for (j = 0; j < 10; j++) - x += bins[i + j]; - x /= 10.0; - x /= total_samples; - /* Now send it out for graphing. */ - if (p > 0.0000001) - printf("%6d %.7f %.7f\n", i - 32768, x, p); - } - - printf("Generating AWGN at -15dBOv to file\n"); - for (j = 0; j < 50; j++) - { - for (i = 0; i < 1024; i++) - amp[i] = noise(&noise_source); - outframes = sf_writef_short(outhandle, amp, 1024); - if (outframes != 1024) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - - /* Generate Hoth noise at several RMS levels between -50dBm and 0dBm. Noise - is generated for a large number of samples (1,000,000), and the RMS value - of the noise is calculated along the way. If the resulting level is - close to the requested RMS level, at least the scaling of the noise - should be Ok. At high levels some clipping may distort the result a - little. */ - quality = 7; - printf("Testing Hoth noise power, with quality %d\n", quality); - for (level = -50; level <= 0; level += 5) - { - clip_high = 0; - clip_low = 0; - total = 0.0; - noise_init_dbov(&noise_source, seed, (float) level, NOISE_CLASS_HOTH, quality); - total_samples = 1000000; - for (i = 0; i < total_samples; i++) - { - value = noise(&noise_source); - if (value == 32767) - clip_high++; - else if (value == -32768) - clip_low++; - total += ((double) value)*((double) value); - } - printf ("RMS = %.3f (expected %d) %.2f%% error [clipped samples %d+%d]\n", - 10.0*log10((total/total_samples)/(32768.0*32768.0) + 1.0e-10), - level, - 100.0*(1.0 - sqrt(total/total_samples)/(pow(10.0, level/20.0)*32768.0)), - clip_low, - clip_high); - if (level < -5 && fabs(10.0*log10((total/total_samples)/(32768.0*32768.0) + 1.0e-10) - level) > 0.2) - { - printf("Test failed\n"); - exit(2); - } - } - - quality = 7; - printf("Generating Hoth noise at -15dBOv to file\n"); - level = -15; - noise_init_dbov(&noise_source, seed, (float) level, NOISE_CLASS_HOTH, quality); - for (j = 0; j < 50; j++) - { - for (i = 0; i < 1024; i++) - amp[i] = noise(&noise_source); - outframes = sf_writef_short(outhandle, amp, 1024); - if (outframes != 1024) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/oki_adpcm_tests.c b/libs/spandsp/tests/oki_adpcm_tests.c deleted file mode 100644 index a9eef7e1ae..0000000000 --- a/libs/spandsp/tests/oki_adpcm_tests.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * oki_adpcm_tests.c - Test the Oki (Dialogic) ADPCM encode and decode - * software at 24kbps and 32kbps. - * - * 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 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 oki_adpcm_tests_page OKI (Dialogic) ADPCM tests -\section oki_adpcm_tests_page_sec_1 What does it do? -To perform a general audio quality test, oki_adpcm_tests should be run. The test file -../test-data/local/short_nb_voice.wav will be compressed to the specified bit rate, -decompressed, and the resulting audio stored in post_oki_adpcm.wav. A simple SNR test -is automatically performed. Listening tests may be used for a more detailed evaluation -of the degradation in quality caused by the compression. Both 32k bps and 24k bps -compression may be tested. - -\section oki_adpcm_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUT_FILE_NAME "post_oki_adpcm.wav" - -#define HIST_LEN 1000 - -int main(int argc, char *argv[]) -{ - int i; - SNDFILE *inhandle; - SNDFILE *outhandle; - int frames; - int dec_frames; - int oki_bytes; - int bit_rate; - double pre_energy; - double post_energy; - double diff_energy; - int16_t pre_amp[HIST_LEN]; - int16_t post_amp[HIST_LEN]; - uint8_t oki_data[HIST_LEN]; - int16_t history[HIST_LEN]; - int hist_in; - int hist_out; - oki_adpcm_state_t *oki_enc_state; - oki_adpcm_state_t *oki_dec_state; - oki_adpcm_state_t *oki_dec_state2; - int xx; - int total_pre_samples; - int total_compressed_bytes; - int total_post_samples; - int successive_08_bytes; - int successive_80_bytes; - int encoded_fd; - const char *encoded_file_name; - const char *in_file_name; - bool log_encoded_data; - int opt; - - bit_rate = 32000; - encoded_file_name = NULL; - in_file_name = IN_FILE_NAME; - log_encoded_data = false; - while ((opt = getopt(argc, argv, "2d:i:l")) != -1) - { - switch (opt) - { - case '2': - bit_rate = 24000; - break; - case 'd': - encoded_file_name = optarg; - break; - case 'i': - in_file_name = optarg; - break; - case 'l': - log_encoded_data = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - encoded_fd = -1; - inhandle = NULL; - oki_enc_state = NULL; - if (encoded_file_name) - { - if ((encoded_fd = open(encoded_file_name, O_RDONLY)) < 0) - { - fprintf(stderr, " Cannot open encoded file '%s'\n", encoded_file_name); - exit(2); - } - } - else - { - if ((inhandle = sf_open_telephony_read(in_file_name, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", in_file_name); - exit(2); - } - if ((oki_enc_state = oki_adpcm_init(NULL, bit_rate)) == NULL) - { - fprintf(stderr, " Cannot create encoder\n"); - exit(2); - } - } - - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - if ((oki_dec_state = oki_adpcm_init(NULL, bit_rate)) == NULL) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - if ((oki_dec_state2 = oki_adpcm_init(NULL, bit_rate)) == NULL) - { - fprintf(stderr, " Cannot create decoder\n"); - exit(2); - } - - hist_in = 0; - if (bit_rate == 32000) - hist_out = 0; - else - hist_out = HIST_LEN - 27; - memset(history, 0, sizeof(history)); - pre_energy = 0.0; - post_energy = 0.0; - diff_energy = 0.0; - total_pre_samples = 0; - total_compressed_bytes = 0; - total_post_samples = 0; - if (encoded_file_name) - { - /* Decode a file of OKI ADPCM code to a linear wave file */ - while ((oki_bytes = read(encoded_fd, oki_data, 80)) > 0) - { - total_compressed_bytes += oki_bytes; - dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes); - total_post_samples += dec_frames; - for (i = 0; i < dec_frames; i++) - { - post_energy += (double) post_amp[i] * (double) post_amp[i]; - xx = post_amp[i] - history[hist_out++]; - if (hist_out >= HIST_LEN) - hist_out = 0; - diff_energy += (double) xx * (double) xx; - } - sf_writef_short(outhandle, post_amp, dec_frames); - } - close(encoded_fd); - } - else - { - /* Perform a linear wave file -> OKI ADPCM -> linear wave file cycle. Along the way - check the decoder resets on the sequence specified for this codec, and the gain - and worst case sample distortion. */ - successive_08_bytes = 0; - successive_80_bytes = 0; - while ((frames = sf_readf_short(inhandle, pre_amp, 159))) - { - total_pre_samples += frames; - oki_bytes = oki_adpcm_encode(oki_enc_state, oki_data, pre_amp, frames); - if (log_encoded_data) - write(1, oki_data, oki_bytes); - total_compressed_bytes += oki_bytes; - /* Look for a condition which is defined as something which should cause a reset of - the decoder (48 samples of 0, 8, 0, 8, etc.), and verify that it really does. Use - a second decode, which we feed byte by byte, for this. */ - for (i = 0; i < oki_bytes; i++) - { - oki_adpcm_decode(oki_dec_state2, post_amp, &oki_data[i], 1); - if (oki_data[i] == 0x08) - successive_08_bytes++; - else - successive_08_bytes = 0; - if (oki_data[i] == 0x80) - successive_80_bytes++; - else - successive_80_bytes = 0; - if (successive_08_bytes == 24 || successive_80_bytes == 24) - { - if (oki_dec_state2->step_index != 0) - { - fprintf(stderr, "Decoder reset failure\n"); - exit(2); - } - } - } - dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes); - total_post_samples += dec_frames; - for (i = 0; i < frames; i++) - { - history[hist_in++] = pre_amp[i]; - if (hist_in >= HIST_LEN) - hist_in = 0; - pre_energy += (double) pre_amp[i] * (double) pre_amp[i]; - } - for (i = 0; i < dec_frames; i++) - { - post_energy += (double) post_amp[i] * (double) post_amp[i]; - xx = post_amp[i] - history[hist_out++]; - if (hist_out >= HIST_LEN) - hist_out = 0; - diff_energy += (double) xx * (double) xx; - //post_amp[i] = xx; - } - sf_writef_short(outhandle, post_amp, dec_frames); - } - printf("Pre samples: %d\n", total_pre_samples); - printf("Compressed bytes: %d\n", total_compressed_bytes); - printf("Post samples: %d\n", total_post_samples); - - printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy); - printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy); - if (bit_rate == 32000) - { - if (fabs(1.0 - post_energy/pre_energy) > 0.01 - || - fabs(diff_energy/post_energy) > 0.01) - { - printf("Tests failed.\n"); - exit(2); - } - } - else - { - if (fabs(1.0 - post_energy/pre_energy) > 0.11 - || - fabs(diff_energy/post_energy) > 0.05) - { - printf("Tests failed.\n"); - exit(2); - } - } - - oki_adpcm_free(oki_enc_state); - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", in_file_name); - exit(2); - } - } - oki_adpcm_free(oki_dec_state); - oki_adpcm_free(oki_dec_state2); - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/pcap_parse.c b/libs/spandsp/tests/pcap_parse.c deleted file mode 100644 index 4e79743706..0000000000 --- a/libs/spandsp/tests/pcap_parse.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * pcap_parse.c - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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. - * - * Some code from SIPP (http://sf.net/projects/sipp) was used as a model - * for how to work with PCAP files. That code was authored by Guillaume - * TEISSIER from FTR&D 02/02/2006, and released under the GPL2 licence. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#if defined(HAVE_PCAP_H) -#include -#include -#endif -#include -#include -#if defined(__HPUX) || defined(__CYGWIN__) || defined(__FreeBSD__) -#include -#endif -#include -#if !defined(__CYGWIN__) -#include -#endif -#include - -#include -#include -#include - -#include "udptl.h" -#include "spandsp.h" -#include "pcap_parse.h" - -#if defined(__HPUX) || defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) - -struct iphdr -{ -#if defined(_HPUX_LI) - unsigned int ihl:4; - unsigned int version:4; -#else - unsigned int version:4; - unsigned int ihl:4; -#endif - uint8_t tos; - uint16_t tot_len; - uint16_t id; - uint16_t frag_off; - uint8_t ttl; - uint8_t protocol; - uint16_t check; - uint32_t saddr; - uint32_t daddr; - /*The options start here. */ -}; - -#endif - -/* We define our own structures for Ethernet Header and IPv6 Header as they are not available on CYGWIN. - * We only need the fields, which are necessary to determine the type of the next header. - * we could also define our own structures for UDP and IPv4. We currently use the structures - * made available by the platform, as we had no problems to get them on all supported platforms. - */ - -typedef struct _ether_hdr -{ - char ether_dst[6]; - char ether_src[6]; - uint16_t ether_type; -} ether_hdr; - -typedef struct _null_hdr -{ - uint32_t pf_type; -} null_hdr; - -#if !defined(__CYGWIN__) -typedef struct _ipv6_hdr -{ - char dontcare[6]; - u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */ - char dontcare2[33]; -} ipv6_hdr; -#endif - -char errbuf[PCAP_ERRBUF_SIZE]; - -int pcap_scan_pkts(const char *file, - uint32_t src_addr, - uint16_t src_port, - uint32_t dest_addr, - uint16_t dest_port, - pcap_timing_update_handler_t *timing_update_handler, - pcap_packet_handler_t *packet_handler, - void *user_data) -{ - pcap_t *pcap; - struct pcap_pkthdr *pkthdr; - uint8_t *pktdata; - uint8_t *pktptr; - const uint8_t *body; - int body_len; - int total_pkts; - uint32_t pktlen; - ether_hdr *ethhdr; - struct sll_header *sllhdr; - null_hdr *nullhdr; - struct iphdr *iphdr; -#if !defined(__CYGWIN__) - ipv6_hdr *ip6hdr; -#endif - struct udphdr *udphdr; - int datalink; - int packet_type; - - total_pkts = 0; - if ((pcap = pcap_open_offline(file, errbuf)) == NULL) - { - fprintf(stderr, "Can't open PCAP file: %s\n", errbuf); - return -1; - } - //printf("PCAP file version %d.%d\n", pcap_major_version(pcap), pcap_minor_version(pcap)); - datalink = pcap_datalink(pcap); - /* DLT_EN10MB seems to apply to all forms of ethernet, not just the 10MB kind. */ - switch (datalink) - { - case DLT_EN10MB: - printf("Datalink type ethernet\n"); - break; - case DLT_LINUX_SLL: - printf("Datalink type cooked Linux socket\n"); - break; - case DLT_NULL: - printf("Datalink type NULL\n"); - break; - default: - fprintf(stderr, "Unsupported data link type %d\n", datalink); - return -1; - } - - pkthdr = NULL; - pktdata = NULL; -#if defined(HAVE_PCAP_NEXT_EX) - while (pcap_next_ex(pcap, &pkthdr, (const uint8_t **) &pktdata) == 1) - { -#else - if ((pkthdr = (struct pcap_pkthdr *) malloc(sizeof(*pkthdr))) == NULL) - { - fprintf(stderr, "Can't allocate memory for pcap pkthdr\n"); - return -1; - } - while ((pktdata = (uint8_t *) pcap_next(pcap, pkthdr)) != NULL) - { -#endif - pktptr = pktdata; - switch (datalink) - { - case DLT_EN10MB: - ethhdr = (ether_hdr *) pktptr; - packet_type = ntohs(ethhdr->ether_type); - pktptr += sizeof(*ethhdr); - /* Check for a 802.1Q Virtual LAN entry we might need to step over */ - if (packet_type == 0x8100) - { - /* Step over the 802.1Q stuff, to get to the next packet type */ - pktptr += sizeof(uint16_t); - packet_type = ntohs(*((uint16_t *) pktptr)); - pktptr += sizeof(uint16_t); - } -#if !defined(__CYGWIN__) - if (packet_type != 0x0800 /* IPv4 */ - && - packet_type != 0x86DD) /* IPv6 */ -#else - if (packet_type != 0x0800) /* IPv4 */ -#endif - { - continue; - } - iphdr = (struct iphdr *) pktptr; - break; - case DLT_LINUX_SLL: - sllhdr = (struct sll_header *) pktptr; - packet_type = ntohs(sllhdr->sll_protocol); - pktptr += sizeof(*sllhdr); -#if !defined(__CYGWIN__) - if (packet_type != 0x0800 /* IPv4 */ - && - packet_type != 0x86DD) /* IPv6 */ -#else - if (packet_type != 0x0800) /* IPv4 */ -#endif - { - continue; - } - iphdr = (struct iphdr *) pktptr; - break; - case DLT_NULL: - nullhdr = (null_hdr *) pktptr; - pktptr += sizeof(*nullhdr); - if (nullhdr->pf_type != PF_INET && nullhdr->pf_type != PF_INET6) - continue; - iphdr = (struct iphdr *) pktptr; - break; - default: - continue; - } -#if 0 - { - int i; - printf("--- %d -", pkthdr->caplen); - for (i = 0; i < pkthdr->caplen; i++) - printf(" %02x", pktdata[i]); - printf("\n"); - } -#endif -#if !defined(__CYGWIN__) - if (iphdr && iphdr->version == 6) - { - /* ipv6 */ - ip6hdr = (ipv6_hdr *) (void *) iphdr; - if (ip6hdr->nxt_header != IPPROTO_UDP) - continue; - pktlen = (uint32_t) pkthdr->len - (pktptr - pktdata) - sizeof(*ip6hdr); - udphdr = (struct udphdr *) ((uint8_t *) ip6hdr + sizeof(*ip6hdr)); - } - else -#endif - { - /* ipv4 */ - if (iphdr->protocol != IPPROTO_UDP) - continue; -#if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) - udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2) + 4); - pktlen = (uint32_t) ntohs(udphdr->uh_ulen); -#elif defined ( __HPUX) - udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2)); - pktlen = (uint32_t) pkthdr->len - (pktptr - pktdata) - sizeof(*iphdr); -#else - udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2)); - pktlen = (uint32_t) ntohs(udphdr->len); -#endif - } - - timing_update_handler(user_data, &pkthdr->ts); - - if (src_addr && ntohl(iphdr->saddr) != src_addr) - continue; -#if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) - if (src_port && ntohs(udphdr->uh_sport) != src_port) -#else - if (src_port && ntohs(udphdr->source) != src_port) -#endif - continue; - if (dest_addr && ntohl(iphdr->daddr) != dest_addr) - continue; -#if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) - if (dest_port && ntohs(udphdr->uh_dport) != dest_port) -#else - if (dest_port && ntohs(udphdr->dest) != dest_port) -#endif - continue; - - if (pkthdr->len != pkthdr->caplen) - { - fprintf(stderr, "Truncated packet - total len = %d, captured len = %d\n", pkthdr->len, pkthdr->caplen); - exit(2); - } -#if 0 - printf("%d:%d -> %d:%d\n", ntohl(iphdr->saddr), ntohs(udphdr->source), ntohl(iphdr->daddr), ntohs(udphdr->dest)); -#endif - body = (const uint8_t *) udphdr; - body += sizeof(struct udphdr); - body_len = pktlen - sizeof(struct udphdr); - packet_handler(user_data, body, body_len); - - total_pkts++; - } - fprintf(stderr, "In pcap %s there were %d accepted packets\n", file, total_pkts); - pcap_close(pcap); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/pcap_parse.h b/libs/spandsp/tests/pcap_parse.h deleted file mode 100644 index e21c8804c9..0000000000 --- a/libs/spandsp/tests/pcap_parse.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * pcap_parse.h - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 */ - -#if !defined(_SPANDSP_PCAP_PARSE_H_) -#define _SPANDSP_PCAP_PARSE_H_ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -typedef int (pcap_timing_update_handler_t)(void *user_data, struct timeval *ts); -typedef int (pcap_packet_handler_t)(void *user_data, const uint8_t *pkt, int len); - -int pcap_scan_pkts(const char *file, - uint32_t src_addr, - uint16_t src_port, - uint32_t dest_addr, - uint16_t dest_port, - pcap_timing_update_handler_t *timing_update_handler, - pcap_packet_handler_t *packet_handler, - void *user_data); - -#if defined(__cplusplus) -} -#endif - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/playout_tests.c b/libs/spandsp/tests/playout_tests.c deleted file mode 100644 index a5180eafdf..0000000000 --- a/libs/spandsp/tests/playout_tests.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * playout_tests.c - * - * 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 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. - */ - -/*! \page playout_tests_page Playout (jitter buffering) tests -\section playout_tests_page_sec_1 What does it do? -These tests simulate timing jitter and packet loss in an audio stream, and see -how well the playout module copes. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp/private/time_scale.h" -#include "spandsp-sim.h" - -#define INPUT_FILE_NAME "playout_in.wav" -#define OUTPUT_FILE_NAME "playout_out.wav" - -#define BLOCK_LEN 160 - -static void dynamic_buffer_tests(void) -{ - playout_state_t *s; - playout_frame_t frame; - playout_frame_t *p; - plc_state_t plc; - time_scale_state_t ts; - int16_t *amp; - int16_t fill[BLOCK_LEN]; - int16_t buf[20*BLOCK_LEN]; - int16_t out[10*BLOCK_LEN]; - timestamp_t time_stamp; - timestamp_t next_actual_receive; - timestamp_t next_scheduled_receive; - int near_far_time_offset; - int rng; - int i; - int j; - int ret; - int len; - int inframes; - int outframes; - SNDFILE *inhandle; - SNDFILE *outhandle; - - if ((inhandle = sf_open_telephony_read(INPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Failed to open audio file '%s'\n", INPUT_FILE_NAME); - exit(2); - } - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Failed to create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - near_far_time_offset = 54321; - time_stamp = 12345; - next_actual_receive = time_stamp + near_far_time_offset; - next_scheduled_receive = 0; - for (i = 0; i < BLOCK_LEN; i++) - fill[i] = 32767; - - if ((s = playout_init(2*BLOCK_LEN, 15*BLOCK_LEN)) == NULL) - return; - plc_init(&plc); - time_scale_init(&ts, SAMPLE_RATE, 1.0); - for (i = 0; i < 1000000; i++) - { - if (i >= next_actual_receive) - { - amp = malloc(BLOCK_LEN*sizeof(int16_t)); - inframes = sf_readf_short(inhandle, amp, BLOCK_LEN); - if (inframes < BLOCK_LEN) - break; - ret = playout_put(s, - amp, - PLAYOUT_TYPE_SPEECH, - inframes, - time_stamp, - next_actual_receive); -#if 0 - switch (ret) - { - case PLAYOUT_OK: - printf("<< Record\n"); - break; - case PLAYOUT_ERROR: - printf("<< Error\n"); - break; - default: - printf("<< Eh?\n"); - break; - } -#endif - rng = rand() & 0xFF; - if (i < 100000) - rng = (rng*rng) >> 7; - else if (i < 200000) - rng = (rng*rng) >> 6; - else if (i < 300000) - rng = (rng*rng) >> 5; - else if (i < 400000) - rng = (rng*rng) >> 7; - time_stamp += BLOCK_LEN; - next_actual_receive = time_stamp + near_far_time_offset + rng; - } - if (i >= next_scheduled_receive) - { - do - { - ret = playout_get(s, &frame, next_scheduled_receive); - if (ret == PLAYOUT_DROP) - printf(">> Drop %d\n", next_scheduled_receive); - } - while (ret == PLAYOUT_DROP); - switch (ret) - { - case PLAYOUT_OK: - printf(">> Play %d\n", next_scheduled_receive); - plc_rx(&plc, frame.data, frame.sender_len); - len = time_scale(&ts, out, ((int16_t *) frame.data), frame.sender_len); -printf("len = %d\n", len); - for (j = 0; j < len; j++) - { - buf[2*j] = out[j]; - buf[2*j + 1] = 10*playout_current_length(s); - } - outframes = sf_writef_short(outhandle, buf, len); - if (outframes != len) - { - fprintf(stderr, " Error writing out sound\n"); - exit(2); - } - free(frame.data); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_FILLIN: - printf(">> Fill %d\n", next_scheduled_receive); - plc_fillin(&plc, fill, BLOCK_LEN); - time_scale_rate(&ts, 0.5); - len = time_scale(&ts, out, fill, BLOCK_LEN); - time_scale_rate(&ts, 1.0); -printf("len = %d\n", len); - for (j = 0; j < len; j++) - { - buf[2*j] = out[j]; - buf[2*j + 1] = 10*playout_current_length(s); - } - outframes = sf_writef_short(outhandle, buf, len); - if (outframes != len) - { - fprintf(stderr, " Error writing out sound\n"); - exit(2); - } - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_DROP: - printf(">> Drop %d\n", next_scheduled_receive); - break; - case PLAYOUT_NOFRAME: - printf(">> No frame %d %d %d %d\n", next_scheduled_receive, playout_next_due(s), s->last_speech_sender_stamp, s->last_speech_sender_len); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_EMPTY: - printf(">> Empty %d\n", next_scheduled_receive); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_ERROR: - printf(">> Error %d\n", next_scheduled_receive); - next_scheduled_receive += BLOCK_LEN; - break; - default: - printf(">> Eh? %d\n", next_scheduled_receive); - break; - } - } - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", INPUT_FILE_NAME); - exit(2); - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - printf("%10" PRId32 " %10" PRId32 " %10d\n", s->state_just_in_time, s->state_late, playout_current_length(s)); - - /* Clear everything from the queue */ - while ((p = playout_get_unconditional(s))) - /*free(p->data)*/; - /* Now free the context itself */ - playout_free(s); -} -/*- End of function --------------------------------------------------------*/ - -static void static_buffer_tests(void) -{ - playout_state_t *s; - playout_frame_t frame; - playout_frame_t *p; - int type; - uint8_t fr[BLOCK_LEN]; - timestamp_t next_scheduled_send; - int transit_time; - timestamp_t next_actual_receive; - timestamp_t next_scheduled_receive; - int len; - int i; - int ret; - - next_scheduled_send = 0; - transit_time = 320; - next_actual_receive = next_scheduled_send + transit_time; - next_scheduled_receive = 960; - - memset(fr, 0, sizeof(fr)); - type = PLAYOUT_TYPE_SPEECH; - len = BLOCK_LEN; - - if ((s = playout_init(2*BLOCK_LEN, 2*BLOCK_LEN)) == NULL) - return; - for (i = 0; i < 1000000; i++) - { - if (i >= next_actual_receive) - { - ret = playout_put(s, - fr, - type, - len, - next_scheduled_send, - next_actual_receive); - switch (ret) - { - case PLAYOUT_OK: - printf("<< Record\n"); - break; - case PLAYOUT_ERROR: - printf("<< Error\n"); - break; - default: - printf("<< Eh?\n"); - break; - } - next_scheduled_send += BLOCK_LEN; - ret = rand() & 0xFF; - ret = (ret*ret) >> 7; - transit_time = 320 + ret; - next_actual_receive = next_scheduled_send + transit_time; - } - if (i >= next_scheduled_receive) - { - do - { - ret = playout_get(s, &frame, next_scheduled_receive); - } - while (ret == PLAYOUT_DROP); - switch (ret) - { - case PLAYOUT_OK: - printf(">> Play\n"); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_FILLIN: - printf(">> Fill\n"); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_DROP: - printf(">> Drop\n"); - break; - case PLAYOUT_NOFRAME: - printf(">> No frame\n"); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_EMPTY: - printf(">> Empty\n"); - next_scheduled_receive += BLOCK_LEN; - break; - case PLAYOUT_ERROR: - printf(">> Error\n"); - next_scheduled_receive += BLOCK_LEN; - break; - default: - printf(">> Eh?\n"); - break; - } - } - } - /* Clear everything from the queue */ - while ((p = playout_get_unconditional(s))) - /*free(p->data)*/; - /* Now free the context itself */ - playout_free(s); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - printf("Dynamic buffering tests\n"); - dynamic_buffer_tests(); - printf("Static buffering tests\n"); - static_buffer_tests(); -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/plc_tests.c b/libs/spandsp/tests/plc_tests.c deleted file mode 100644 index 78e645d317..0000000000 --- a/libs/spandsp/tests/plc_tests.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * plc_tests.c - * - * 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 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. - */ - -/*! \page plc_tests_page Packet loss concealment tests -\section plc_tests_page_sec_1 What does it do? -These tests run a speech file through the packet loss concealment routines. -The loss rate, in percent, and the packet size, in samples, may be specified -on the command line. - -\section plc_tests_page_sec_2 How are the tests run? -These tests process a speech file called pre_plc.wav. This file should contain -8000 sample/second 16 bits/sample linear audio. The tests read this file in -blocks, of a size specified on the command line. Some of these blocks are -dropped, to simulate packet loss. The rate of loss is also specified on the -command line. The PLC module is then used to reconstruct an acceptable -approximation to the original signal. The resulting audio is written to a new -audio file, called post_plc.wav. This file contains 8000 sample/second -16 bits/sample linear audio. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define INPUT_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUTPUT_FILE_NAME "post_plc.wav" - -int main(int argc, char *argv[]) -{ - SNDFILE *inhandle; - SNDFILE *outhandle; - plc_state_t plc; - int inframes; - int outframes; - int16_t amp[1024]; - int block_no; - int lost_blocks; - int block_len; - int loss_rate; - int dropit; - int tone; - int i; - int opt; - bool block_real; - bool block_synthetic; - uint32_t phase_acc; - int32_t phase_rate; - - loss_rate = 25; - block_len = 160; - block_real = false; - block_synthetic = false; - tone = -1; - while ((opt = getopt(argc, argv, "b:l:rst:")) != -1) - { - switch (opt) - { - case 'b': - block_len = atoi(optarg); - break; - case 'l': - loss_rate = atoi(optarg); - break; - case 'r': - block_real = true; - break; - case 's': - block_synthetic = true; - break; - case 't': - tone = atoi(optarg); - break; - } - } - phase_rate = 0; - inhandle = NULL; - if (tone < 0) - { - if ((inhandle = sf_open_telephony_read(INPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Failed to open audio file '%s'\n", INPUT_FILE_NAME); - exit(2); - } - } - else - { - phase_rate = dds_phase_ratef((float) tone); - } - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Failed to open audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - plc_init(&plc); - lost_blocks = 0; - for (block_no = 0; ; block_no++) - { - if (tone < 0) - { - inframes = sf_readf_short(inhandle, amp, block_len); - if (inframes != block_len) - break; - } - else - { - if (block_no > 10000) - break; - for (i = 0; i < block_len; i++) - amp[i] = (int16_t) dds_modf(&phase_acc, phase_rate, 10000.0, 0); - inframes = block_len; - } - dropit = rand()/(RAND_MAX/100); - if (dropit > loss_rate) - { - plc_rx(&plc, amp, inframes); - if (block_real) - memset(amp, 0, sizeof(int16_t)*inframes); - } - else - { - lost_blocks++; - plc_fillin(&plc, amp, inframes); - if (block_synthetic) - memset(amp, 0, sizeof(int16_t)*inframes); - } - outframes = sf_writef_short(outhandle, amp, inframes); - if (outframes != inframes) - { - fprintf(stderr, " Error writing out sound\n"); - exit(2); - } - } - printf("Dropped %d of %d blocks\n", lost_blocks, block_no); - if (tone < 0) - { - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", INPUT_FILE_NAME); - exit(2); - } - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/power_meter_tests.c b/libs/spandsp/tests/power_meter_tests.c deleted file mode 100644 index 59287b7d21..0000000000 --- a/libs/spandsp/tests/power_meter_tests.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * power_meter_tests.c - * - * 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 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. - */ - -/*! \page power_meter_tests_page Power meter tests -\section power_meter_tests_page_sec_1 What does it do? -These tests assess the accuracy of power meters built from the power meter module. -Both tones and noise are used to check the meter's behaviour. - -\section power_meter_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 "spandsp.h" -#include "spandsp-sim.h" - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUT_FILE_NAME "power_meter_tests.wav" - -static int power_surge_detector_tests(void) -{ - SNDFILE *outhandle; - power_surge_detector_state_t *sig; - int i; - int sample; - int16_t amp[8000]; - int16_t amp_out[2*8000]; - awgn_state_t *awgnx; - int32_t phase_rate; - uint32_t phase_acc; - int16_t phase_scale; - float signal_power; - int32_t signal_level; - int signal_present; - int prev_signal_present; - int ok; - int extremes[4]; - - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - sig = power_surge_detector_init(NULL, -50.0f, 5.0f); - prev_signal_present = false; - - phase_rate = dds_phase_rate(450.0f); - phase_acc = 0; - - phase_scale = dds_scaling_dbm0(-33.0f); - awgnx = awgn_init_dbm0(NULL, 1234567, -45.0f); - - extremes[0] = 8001; - extremes[1] = -1; - extremes[2] = 8001; - extremes[3] = -1; - for (sample = 0; sample < 800000; sample += 8000) - { - ok = 0; - for (i = 0; i < 8000; i++) - { - amp[i] = awgn(awgnx); - if (i < 4000) - amp[i] += dds_mod(&phase_acc, phase_rate, phase_scale, 0); - - signal_level = power_surge_detector(sig, amp[i]); - signal_present = (signal_level != 0); - if (prev_signal_present != signal_present) - { - signal_power = power_surge_detector_current_dbm0(sig); - if (signal_present) - { - if (ok == 0 && i >= 0 && i < 25) - ok = 1; - if (extremes[0] > i) - extremes[0] = i; - if (extremes[1] < i) - extremes[1] = i; - printf("On at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power); - } - else - { - if (ok == 1 && i >= 4000 + 0 && i < 4000 + 35) - ok = 2; - if (extremes[2] > i) - extremes[2] = i; - if (extremes[3] < i) - extremes[3] = i; - printf("Off at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power); - } - prev_signal_present = signal_present; - } - amp_out[2*i] = amp[i]; - amp_out[2*i + 1] = signal_present*5000; - } - sf_writef_short(outhandle, amp_out, 8000); - if (ok != 2 - || - extremes[0] < 1 - || - extremes[1] > 30 - || - extremes[2] < 4001 - || - extremes[3] > 4030) - { - printf(" Surge not detected correctly (%d)\n", ok); - exit(2); - } - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - printf("Min on %d, max on %d, min off %d, max off %d\n", extremes[0], extremes[1], extremes[2], extremes[3]); - power_surge_detector_free(sig); - awgn_free(awgnx); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int power_surge_detector_file_test(const char *file) -{ - SNDFILE *inhandle; - SNDFILE *outhandle; - int inframes; - power_surge_detector_state_t *sig; - int i; - int16_t amp[8000]; - int16_t amp_out[2*8000]; - int sample; - float signal_power; - int32_t signal_level; - int signal_present; - int prev_signal_present; - - if ((inhandle = sf_open_telephony_read(file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", file); - exit(2); - } - - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - sig = power_surge_detector_init(NULL, -50.0f, 6.0f); - prev_signal_present = false; - - sample = 0; - while ((inframes = sf_readf_short(inhandle, amp, 8000))) - { - for (i = 0; i < inframes; i++) - { - signal_level = power_surge_detector(sig, amp[i]); - signal_present = (signal_level != 0); - if (prev_signal_present != signal_present) - { - signal_power = power_surge_detector_current_dbm0(sig); - if (signal_present) - printf("On at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power); - else - printf("Off at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power); - prev_signal_present = signal_present; - } - amp_out[2*i] = amp[i]; - amp_out[2*i + 1] = signal_present*5000; - } - sf_writef_short(outhandle, amp_out, inframes); - sample += inframes; - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", file); - exit(2); - } - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int power_meter_tests(void) -{ - awgn_state_t noise_source; - power_meter_t meter; - tone_gen_descriptor_t tone_desc; - tone_gen_state_t gen; - int i; - int idum = 1234567; - int16_t amp[1000]; - int len; - int32_t level; - - power_meter_init(&meter, 7); - printf("Testing with zero in the power register\n"); - printf("Power: expected %fdBm0, got %fdBm0\n", -90.169f, power_meter_current_dbm0(&meter)); - printf("Power: expected %fdBOv, got %fdBOv\n", -96.329f, power_meter_current_dbov(&meter)); - - printf("Testing with a square wave 10dB from maximum\n"); - for (i = 0; i < 1000; i++) - { - amp[i] = (i & 1) ? 10362 : -10362; - level = power_meter_update(&meter, amp[i]); - //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter)); - } - printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level); - printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter)); - printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter)); - if (level < power_meter_level_dbov(-10.0f)*0.99f - || - level > power_meter_level_dbov(-10.0f)*1.01f) - { - printf("Test failed (level)\n"); - exit(2); - } - if (0.1f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER)) - { - printf("Test failed (dBm0)\n"); - exit(2); - } - if (0.1f < fabsf(power_meter_current_dbov(&meter) + 10.0)) - { - printf("Test failed (dBOv)\n"); - exit(2); - } - - printf("Testing with a sine wave tone 10dB from maximum\n"); - tone_gen_descriptor_init(&tone_desc, - 1000, - -4, - 0, - 1, - 1, - 0, - 0, - 0, - true); - tone_gen_init(&gen, &tone_desc); - len = tone_gen(&gen, amp, 1000); - for (i = 0; i < len; i++) - { - level = power_meter_update(&meter, amp[i]); - //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter)); - } - printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level); - printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter)); - printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter)); - if (level < power_meter_level_dbov(-10.0f)*0.95f - || - level > power_meter_level_dbov(-10.0f)*1.05f) - { - printf("Test failed (level)\n"); - exit(2); - } - if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER)) - { - printf("Test failed (dBm0)\n"); - exit(2); - } - if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0)) - { - printf("Test failed (dBOv)\n"); - exit(2); - } - - printf("Testing with AWGN 10dB from maximum\n"); - awgn_init_dbov(&noise_source, idum, -10.0f); - for (i = 0; i < 1000; i++) - amp[i] = awgn(&noise_source); - for (i = 0; i < 1000; i++) - { - level = power_meter_update(&meter, amp[i]); - //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter)); - } - printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level); - printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter)); - printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter)); - if (level < power_meter_level_dbov(-10.0f)*0.95f - || - level > power_meter_level_dbov(-10.0f)*1.05f) - { - printf("Test failed (level)\n"); - exit(2); - } - if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER)) - { - printf("Test failed (dBm0)\n"); - exit(2); - } - if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0f)) - { - printf("Test failed (dBOv)\n"); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - bool basic_tests; - bool decode; - int opt; - const char *in_file; - - basic_tests = true; - decode = false; - in_file = IN_FILE_NAME; - while ((opt = getopt(argc, argv, "d:")) != -1) - { - switch (opt) - { - case 'd': - in_file = optarg; - basic_tests = false; - decode = true; - break; - default: - //usage(); - exit(2); - } - } - - if (basic_tests) - { - power_meter_tests(); - power_surge_detector_tests(); - } - if (decode) - { - power_surge_detector_file_test(in_file); - } - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/pseudo_terminal_tests.c b/libs/spandsp/tests/pseudo_terminal_tests.c deleted file mode 100644 index f9f0ed55f6..0000000000 --- a/libs/spandsp/tests/pseudo_terminal_tests.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 (pseudo_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 (pseudo_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 deleted file mode 100644 index 16ae2d74e1..0000000000 --- a/libs/spandsp/tests/pseudo_terminals.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * pseudo_terminals.c - pseudo terminal handling. - * - * 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 -#include -#elif defined(__FreeBSD__) -#include -#include -#else -#include -#endif -#include -#include -#include -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#include "pseudo_terminals.h" - -int next_id = 0; -const char *device_root_name = "/dev/spandsp"; - -int pseudo_terminal_close(modem_t *modem) -{ -#if defined(WIN32) - if (modem->master) - { - CloseHandle(modem->master); - modem->master = 0; - } -#else - if (modem->master > -1) - { - shutdown(modem->master, 2); - close(modem->master); - modem->master = -1; - } -#endif - - if (modem->slave > -1) - { - shutdown(modem->slave, 2); - close(modem->slave); - modem->slave = -1; - } - - if (unlink(modem->devlink)) - return -1; - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int pseudo_terminal_create(modem_t *modem) -{ -#if defined(WIN32) - COMMTIMEOUTS timeouts = {0}; -#endif - - memset(modem, 0, sizeof(*modem)); - - span_log_init(&modem->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&modem->logging, "PTY"); - - span_log_set_level(&modem->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(&modem->logging, "PTY"); - - modem->master = -1; - modem->slave = -1; - -#if USE_OPENPTY - if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL)) - { - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to initialize pty\n"); - return -1; - } - modem->stty = ttyname(modem->slave); -#else -#if defined(WIN32) - modem->slot = 4 + next_id++; /* Need work here. We start at COM4 for now */ - snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot); - - modem->master = CreateFile(modem->devlink, - GENERIC_READ | GENERIC_WRITE, - 0, - 0, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - 0); - if (modem->master == INVALID_HANDLE_VALUE) - { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: Serial port does not exist\n"); - else - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: Serial port open error\n"); - return -1; - } -#elif !defined(HAVE_POSIX_OPENPT) - modem->master = open("/dev/ptmx", O_RDWR); -#else - modem->master = posix_openpt(O_RDWR | O_NOCTTY); -#endif - -#if !defined(WIN32) - if (modem->master < 0) - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n"); - - if (grantpt(modem->master) < 0) - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n"); - - if (unlockpt(modem->master) < 0) - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to unlock slave pty\n"); - - if ((modem->stty = ptsname(modem->master)) == NULL) - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n"); - - if ((modem->slave = open(modem->stty, O_RDWR)) < 0) - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty); -#endif - -#if defined(SOLARIS) - ioctl(modem->slave, I_PUSH, "ptem"); - ioctl(modem->slave, I_PUSH, "ldterm"); -#endif -#endif - -#if defined(WIN32) - timeouts.ReadIntervalTimeout = 50; - timeouts.ReadTotalTimeoutConstant = 50; - timeouts.ReadTotalTimeoutMultiplier = 10; - - timeouts.WriteTotalTimeoutConstant = 50; - timeouts.WriteTotalTimeoutMultiplier = 10; - - SetCommMask(modem->master, EV_RXCHAR); - - if (!SetCommTimeouts(modem->master, &timeouts)) - { - span_log(&modem->logging, SPAN_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink); - pseudo_terminal_close(modem); - return -1; - } - modem->threadAbort = CreateEvent(NULL, true, false, NULL); -#else - modem->slot = next_id++; - snprintf(modem->devlink, sizeof(modem->devlink), "%s/%d", device_root_name, modem->slot); - - /* Remove any stale link which might be present */ - unlink(modem->devlink); - - if (symlink(modem->stty, modem->devlink)) - { - span_log(&modem->logging, SPAN_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink); - pseudo_terminal_close(modem); - return -1; - } - - if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK)) - { - span_log(&modem->logging, SPAN_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master)); - pseudo_terminal_close(modem); - return -1; - } -#endif - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/pseudo_terminals.h b/libs/spandsp/tests/pseudo_terminals.h deleted file mode 100644 index 481530d875..0000000000 --- a/libs/spandsp/tests/pseudo_terminals.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * pseudo_terminals.h - pseudo terminal handling. - * - * 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. - */ - -#if !defined(HAVE_POSIX_OPENPT) && !defined(HAVE_DEV_PTMX) && !defined(WIN32) -#define USE_OPENPTY 1 -#endif - -struct modem_s -{ - int slot; - int master; - int slave; - const char *stty; - char devlink[128]; - int block_read; - int block_write; - logging_state_t logging; -}; - -typedef struct modem_s modem_t; - -int pseudo_terminal_close(modem_t *modem); - -int pseudo_terminal_create(modem_t *modem); diff --git a/libs/spandsp/tests/queue_tests.c b/libs/spandsp/tests/queue_tests.c deleted file mode 100644 index f648b155f8..0000000000 --- a/libs/spandsp/tests/queue_tests.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * queue_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -/*! \page queue_tests_page Queue tests -\section queue_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define BUF_LEN 10000 -#define MSG_LEN 17 - -pthread_t thread[2]; -queue_state_t *queue; -volatile int put_oks; -volatile int put_misses; -volatile int got_oks; -volatile int got_misses; - -int total_in; -int total_out; - -static void tests_failed(void) -{ - printf("Tests failed\n"); - exit(2); -} -/*- End of function --------------------------------------------------------*/ - -static void display_queue_pointers(void) -{ - printf("Pointers %d %d %d\n", queue->iptr, queue->optr, queue->len); -} -/*- End of function --------------------------------------------------------*/ - -static void *run_stream_write(void *arg) -{ - uint8_t buf[MSG_LEN]; - int i; - int next; - - printf("Write thread\n"); - next = 0; - for (i = 0; i < MSG_LEN; i++) - buf[i] = next; - next = (next + 1) & 0xFF; - put_oks = 0; - put_misses = 0; - for (;;) - { - if (queue_write(queue, buf, MSG_LEN) == MSG_LEN) - { - for (i = 0; i < MSG_LEN; i++) - buf[i] = next; - next = (next + 1) & 0xFF; - put_oks++; - if (put_oks%1000000 == 0) - printf("%d puts, %d misses\n", put_oks, put_misses); - } - else - { - sched_yield(); - put_misses++; - } - } - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -static void *run_stream_read(void *arg) -{ - uint8_t buf[MSG_LEN]; - int i; - int len; - int next; - - printf("Read thread\n"); - next = 0; - got_oks = 0; - got_misses = 0; - for (;;) - { - if ((len = queue_read(queue, buf, MSG_LEN)) >= 0) - { - if (len != MSG_LEN) - { - printf("AHH! - len %d\n", len); - tests_failed(); - } - for (i = 0; i < len; i++) - { - if (buf[i] != next) - { - printf("AHH! - 0x%X 0x%X\n", buf[i], next); - tests_failed(); - } - } - next = (next + 1) & 0xFF; - got_oks++; - if (got_oks%1000000 == 0) - printf("%d gots, %d misses\n", got_oks, got_misses); - } - else - { - sched_yield(); - got_misses++; - } - } - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -static void threaded_stream_tests(void) -{ - pthread_attr_t attr; - - if ((queue = queue_init(NULL, BUF_LEN, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC)) == NULL) - { - printf("Failed to create the queue\n"); - tests_failed(); - } - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (pthread_create(&thread[0], &attr, run_stream_write, NULL)) - { - printf("Failed to create thread\n"); - tests_failed(); - } - if (pthread_create(&thread[1], &attr, run_stream_read, NULL)) - { - printf("Failed to create thread\n"); - tests_failed(); - } - for (;;) - { - sleep(5); - printf("Main thread - %d %d\n", put_oks, got_oks); - } - queue_free(queue); -} -/*- End of function --------------------------------------------------------*/ - -static void *run_message_write(void *arg) -{ - uint8_t buf[MSG_LEN]; - int i; - int next; - - printf("Write thread\n"); - next = 0; - for (i = 0; i < MSG_LEN; i++) - buf[i] = next; - next = (next + 1) & 0xFF; - put_oks = 0; - put_misses = 0; - for (;;) - { - if (queue_write_msg(queue, buf, MSG_LEN) == MSG_LEN) - { - for (i = 0; i < MSG_LEN; i++) - buf[i] = next; - next = (next + 1) & 0xFF; - put_oks++; - if (put_oks%1000000 == 0) - printf("%d puts, %d misses\n", put_oks, put_misses); - } - else - { - sched_yield(); - put_misses++; - } - } - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -static void *run_message_read(void *arg) -{ - uint8_t buf[1024]; - int i; - int len; - int next; - - printf("Read thread\n"); - next = 0; - got_oks = 0; - got_misses = 0; - for (;;) - { - if ((len = queue_read_msg(queue, buf, 1024)) >= 0) - { - if (len != MSG_LEN) - { - printf("AHH! - len %d\n", len); - tests_failed(); - } - for (i = 0; i < len; i++) - { - if (buf[i] != next) - { - printf("AHH! - 0x%X 0x%X\n", buf[i], next); - tests_failed(); - } - } - next = (next + 1) & 0xFF; - got_oks++; - if (got_oks%1000000 == 0) - printf("%d gots, %d misses\n", got_oks, got_misses); - } - else - { - sched_yield(); - got_misses++; - } - } - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -static void threaded_message_tests(void) -{ - pthread_attr_t attr; - - if ((queue = queue_init(NULL, BUF_LEN, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC)) == NULL) - { - printf("Failed to create the queue\n"); - tests_failed(); - } - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (pthread_create(&thread[0], &attr, run_message_write, NULL)) - { - printf("Failed to create thread\n"); - tests_failed(); - } - if (pthread_create(&thread[1], &attr, run_message_read, NULL)) - { - printf("Failed to create thread\n"); - tests_failed(); - } - for (;;) - { - sleep(5); - printf("Main thread - %d %d\n", put_oks, got_oks); - } - queue_free(queue); -} -/*- End of function --------------------------------------------------------*/ - -static void check_contents(int total_in, int total_out) -{ - if (queue_contents(queue) != (total_in - total_out)) - { - printf("Contents = %d (%d)\n", queue_contents(queue), (total_in - total_out)); - display_queue_pointers(); - tests_failed(); - } - if (queue_free_space(queue) != BUF_LEN - (total_in - total_out)) - { - printf("Free space = %d (%d)\n", queue_free_space(queue), BUF_LEN - (total_in - total_out)); - display_queue_pointers(); - tests_failed(); - } -} -/*- End of function --------------------------------------------------------*/ - -static int monitored_queue_write(const uint8_t buf[], int len) -{ - int lenx; - - lenx = queue_write(queue, buf, len); - if (lenx >= 0) - total_in += lenx; - check_contents(total_in, total_out); - return lenx; -} -/*- End of function --------------------------------------------------------*/ - -static int monitored_queue_write_byte(const uint8_t buf) -{ - int res; - - if ((res = queue_write_byte(queue, buf)) >= 0) - total_in++; - check_contents(total_in, total_out); - return res; -} -/*- End of function --------------------------------------------------------*/ - -static int monitored_queue_read(uint8_t buf[], int len) -{ - int lenx; - - lenx = queue_read(queue, buf, len); - if (lenx >= 0) - total_out += lenx; - check_contents(total_in, total_out); - return lenx; -} -/*- End of function --------------------------------------------------------*/ - -static int monitored_queue_read_byte(void) -{ - int res; - - if ((res = queue_read_byte(queue)) >= 0) - total_out++; - check_contents(total_in, total_out); - return res; -} -/*- End of function --------------------------------------------------------*/ - -static void functional_stream_tests(void) -{ - uint8_t buf[MSG_LEN]; - int i; - int res; - - total_in = 0; - total_out = 0; - - for (i = 0; i < MSG_LEN; i++) - buf[i] = i; - if ((queue = queue_init(NULL, BUF_LEN, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC)) == NULL) - { - printf("Failed to create the queue\n"); - tests_failed(); - } - check_contents(total_in, total_out); - /* Half fill the buffer, and check we can get out what we put in. */ - for (i = 1; i < 5000; i++) - { - if (monitored_queue_write_byte(i & 0xFF) != 1) - { - printf("Byte by byte full at %d/%d\n", i, BUF_LEN); - tests_failed(); - } - } - for (i = 1; i < 5001; i++) - { - if ((res = monitored_queue_read_byte()) != (i & 0xFF)) - break; - } - printf("Byte by byte read breaks at %d (expected %d) - %d\n", i, 5000, res); - if (i != 5000) - tests_failed(); - /* Now completely fill the buffer, and we should roll around the end. Check we can - get out what we put in. */ - for (i = 1; i < 20000; i++) - { - if (monitored_queue_write_byte(i & 0xFF) != 1) - break; - } - printf("Byte by byte full at %d (expected %d)\n", i, 10001); - if (i != 10001) - tests_failed(); - for (i = 1; i < 20000; i++) - { - if ((res = monitored_queue_read_byte()) != (i & 0xFF)) - break; - } - printf("Byte by byte read breaks at %d (expected %d) - %d\n", i, 10001, res); - if (i != 10001) - tests_failed(); - /* Fill the buffer, checking the contents grow correctly */ - for (i = 1; i < 1000; i++) - { - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - break; - } - printf("Full at chunk %d (expected %d)\n", i, BUF_LEN/MSG_LEN + 1); - if (i != BUF_LEN/MSG_LEN + 1) - tests_failed(); - if (monitored_queue_write(buf, 5) == 5) - { - printf("Write of 5 succeeded\n"); - tests_failed(); - } - if (monitored_queue_write(buf, 4) != 4) - { - printf("Write of 4 failed\n"); - tests_failed(); - } - /* Now full. Empty a little, and refill around the end */ - if (monitored_queue_read(buf, MSG_LEN) != MSG_LEN) - { - printf("Read failed\n"); - tests_failed(); - } - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - { - printf("Write failed\n"); - tests_failed(); - } - /* Empty completely, checking the contents shrink correctly */ - for (;;) - { - if (monitored_queue_read(buf, MSG_LEN) != MSG_LEN) - break; - } - if (monitored_queue_read(buf, 4) != 4) - { - printf("Read failed\n"); - tests_failed(); - } - /* Nudge around the buffer */ - for (i = 1; i < 588; i++) - { - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - { - printf("Write failed\n"); - tests_failed(); - } - if (monitored_queue_read(buf, MSG_LEN) != MSG_LEN) - { - printf("Read failed\n"); - tests_failed(); - } - } - /* Fill the buffer, checking the contents grow correctly */ - for (i = 1; i < 1000; i++) - { - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - break; - } - printf("Full at chunk %d (expected %d)\n", i, BUF_LEN/MSG_LEN + 1); - if (i != BUF_LEN/MSG_LEN + 1) - tests_failed(); - display_queue_pointers(); - if (monitored_queue_read(buf, MSG_LEN) != MSG_LEN) - { - printf("Read failed\n"); - tests_failed(); - } - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - { - printf("Write failed\n"); - tests_failed(); - } - display_queue_pointers(); - for (i = 1; i < 5000; i++) - { - if (monitored_queue_read(buf, MSG_LEN) != MSG_LEN) - { - printf("Read failed\n"); - tests_failed(); - } - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - { - printf("Write failed\n"); - tests_failed(); - } - } - display_queue_pointers(); - if (monitored_queue_write(buf, 5) == 5) - { - printf("Write of 5 succeeded\n"); - tests_failed(); - } - if (monitored_queue_write(buf, 4) != 4) - { - printf("Write of 4 failed\n"); - tests_failed(); - } - display_queue_pointers(); - for (i = 1; i < 5000; i++) - { - if (monitored_queue_read(buf, MSG_LEN) != MSG_LEN) - { - printf("Read failed\n"); - tests_failed(); - } - if (monitored_queue_write(buf, MSG_LEN) != MSG_LEN) - { - printf("Write failed\n"); - tests_failed(); - } - } - display_queue_pointers(); - queue_free(queue); -} -/*- End of function --------------------------------------------------------*/ - -static int monitored_queue_write_msg(const uint8_t buf[], int len) -{ - int lenx; - - lenx = queue_write_msg(queue, buf, len); - if (lenx >= 0) - total_in += lenx + sizeof(uint16_t); - check_contents(total_in, total_out); - return lenx; -} -/*- End of function --------------------------------------------------------*/ - -static int monitored_queue_read_msg(uint8_t buf[], int len) -{ - int lenx; - - lenx = queue_read_msg(queue, buf, len); - if (lenx >= 0) - total_out += lenx + sizeof(uint16_t); - check_contents(total_in, total_out); - return lenx; -} -/*- End of function --------------------------------------------------------*/ - -static void functional_message_tests(void) -{ - uint8_t buf[MSG_LEN]; - int i; - int len; - - total_in = 0; - total_out = 0; - - for (i = 0; i < MSG_LEN; i++) - buf[i] = i; - if ((queue = queue_init(NULL, BUF_LEN, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC)) == NULL) - { - printf("Failed to create the queue\n"); - tests_failed(); - } - check_contents(total_in, total_out); - /* Fill the buffer, checking the contents grow correctly */ - for (i = 1; i < 1000; i++) - { - if (monitored_queue_write_msg(buf, MSG_LEN) != MSG_LEN) - break; - } - printf("Full at chunk %d (expected %lu)\n", i, (unsigned long int) BUF_LEN/(MSG_LEN + sizeof(uint16_t)) + 1); - if (i != BUF_LEN/(MSG_LEN + sizeof(uint16_t)) + 1) - tests_failed(); - if ((len = monitored_queue_write_msg(buf, 5)) == 5) - { - printf("Write of 5 succeeded\n"); - tests_failed(); - } - if ((len = monitored_queue_write_msg(buf, 4)) != 4) - { - printf("Write of 4 failed\n"); - tests_failed(); - } - /* Now full. Empty a little, and refill around the end */ - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - if ((len = monitored_queue_write_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Write failed - %d\n", len); - tests_failed(); - } - /* Empty completely, checking the contents shrink correctly */ - for (;;) - { - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != MSG_LEN) - break; - } - if (len != 4) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - /* We should now have one MSG_LEN message in the buffer */ - /* Nudge around the buffer */ - for (i = 1; i < 527; i++) - { - if ((len = monitored_queue_write_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Write failed - %d\n", len); - tests_failed(); - } - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - } - /* Fill the buffer, checking the contents grow correctly */ - for (i = 1; i < 1000; i++) - { - if ((len = monitored_queue_write_msg(buf, MSG_LEN)) != MSG_LEN) - break; - } - printf("Free space = %d (%d)\n", queue_free_space(queue), BUF_LEN - (total_in - total_out)); - display_queue_pointers(); - printf("Full at chunk %d (expected %lu)\n", i, (unsigned long int) BUF_LEN/(MSG_LEN + sizeof(uint16_t))); - if (i != BUF_LEN/(MSG_LEN + sizeof(uint16_t))) - tests_failed(); - display_queue_pointers(); - - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - if ((len = monitored_queue_write_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Write failed - %d\n", len); - tests_failed(); - } - display_queue_pointers(); - for (i = 1; i < 5000; i++) - { - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - if ((len = monitored_queue_write_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Write failed - %d\n", len); - tests_failed(); - } - } - display_queue_pointers(); - if ((len = monitored_queue_write_msg(buf, 5)) == 5) - { - printf("Write of 5 succeeded\n"); - tests_failed(); - } - if ((len = monitored_queue_write_msg(buf, 4)) != 4) - { - printf("Write of 4 failed\n"); - tests_failed(); - } - display_queue_pointers(); - for (i = 1; i < 5000; i++) - { - if (i == 527) - { - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != 4) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - } - if ((len = monitored_queue_read_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Read failed - %d\n", len); - tests_failed(); - } - if ((len = monitored_queue_write_msg(buf, MSG_LEN)) != MSG_LEN) - { - printf("Write failed - %d\n", len); - tests_failed(); - } - } - display_queue_pointers(); - queue_free(queue); -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - bool threaded_messages; - bool threaded_streams; - int opt; - - threaded_messages = false; - threaded_streams = false; - while ((opt = getopt(argc, argv, "ms")) != -1) - { - switch (opt) - { - case 'm': - threaded_messages = true; - break; - case 's': - threaded_streams = true; - break; - } - } - - /* Test the basic functionality of the queueing code in stream and message modes */ - printf("Stream mode functional tests\n"); - functional_stream_tests(); - printf("Message mode functional tests\n"); - functional_message_tests(); - - /* Run separate write and read threads for a while, to verify there are no locking - issues. */ - if (threaded_streams) - { - printf("Stream mode threaded tests\n"); - threaded_stream_tests(); - } - if (threaded_messages) - { - printf("Message mode threaded tests\n"); - threaded_message_tests(); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/r2_mf_rx_tests.c b/libs/spandsp/tests/r2_mf_rx_tests.c deleted file mode 100644 index 3355677144..0000000000 --- a/libs/spandsp/tests/r2_mf_rx_tests.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * r2_mf_tests.c - Test the R2 MF detector against the spec., whatever the - * spec. may be :) - * - * 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 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 r2_mf_tests_page R2 MF tone generation and detection tests -\section r2_mf_tests_page_sec_1 What does it do? -These tests are fashioned after those on the CM7291 test tape from -Mitel. Those tests are for DTMF, rather than R2 MF, but make a -fair starting point for a set of meaningful tests of R2 MF. - -These tests include conversion to and from A-law. It is assumed the -distortion this produces is comparable to u-law, so it should be -a fair test of performance in a real PSTN channel. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -/* R2 tone generation specs. - * Power: -11.5dBm +- 1dB - * Frequency: within +-4Hz - * Mismatch between the start time of a pair of tones: <=1ms. - * Mismatch between the end time of a pair of tones: <=1ms. - */ -/* Basic MFC/R2 tone detection specs: - * Receiver response range: -5dBm to -35dBm - * Difference in level for a pair of frequencies - * Adjacent tones: <5dB - * Non-adjacent tones: <7dB - * Receiver not to detect a signal of 2 frequencies of level -5dB and - * duration <7ms. - * Receiver not to recognise a signal of 2 frequencies having a difference - * in level >=20dB. - * Max received signal frequency error: +-10Hz - * The sum of the operate and release times of a 2 frequency signal not to - * exceed 80ms (there are no individual specs for the operate and release - * times). - * Receiver not to release for signal interruptions <=7ms. - * System malfunction due to signal interruptions >7ms (typically 20ms) is - * prevented by further logic elements. - */ - -#define MF_DURATION (68*8) -#define MF_PAUSE (68*8) -#define MF_CYCLE (MF_DURATION + MF_PAUSE) - -#define SAMPLES_PER_CHUNK 160 - -/*! - MF tone generator descriptor for tests. -*/ -typedef struct -{ - float f1; /* First freq */ - float f2; /* Second freq */ - int8_t level1; /* Level of the first freq (dB) */ - int8_t level2; /* Level of the second freq (dB) */ - uint8_t on_time; /* Tone on time (ms) */ - uint8_t off_time; /* Minimum post tone silence (ms) */ -} mf_digit_tones_t; - -static const mf_digit_tones_t r2_mf_fwd_tones[] = -{ - {1380.0, 1500.0, -11, -11, 1, 0}, - {1380.0, 1620.0, -11, -11, 1, 0}, - {1500.0, 1620.0, -11, -11, 1, 0}, - {1380.0, 1740.0, -11, -11, 1, 0}, - {1500.0, 1740.0, -11, -11, 1, 0}, - {1620.0, 1740.0, -11, -11, 1, 0}, - {1380.0, 1860.0, -11, -11, 1, 0}, - {1500.0, 1860.0, -11, -11, 1, 0}, - {1620.0, 1860.0, -11, -11, 1, 0}, - {1740.0, 1860.0, -11, -11, 1, 0}, - {1380.0, 1980.0, -11, -11, 1, 0}, - {1500.0, 1980.0, -11, -11, 1, 0}, - {1620.0, 1980.0, -11, -11, 1, 0}, - {1740.0, 1980.0, -11, -11, 1, 0}, - {1860.0, 1980.0, -11, -11, 1, 0}, - {0.0, 0.0, 0, 0, 0, 0} -}; - -static const mf_digit_tones_t r2_mf_back_tones[] = -{ - {1140.0, 1020.0, -11, -11, 1, 0}, - {1140.0, 900.0, -11, -11, 1, 0}, - {1020.0, 900.0, -11, -11, 1, 0}, - {1140.0, 780.0, -11, -11, 1, 0}, - {1020.0, 780.0, -11, -11, 1, 0}, - { 900.0, 780.0, -11, -11, 1, 0}, - {1140.0, 660.0, -11, -11, 1, 0}, - {1020.0, 660.0, -11, -11, 1, 0}, - { 900.0, 660.0, -11, -11, 1, 0}, - { 780.0, 660.0, -11, -11, 1, 0}, - {1140.0, 540.0, -11, -11, 1, 0}, - {1020.0, 540.0, -11, -11, 1, 0}, - { 900.0, 540.0, -11, -11, 1, 0}, - { 780.0, 540.0, -11, -11, 1, 0}, - { 660.0, 540.0, -11, -11, 1, 0}, - {0.0, 0.0, 0, 0, 0, 0} -}; - -static tone_gen_descriptor_t my_mf_digit_tones[16]; - -static char r2_mf_tone_codes[] = "1234567890BCDEF"; - -int callback_ok; -int callback_roll; - -codec_munge_state_t *munge = NULL; - -char *decode_test_file = NULL; - -static void my_mf_gen_init(float low_fudge, - int low_level, - float high_fudge, - int high_level, - int duration, - int fwd) -{ - const mf_digit_tones_t *tone; - int i; - - for (i = 0; i < 15; i++) - { - if (fwd) - tone = &r2_mf_fwd_tones[i]; - else - tone = &r2_mf_back_tones[i]; - tone_gen_descriptor_init(&my_mf_digit_tones[i], - tone->f1*(1.0 + low_fudge), - low_level, - tone->f2*(1.0 + high_fudge), - high_level, - duration, - 0, - 0, - 0, - false); - } -} -/*- End of function --------------------------------------------------------*/ - -static int my_mf_generate(int16_t amp[], char digit) -{ - int len; - char *cp; - tone_gen_state_t *tone; - - len = 0; - if ((cp = strchr(r2_mf_tone_codes, digit))) - { - tone = tone_gen_init(NULL, &my_mf_digit_tones[cp - r2_mf_tone_codes]); - len += tone_gen(tone, amp + len, 9999); - tone_gen_free(tone); - } - return len; -} -/*- End of function --------------------------------------------------------*/ - -static void digit_delivery(void *data, int digit, int level, int delay) -{ - char ch; - - if (data != (void *) 0x12345678) - { - callback_ok = false; - return; - } - if ((callback_roll & 1)) - ch = 0; - else - ch = r2_mf_tone_codes[callback_roll >> 1]; - if (ch == digit) - callback_ok = true; - else - callback_ok = false; - if (r2_mf_tone_codes[callback_roll >> 1]) - callback_roll++; - else - callback_ok = false; -} -/*- End of function --------------------------------------------------------*/ - -static int test_a_tone_set(int fwd) -{ - int i; - int j; - int len; - int sample; - const char *s; - char digit; - int actual; - int nplus; - int nminus; - float rrb; - float rcfo; - int16_t amp[100000]; - r2_mf_rx_state_t *mf_state; - awgn_state_t *noise_source; - - mf_state = r2_mf_rx_init(NULL, fwd, NULL, NULL); - - /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step, - which has no meaning here. */ - - printf("Test 1: Calibration\n"); - printf(" Passed\n"); - - /* Test 2: Decode check - This is a sanity check, that all digits are reliably detected - under ideal conditions. Each possible digit is repeated 10 times, - with 68ms bursts. The level of each tone is about 6dB down from clip */ - - printf("Test 2: Decode check\n"); - my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); - s = r2_mf_tone_codes; - while (*s) - { - digit = *s++; - for (i = 0; i < 10; i++) - { - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - actual = r2_mf_rx_get(mf_state); - if (actual != digit) - { - printf(" Sent '%c'\n", digit); - printf(" Received 0x%X\n", actual); - printf(" Failed\n"); - exit(2); - } - } - } - printf(" Passed\n"); - - /* Test 3: Recognition bandwidth and channel centre frequency check. - Use all digits. Each digit types requires four tests to complete - the check. Each section contains 40 pulses of 68ms duration, - with an amplitude of -20dB from clip per frequency. - - Four sections covering the tests for one tone (1 digit) are: - a. H frequency at 0% deviation from center, L frequency at +0.1%. - L frequency is then increments in +01.% steps up to +4%. The - number of tone bursts is noted and designated N+. - b. H frequency at 0% deviation, L frequency at -0.1%. L frequency - is then incremental in -0.1% steps, up to -4%. The number of - tone bursts is noted and designated N-. - c. The test in (a) is repeated with the L frequency at 0% and the - H frequency varied up to +4%. - d. The test in (b) is repeated with the L frequency and 0% and the - H frequency varied to -4%. - - Receiver Recognition Bandwidth (RRB) is calculated as follows: - RRB% = (N+ + N-)/10 - Receiver Center Frequency Offset (RCFO) is calculated as follows: - RCFO% = X + (N+ - N-)/20 - - Note that this test doesn't test what it says it is testing at all, - and the results are quite inaccurate, if not a downright lie! However, - it follows the Mitel procedure, so how can it be bad? :) - - The spec calls for +-4 +-10Hz (ie +-14Hz) of bandwidth. */ - - printf("Test 3: Recognition bandwidth and channel centre frequency check\n"); - s = r2_mf_tone_codes; - j = 0; - while (*s) - { - digit = *s++; - for (nplus = 0, i = 1; i <= 60; i++) - { - my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, fwd); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) == digit) - nplus++; - } - for (nminus = 0, i = -1; i >= -60; i--) - { - my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, fwd); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) == digit) - nminus++; - } - rrb = (float) (nplus + nminus)/10.0; - rcfo = (float) (nplus - nminus)/10.0; - printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", - digit, - rrb, - rcfo, - (float) nminus/10.0, - (float) nplus/10.0); - - if (rrb < rcfo + (2.0*100.0*14.0/r2_mf_fwd_tones[j].f1) || rrb >= 15.0 + rcfo) - { - printf(" Failed\n"); - exit(2); - } - - for (nplus = 0, i = 1; i <= 60; i++) - { - my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, fwd); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) == digit) - nplus++; - } - for (nminus = 0, i = -1; i >= -60; i--) - { - my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, fwd); - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) == digit) - nminus++; - } - rrb = (float) (nplus + nminus)/10.0; - rcfo = (float) (nplus - nminus)/10.0; - printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", - digit, - rrb, - rcfo, - (float) nminus/10.0, - (float) nplus/10.0); - if (rrb < rcfo + (2.0*100.0*14.0/r2_mf_fwd_tones[j].f2) || rrb >= 15.0 + rcfo) - { - printf(" Failed\n"); - exit(2); - } - j++; - } - printf(" Passed\n"); - - /* Test 4: Acceptable amplitude ratio (twist). - Twist all digits in both directions, and check the maximum twist - we can accept. The way this is done is styled after the Mitel DTMF - test, and has good and bad points. */ - - printf("Test 4: Acceptable amplitude ratio (twist)\n"); - s = r2_mf_tone_codes; - while (*s) - { - digit = *s++; - for (nplus = 0, i = -50; i >= -250; i--) - { - my_mf_gen_init(0.0, -5, 0.0, i/10, 68, fwd); - - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) == digit) - nplus++; - } - printf(" %c normal twist = %.2fdB\n", digit, (float) nplus/10.0); - if (nplus < 70) - { - printf(" Failed\n"); - exit(2); - } - for (nminus = 0, i = -50; i >= -250; i--) - { - my_mf_gen_init(0.0, i/10, 0.0, -5, 68, fwd); - - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) == digit) - nminus++; - } - printf(" %c reverse twist = %.2fdB\n", digit, (float) nminus/10.0); - if (nminus < 70) - { - printf(" Failed\n"); - exit(2); - } - } - printf(" Passed\n"); - - /* Test 5: Dynamic range - This test sends all possible digits, with gradually increasing - amplitude. We determine the span over which we achieve reliable - detection. */ - - printf("Test 5: Dynamic range\n"); - for (nplus = nminus = -1000, i = -50; i <= 3; i++) - { - s = r2_mf_tone_codes; - while (*s) - { - digit = *s++; - my_mf_gen_init(0.0, i, 0.0, i, 68, fwd); - for (j = 0; j < 100; j++) - { - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) != digit) - break; - } - if (j < 100) - break; - } - if (j == 100) - { - if (nplus == -1000) - nplus = i; - } - else - { - if (nplus != -1000 && nminus == -1000) - nminus = i; - } - } - printf(" Dynamic range = %ddB to %ddB\n", nplus, nminus - 1); - if (nplus > -35 || nminus <= -5) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - /* Test 6: Guard time - This test sends all possible digits, with a gradually reducing - duration. */ - - printf("Test 6: Guard time\n"); - for (i = 30; i < 62; i++) - { - s = r2_mf_tone_codes; - j = 0; - while (*s) - { - digit = *s++; - my_mf_gen_init(0.0, -5, 0.0, -3, i, fwd); - for (j = 0; j < 500; j++) - { - len = my_mf_generate(amp, digit); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) != digit) - break; - } - if (j < 500) - break; - } - if (j == 500) - break; - } - printf(" Guard time = %dms\n", i); - if (i > 61) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - /* Test 7: Acceptable signal to noise ratio - We send all possible digits at -6dBm from clip, mixed with AWGN. - We gradually reduce the noise until we get clean detection. */ - - printf("Test 7: Acceptable signal to noise ratio\n"); - my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); - for (i = -3; i > -50; i--) - { - s = r2_mf_tone_codes; - while (*s) - { - digit = *s++; - noise_source = awgn_init_dbm0(NULL, 1234567, (float) i); - for (j = 0; j < 500; j++) - { - len = my_mf_generate(amp, digit); - for (sample = 0; sample < len; sample++) - amp[sample] = sat_add16(amp[sample], awgn(noise_source)); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - if (r2_mf_rx_get(mf_state) != digit) - break; - } - awgn_free(noise_source); - if (j < 500) - break; - } - if (j == 500) - break; - } - printf(" Acceptable S/N ratio is %ddB\n", -3 - i); - if (-3 - i > 26) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - printf("Test 8: Callback digit delivery mode.\n"); - callback_ok = false; - callback_roll = 0; - mf_state = r2_mf_rx_init(mf_state, fwd, digit_delivery, (void *) 0x12345678); - my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); - s = r2_mf_tone_codes; - noise_source = awgn_init_dbm0(NULL, 1234567, -40.0f); - while (*s) - { - digit = *s++; - len = my_mf_generate(amp, digit); - for (sample = 0; sample < len; sample++) - amp[sample] = sat_add16(amp[sample], awgn(noise_source)); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - len = 160; - memset(amp, '\0', len*sizeof(int16_t)); - for (sample = 0; sample < len; sample++) - amp[sample] = sat_add16(amp[sample], awgn(noise_source)); - codec_munge(munge, amp, len); - r2_mf_rx(mf_state, amp, len); - } - awgn_free(noise_source); - if (!callback_ok) - { - printf(" Failed\n"); - exit(2); - } - printf(" Passed\n"); - - r2_mf_rx_free(mf_state); - - /* The remainder of the Mitel tape is the talk-off test. This is - meaningless for R2 MF. However the decoder's tolerance of - out of band noise is significant. */ - /* TODO: add a OOB tolerance test. */ - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void digit_delivery_fwd(void *data, int digit, int level, int delay) -{ - if (data != (void *) 0x12345678) - { - callback_ok = false; - return; - } - printf("FWD '%c' %d %d\n", (digit == 0) ? '-' : digit, level, delay); -} -/*- End of function --------------------------------------------------------*/ - -static void digit_delivery_bwd(void *data, int digit, int level, int delay) -{ - if (data != (void *) 0x12345678) - { - callback_ok = false; - return; - } - printf("BWD '%c' %d %d\n", (digit == 0) ? '-' : digit, level, delay); -} -/*- End of function --------------------------------------------------------*/ - -static void decode_test(const char *test_file) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - SNDFILE *inhandle; - r2_mf_rx_state_t *mf_fwd_state; - r2_mf_rx_state_t *mf_bwd_state; - int samples; - - mf_fwd_state = r2_mf_rx_init(NULL, true, digit_delivery_fwd, (void *) 0x12345678); - mf_bwd_state = r2_mf_rx_init(NULL, false, digit_delivery_bwd, (void *) 0x12345678); - - /* We will decode the audio from a file. */ - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - - while ((samples = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK)) > 0) - { - codec_munge(munge, amp, samples); - r2_mf_rx(mf_fwd_state, amp, samples); - r2_mf_rx(mf_bwd_state, amp, samples); - } -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - time_t now; - time_t duration; - decode_test_file = NULL; - int opt; - - while ((opt = getopt(argc, argv, "d:")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - munge = codec_munge_init(MUNGE_CODEC_ALAW, 0); - if (decode_test_file) - { - decode_test(decode_test_file); - } - else - { - now = time(NULL); - printf("R2 forward tones\n"); - test_a_tone_set(true); - printf("R2 backward tones\n"); - test_a_tone_set(false); - duration = time(NULL) - now; - printf("Tests passed in %lds\n", duration); - } - codec_munge_free(munge); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/r2_mf_tx_tests.c b/libs/spandsp/tests/r2_mf_tx_tests.c deleted file mode 100644 index 0348f799e8..0000000000 --- a/libs/spandsp/tests/r2_mf_tx_tests.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * r2_mf_tx_tests.c - Test the Bell MF generator. - * - * 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 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 r2_mf_tx_tests_page R2 MF generation tests -\section r2_mf_tx_tests_page_sec_1 What does it do? -???. - -\section r2_mf_tx_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "r2_mf.wav" - -int main(int argc, char *argv[]) -{ - r2_mf_tx_state_t gen; - int16_t amp[1000]; - int len; - SNDFILE *outhandle; - int digit; - const char *digits = "0123456789BCDEF"; - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - r2_mf_tx_init(&gen, false); - for (digit = 0; digits[digit]; digit++) - { - r2_mf_tx_put(&gen, digits[digit]); - len = r2_mf_tx(&gen, amp, 1000); - printf("Generated %d samples of %c\n", len, digits[digit]); - if (len > 0) - sf_writef_short(outhandle, amp, len); - r2_mf_tx_put(&gen, 0); - len = r2_mf_tx(&gen, amp, 1000); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - } - - r2_mf_tx_init(&gen, true); - for (digit = 0; digits[digit]; digit++) - { - r2_mf_tx_put(&gen, digits[digit]); - len = r2_mf_tx(&gen, amp, 1000); - printf("Generated %d samples of %c\n", len, digits[digit]); - if (len > 0) - sf_writef_short(outhandle, amp, len); - r2_mf_tx_put(&gen, 0); - len = r2_mf_tx(&gen, amp, 1000); - printf("Generated %d samples\n", len); - if (len > 0) - sf_writef_short(outhandle, amp, len); - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit (2); - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/regression_tests.sh b/libs/spandsp/tests/regression_tests.sh deleted file mode 100755 index 949eca3fcf..0000000000 --- a/libs/spandsp/tests/regression_tests.sh +++ /dev/null @@ -1,745 +0,0 @@ -#!/bin/sh -# -# SpanDSP - a series of DSP components for telephony -# -# regression_tests.sh -# -# 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 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. - -ITUTESTS_TIF=../test-data/itu/fax/itutests.tif -MIXEDSIZES_TIF=../test-data/itu/fax/mixed_size_pages.tif -STDOUT_DEST=xyzzy -STDERR_DEST=xyzzy2 - -echo Performing basic spandsp regression tests -echo - -./ademco_contactid_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo ademco_contactid_tests failed! - exit $RETVAL -fi -echo ademco_contactid_tests completed OK - -./adsi_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo adsi_tests failed! - exit $RETVAL -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 ] -then - echo async_tests failed! - exit $RETVAL -fi -echo async_tests completed OK - -./at_interpreter_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo at_interpreter_tests failed! - exit $RETVAL -fi -echo at_interpreter_tests completed OK - -./awgn_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo awgn_tests failed! - exit $RETVAL -fi -echo awgn_tests completed OK - -./bell_mf_rx_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo bell_mf_rx_tests failed! - exit $RETVAL -fi -echo bell_mf_rx_tests completed OK - -./bell_mf_tx_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo bell_mf_tx_tests failed! - exit $RETVAL -fi -echo bell_mf_tx_tests completed OK - -./bert_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo bert_tests failed! - exit $RETVAL -fi -echo bert_tests completed OK - -./bit_operations_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo bit_operations_tests failed! - exit $RETVAL -fi -echo bit_operations_tests completed OK - -./complex_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo complex_tests failed! - exit $RETVAL -fi -echo complex_tests completed OK - -./complex_vector_float_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo complex_vector_float_tests failed! - exit $RETVAL -fi -echo complex_vector_float_tests completed OK - -./complex_vector_int_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo complex_vector_int_tests failed! - exit $RETVAL -fi -echo complex_vector_int_tests completed OK - -./crc_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo crc_tests failed! - exit $RETVAL -fi -echo crc_tests completed OK - -./dc_restore_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo dc_restore_tests failed! - exit $RETVAL -fi -echo dc_restore_tests completed OK - -./dds_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo dds_tests failed! - exit $RETVAL -fi -echo dds_tests completed OK - -./dtmf_rx_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo dtmf_rx_tests failed! - exit $RETVAL -fi -echo dtmf_rx_tests completed OK - -./dtmf_tx_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo dtmf_tx_tests failed! - exit $RETVAL -fi -echo dtmf_tx_tests completed OK - -#./echo_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo echo_tests failed! -# exit $RETVAL -#fi -#echo echo_tests completed OK -echo echo_tests not enabled - -./fax_tests.sh -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo fax_tests.sh failed! - exit $RETVAL -fi -echo fax_tests.sh completed OK - -./fsk_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo fsk_tests failed! - exit $RETVAL -fi -echo fsk_tests completed OK - -#./g1050_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo g1050_tests failed! -# exit $RETVAL -#fi -#echo g1050_tests completed OK - -./g711_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo g711_tests failed! - exit $RETVAL -fi -echo g711_tests completed OK - -./g722_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo g722_tests failed! - exit $RETVAL -fi -echo g722_tests completed OK - -./g726_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo g726_tests failed! - exit $RETVAL -fi -echo g726_tests completed OK - -./gsm0610_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo gsm0610_tests failed! - exit $RETVAL -fi -echo gsm0610_tests completed OK - -./hdlc_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo hdlc_tests failed! - exit $RETVAL -fi -echo hdlc_tests completed OK - -./ima_adpcm_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo ima_adpcm_tests failed! - exit $RETVAL -fi -echo ima_adpcm_tests completed OK - -./image_translate_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo image_translate_tests failed! - exit $RETVAL -fi -echo image_translate_tests completed OK - -./logging_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo logging_tests failed! - exit $RETVAL -fi -echo logging_tests completed OK - -./lpc10_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo lpc10_tests failed! - exit $RETVAL -fi -echo lpc10_tests completed OK - -./math_fixed_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo math_fixed_tests failed! - exit $RETVAL -fi -echo math_fixed_tests completed OK - -./modem_echo_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo modem_echo_tests failed! - exit $RETVAL -fi -echo modem_echo_tests completed OK - -./modem_connect_tones_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo modem_connect_tones_tests failed! - exit $RETVAL -fi -echo modem_connect_tones_tests completed OK - -./noise_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo noise_tests failed! - exit $RETVAL -fi -echo noise_tests completed OK - -./oki_adpcm_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo oki_adpcm_tests failed! - exit $RETVAL -fi -echo oki_adpcm_tests completed OK - -#./playout_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo playout_tests failed! -# exit $RETVAL -#fi -#echo playout_tests completed OK -echo playout_tests not enabled - -#./plc_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo plc_tests failed! -# exit $RETVAL -#fi -#echo plc_tests completed OK -echo plc_tests not enabled - -./power_meter_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo power_meter_tests failed! - exit $RETVAL -fi -echo power_meter_tests completed OK - -./queue_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo queue_tests failed! - exit $RETVAL -fi -echo queue_tests completed OK - -./r2_mf_rx_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo r2_mf_rx_tests failed! - exit $RETVAL -fi -echo r2_mf_rx_tests completed OK - -./r2_mf_tx_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo r2_mf_tx_tests failed! - exit $RETVAL -fi -echo r2_mf_tx_tests completed OK - -#./rfc2198_sim_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo rfc2198_sim_tests failed! -# exit $RETVAL -#fi -#echo rfc2198_sim_tests completed OK - -./saturated_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo saturated_tests failed! - exit $RETVAL -fi -echo saturated_tests completed OK - -./schedule_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo schedule_tests failed! - exit $RETVAL -fi -echo schedule_tests completed OK - -./sig_tone_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo sig_tone_tests failed! - exit $RETVAL -fi -echo sig_tone_tests completed OK - -#./super_tone_rx_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo super_tone_rx_tests failed! -# exit $RETVAL -#fi -#echo super_tone_rx_tests completed OK -echo super_tone_rx_tests not enabled - -#./super_tone_tx_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo super_tone_tx_tests failed! -# exit $RETVAL -#fi -#echo super_tone_tx_tests completed OK -echo super_tone_tx_tests not enabled - -./swept_tone_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo swept_tone_tests failed! - exit $RETVAL -fi -echo swept_tone_tests completed OK - -./t31_tests -r >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t31_tests -r failed! - exit $RETVAL -fi -./t31_tests -s >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t31_tests -s failed! - exit $RETVAL -fi -echo t31_tests completed OK - -./t35_tests -s >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t35_tests -s failed! - exit $RETVAL -fi -echo t35_tests completed OK - -./t38_core_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t38_core_tests failed! - exit $RETVAL -fi -echo t38_core_tests completed OK - -./t38_non_ecm_buffer_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t38_non_ecm_buffer_tests failed! - exit $RETVAL -fi -echo t38_non_ecm_buffer_tests completed OK - -rm -f t4_tests_receive.tif -./t4_tests -b 0 >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t4_tests failed! - exit $RETVAL -fi -rm -f t4_tests_receive.tif -./t4_tests -b 1 >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t4_tests failed! - exit $RETVAL -fi -rm -f t4_tests_receive.tif -./t4_tests -b 10 >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t4_tests failed! - exit $RETVAL -fi -echo t4_tests completed OK - -rm -f t4_t6_tests_receive.tif -./t4_t6_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t4_t6_tests failed! - exit $RETVAL -fi -echo t4_t6_tests completed OK - -rm -f t81_t82_arith_coding_tests_receive.tif -./t81_t82_arith_coding_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t81_t82_arith_coding_tests failed! - exit $RETVAL -fi -echo t81_t82_arith_coding_tests completed OK - -rm -f t85_tests_receive.tif -./t85_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo t85_tests failed! - exit $RETVAL -fi -echo t85_tests completed OK - -#./time_scale_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo time_scale_tests failed! -# exit $RETVAL -#fi -#echo time_scale_tests completed OK -echo time_scale_tests not enabled - -./timezone_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo timezone_tests failed! - exit $RETVAL -fi -echo timezone_tests completed OK - -#./tone_detect_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo tone_detect_tests failed! -# exit $RETVAL -#fi -#echo tone_detect_tests completed OK -echo tone_detect_tests not enabled - -#./tone_generate_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo tone_generate_tests failed! -# exit $RETVAL -#fi -#echo tone_generate_tests completed OK -echo tone_generate_tests not enabled - -./tsb85_tests.sh >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo ./tsb85_tests.sh failed! - exit $RETVAL -fi -./tsb85_extra_tests.sh -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo ./tsb85_extra_tests.sh failed! - exit $RETVAL -fi -echo tsb85_tests.sh completed OK - -for OPTS in "-b 14400 -s -42 -n -66" "-b 12000 -s -42 -n -61" "-b 9600 -s -42 -n -59" "-b 7200 -s -42 -n -56" -do - ./v17_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo v17_tests ${OPTS} failed! - exit $RETVAL - fi -done -echo v17_tests completed OK - -#for OPTS in "-b 2400" "-b 1200" -#do -# ./v22bis_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST -# RETVAL=$? -# if [ $RETVAL != 0 ] -# then -# echo v22bis_tests ${OPTS} failed! -# exit $RETVAL -# fi -#done -#echo v22bis_tests completed OK -echo v22bis_tests not enabled - -for OPTS in "-b 4800 -s -42 -n -57" "-b 2400 -s -42 -n -51" -do - ./v27ter_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo v27ter_tests ${OPTS} failed! - exit $RETVAL - fi -done -echo v27ter_tests completed OK - -for OPTS in "-b 9600 -s -42 -n -62" "-b 7200 -s -42 -n -59" "-b 4800 -s -42 -n -54" -do - ./v29_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo v29_tests ${OPTS} failed! - exit $RETVAL - fi -done -echo v29_tests completed OK - -#for OPTS in "-b 14400 -s -42 -n -66" "-b 12000 -s -42 -n -61" "-b 9600 -s -42 -n -59" "-b 7200 -s -42 -n -56" -#do -# ./v32bis_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST -# RETVAL=$? -# if [ $RETVAL != 0 ] -# then -# echo v32bis_tests ${OPTS} failed! -# exit $RETVAL -# fi -#done -#echo v32bis_tests completed OK -echo v32bis_tests not enabled - -./v42_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo v42_tests failed! - exit $RETVAL -fi -echo v42_tests completed OK - -./v42bis_tests.sh >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo v42bis_tests.sh failed! - exit $RETVAL -fi -echo v42bis_tests.sh completed OK - -./v8_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo v8_tests failed! - exit $RETVAL -fi -echo v8_tests completed OK - -./v18_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo v18_tests failed! - exit $RETVAL -fi -echo v18_tests completed OK - -./vector_float_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo vector_float_tests failed! - exit $RETVAL -fi -echo vector_float_tests completed OK - -./vector_int_tests >$STDOUT_DEST 2>$STDERR_DEST -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo vector_int_tests failed! - exit $RETVAL -fi -echo vector_int_tests completed OK - -echo -echo All regression tests successfully completed diff --git a/libs/spandsp/tests/rfc2198_sim_tests.c b/libs/spandsp/tests/rfc2198_sim_tests.c deleted file mode 100644 index fe210a2555..0000000000 --- a/libs/spandsp/tests/rfc2198_sim_tests.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * rfc2198_sim_tests.c - Tests for the G.1050/TIA-921 model - * with redundant transmission in the - * style of UDPTL or RFC2198.. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_MATH_H) -#define GEN_CONST -#endif - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif - -#define PACKET_SIZE 256 -#define PACKET_INTERVAL 20 -#define SIMULATION_TIME 300 - -#define MODEL_NO 8 -#define SPEED_PATTERN_NO 133 - -int main(int argc, char *argv[]) -{ - rfc2198_sim_state_t *s; - double *packet_arrival_times; - int packets_per_sec; - int num_packets; - int model_no; - int speed_pattern_no; - int simulation_time; - int i; - int len; - uint8_t put_pkt[256]; - uint8_t get_pkt[256]; - int put_pkt_len; - int get_pkt_len; - int get_seq_no; - double get_departure_time; - double get_arrival_time; - int packets_put; - int packets_really_put; - int packets_got; - int oos_packets_got; - int missing_packets_got; - int highest_seq_no_got; - int opt; - FILE *out_file; -#if defined(ENABLE_GUI) - int use_gui; -#endif - -#if defined(ENABLE_GUI) - use_gui = false; -#endif - model_no = MODEL_NO; - speed_pattern_no = SPEED_PATTERN_NO; - simulation_time = SIMULATION_TIME; - while ((opt = getopt(argc, argv, "gm:s:t:")) != -1) - { - switch (opt) - { - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'm': - model_no = optarg[0] - 'A' + 1; - if (model_no < 0 || model_no > 8) - { - fprintf(stderr, "Bad model ID '%s'\n", optarg); - exit(2); - } - break; - case 's': - speed_pattern_no = atoi(optarg); - if (speed_pattern_no < 1 || speed_pattern_no > 133) - { - fprintf(stderr, "Bad link speed pattern %s\n", optarg); - exit(2); - } - break; - case 't': - simulation_time = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - - if ((out_file = fopen("rfc2198_sim_tests.txt", "w")) == NULL) - { - fprintf(stderr, "Can't open %s\n", "rfc2198_sim_tests.txt"); - return 2; - } - packets_per_sec = 1000/PACKET_INTERVAL; - num_packets = packets_per_sec*simulation_time; - - if ((packet_arrival_times = calloc(num_packets, sizeof(double))) == NULL) - { - fprintf(stderr, "Can't allocate the data buffers\n"); - return 2; - } - for (i = 0; i < num_packets; i++) - packet_arrival_times[i] = 0.0; - - /* If we don't initialise this random number generator it gives endless zeros on some systems. */ - /* Use a fixed seed to produce identical results in successive runs of the simulation, for debug purposes. */ - srand48(0x1234567); - - if ((s = rfc2198_sim_init(model_no, speed_pattern_no, PACKET_SIZE, packets_per_sec, 3)) == NULL) - { - fprintf(stderr, "Failed to start the G.1050 model\n"); - exit(2); - } - //rfc2198_sim_dump_parms(model_no, speed_pattern_no); - -#if defined(ENABLE_GUI) - if (use_gui) - start_media_monitor(); -#endif - - for (i = 0; i < 256; i++) - put_pkt[i] = i; - put_pkt_len = 256; - get_pkt_len = -1; - get_seq_no = -1; - get_arrival_time = -1; - packets_put = 0; - packets_really_put = 0; - packets_got = 0; - oos_packets_got = 0; - missing_packets_got = 0; - highest_seq_no_got = -1; - for (i = 0; i < num_packets; i++) - { - if ((len = rfc2198_sim_put(s, put_pkt, put_pkt_len, i, (double) i*0.001*PACKET_INTERVAL)) > 0) - packets_really_put++; - packets_put++; -#if 0 - if (i == 5) - rfc2198_sim_queue_dump(s); -#endif - if (i >= 5) - { - do - { - get_pkt_len = rfc2198_sim_get(s, get_pkt, 256, (double) i*0.001*PACKET_INTERVAL, &get_seq_no, &get_departure_time, &get_arrival_time); - if (get_pkt_len >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(get_seq_no, get_departure_time, get_arrival_time); -#endif - packets_got++; - if (get_seq_no < highest_seq_no_got) - oos_packets_got++; - else if (get_seq_no > highest_seq_no_got + 1) - missing_packets_got += (get_seq_no - highest_seq_no_got - 1); - if (get_seq_no > highest_seq_no_got) - highest_seq_no_got = get_seq_no; - fprintf(out_file, "%d, %.3f, %.8f\n", get_seq_no, get_seq_no*0.001*PACKET_INTERVAL, get_arrival_time); - } - } - while (get_pkt_len >= 0); - } -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_update_display(); -#endif - } - /* Clear out anything remaining in the queue, by jumping forwards in time */ - do - { - get_pkt_len = rfc2198_sim_get(s, get_pkt, 256, (double) i*0.001*PACKET_INTERVAL + 5.0, &get_seq_no, &get_departure_time, &get_arrival_time); - if (get_pkt_len >= 0) - { - packets_got++; - fprintf(out_file, "%d, %.3f, %.8f\n", get_seq_no, get_seq_no*0.001*PACKET_INTERVAL, get_arrival_time); - } - } - while (get_pkt_len >= 0); - - fclose(out_file); - - rfc2198_sim_free(s); - - free(packet_arrival_times); - - printf("Put %d packets. Really put %d packets. Got %d packets.\n", packets_put, packets_really_put, packets_got); - printf("%d OOS packets, %d missing packets\n", oos_packets_got, missing_packets_got - oos_packets_got); - printf("%d packets queued, %d received\n", packets_really_put, packets_got); - printf("%.3f%% of packets lost before redundancy\n", 100.0*(packets_put - packets_really_put)/packets_put); - printf("%.3f%% of packets lost after redundancy\n", 100.0*(packets_put - packets_got)/packets_put); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/saturated_tests.c b/libs/spandsp/tests/saturated_tests.c deleted file mode 100644 index 67666cede9..0000000000 --- a/libs/spandsp/tests/saturated_tests.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * saturated_tests.c - * - * 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 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. - */ - -/*! \page saturated_tests_page Saturated arithmetic function tests -\section saturated_tests_page_sec_1 What does it do? -???. - -\section saturated_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -#include "spandsp.h" - -int main(int argc, char *argv[]) -{ - printf("Testing 16 bit saturation\n"); - if (saturate16(10000) != 10000 - || - saturate16(-10000) != -10000 - || - saturate16(32767) != 32767 - || - saturate16(-32768) != -32768 - || - saturate16(32768) != 32767 - || - saturate16(-32769) != -32768) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 15 bit saturation\n"); - if (saturate15(10000) != 10000 - || - saturate15(-10000) != -10000 - || - saturate15(16383) != 16383 - || - saturate15(-16384) != -16384 - || - saturate15(16384) != 16383 - || - saturate15(-16385) != -16384) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit unsigned saturation\n"); - if (saturateu16(10000) != 10000 - || - saturateu16(32767) != 32767 - || - saturateu16(65535) != 65535 - || - saturateu16(65536) != 65535) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 8 bit unsigned saturation\n"); - if (saturateu8(100) != 100 - || - saturateu8(127) != 127 - || - saturateu8(255) != 255 - || - saturateu8(256) != 255) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit saturation from float\n"); - if (fsaturatef(10000.0f) != 10000 - || - fsaturatef(-10000.0f) != -10000 - || - fsaturatef(32767.0f) != 32767 - || - fsaturatef(-32768.0f) != -32768 - || - fsaturatef(32768.0f) != 32767 - || - fsaturatef(-32769.0f) != -32768) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit saturation from double\n"); - if (fsaturate(10000.0) != 10000 - || - fsaturate(-10000.0) != -10000 - || - fsaturate(32767.0) != 32767 - || - fsaturate(-32768.0) != -32768 - || - fsaturate(32768.0) != 32767 - || - fsaturate(-32769.0) != -32768) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit fast saturation from float\n"); - if (ffastsaturatef(10000.0f) != 10000 - || - ffastsaturatef(-10000.0f) != -10000 - || - ffastsaturatef(32767.0f) != 32767 - || - ffastsaturatef(-32768.0f) != -32768 - || - ffastsaturatef(32768.0f) != 32767 - || - ffastsaturatef(-32769.0f) != -32768) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit fast saturation from double\n"); - if (ffastsaturate(10000.0) != 10000 - || - ffastsaturate(-10000.0) != -10000 - || - ffastsaturate(32767.0) != 32767 - || - ffastsaturate(-32768.0) != -32768 - || - ffastsaturate(32768.0) != 32767 - || - ffastsaturate(-32769.0) != -32768) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit float saturation from float\n"); - if (ffsaturatef(10000.0f) != 10000.0f - || - ffsaturatef(-10000.0f) != -10000.0f - || - ffsaturatef(32767.0f) != 32767.0f - || - ffsaturatef(-32768.0f) != -32768.0f - || - ffsaturatef(32768.0f) != 32767.0f - || - ffsaturatef(-32769.0f) != -32768.0f) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit double saturation from double\n"); - if (ffsaturate(10000.0) != 10000.0 - || - ffsaturate(-10000.0) != -10000.0 - || - ffsaturate(32767.0) != 32767.0 - || - ffsaturate(-32768.0) != -32768.0 - || - ffsaturate(32768.0) != 32767.0 - || - ffsaturate(-32769.0) != -32768.0) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit add\n"); - if (sat_add16(10000, 10000) != 20000 - || - sat_add16(10000, -10000) != 0 - || - sat_add16(-10000, 10000) != 0 - || - sat_add16(-10000, -10000) != -20000 - || - sat_add16(-30000, -30000) != INT16_MIN - || - sat_add16(30000, 30000) != INT16_MAX - || - sat_add16(-32768, -32768) != INT16_MIN - || - sat_add16(32767, 32767) != INT16_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 32 bit add\n"); - if (sat_add32(10000, 10000) != 20000 - || - sat_add32(10000, -10000) != 0 - || - sat_add32(-10000, 10000) != 0 - || - sat_add32(-10000, -10000) != -20000 - || - sat_add32(-2000000000, -2000000000) != INT32_MIN - || - sat_add32(2000000000, 2000000000) != INT32_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit subtract\n"); - if (sat_sub16(10000, 10000) != 0 - || - sat_sub16(10000, -10000) != 20000 - || - sat_sub16(-10000, 10000) != -20000 - || - sat_sub16(-10000, -10000) != 0 - || - sat_sub16(-30000, 30000) != INT16_MIN - || - sat_sub16(30000, -30000) != INT16_MAX - || - sat_sub16(-32768, 32767) != INT16_MIN - || - sat_sub16(32767, -32768) != INT16_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 32 bit subtract\n"); - if (sat_sub32(10000, 10000) != 0 - || - sat_sub32(10000, -10000) != 20000 - || - sat_sub32(-10000, 10000) != -20000 - || - sat_sub32(-10000, -10000) != 0 - || - sat_sub32(-2000000000, 2000000000) != INT32_MIN - || - sat_sub32(2000000000, -2000000000) != INT32_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 x 16 => 16 bit multiply\n"); - if (sat_mul16(100, 100) != 0 - || - sat_mul16(255, 255) != 1 - || - sat_mul16(32767, -32768) != -32767 - || - sat_mul16(-32768, 32767) != -32767 - || - sat_mul16(32767, 32767) != 32766 - || - sat_mul16(-32768, -32768) != 32767) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 x 16 => 32 bit multiply\n"); - if (sat_mul32_16(100, 100) != 20000 - || - sat_mul32_16(-100, 100) != -20000 - || - sat_mul32_16(32767, -32768) != -2147418112 - || - sat_mul32_16(-32768, 32767) != -2147418112 - || - sat_mul32_16(32767, 32767) != 2147352578 - || - sat_mul32_16(-32768, -32768) != INT32_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 32 + 16 x 16 => 32 bit MAC\n"); - if (sat_mac32_16(123, 100, 100) != 123 + 20000 - || - sat_mac32_16(123, -100, 100) != 123 - 20000 - || - sat_mac32_16(123, 32767, -32768) != 123 - 2147418112 - || - sat_mac32_16(123, -32768, 32767) != 123 - 2147418112 - || - sat_mac32_16(123, 32767, 32767) != 123 + 2147352578 - || - sat_mac32_16(123, -32768, -32768) != INT32_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 32 - 16 x 16 => 32 bit MSU\n"); - if (sat_msu32_16(123, 100, 100) != 123 - 20000 - || - sat_msu32_16(123, -100, 100) != 123 + 20000 - || - sat_msu32_16(123, 32767, -32768) != 123 + 2147418112 - || - sat_msu32_16(123, -32768, 32767) != 123 + 2147418112 - || - sat_msu32_16(123, 32767, 32767) != 123 - 2147352578 - || - sat_msu32_16(123, -32768, -32768) != 123 - INT32_MAX) - { - printf("Test failed.\n"); - exit(2); - } - printf("Testing 16 bit absolute\n"); - if (sat_abs16(10000) != 10000 - || - sat_abs16(-10000) != 10000 - || - sat_abs16(32767) != 32767 - || - sat_abs16(-32768) != 32767) - { - printf("Test failed.\n"); - exit(2); - } - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/schedule_tests.c b/libs/spandsp/tests/schedule_tests.c deleted file mode 100644 index e3aca335bc..0000000000 --- a/libs/spandsp/tests/schedule_tests.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * schedule_tests.c - * - * 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 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. - */ - -/*! \page schedule_tests_page Event scheduler tests -\section schedule_tests_page_sec_1 What does it do? -???. - -\section schedule_tests_page_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -#include "spandsp.h" - -uint64_t when1; -uint64_t when2; - -static void callback1(span_sched_state_t *s, void *user_data) -{ - int id; - uint64_t when; - - when = span_schedule_time(s); - printf("1: Callback at %f %" PRId64 "\n", (float) when/1000000.0, when - when1); - if ((when - when1)) - { - printf("Callback occured at the wrong time.\n"); - exit(2); - } - id = span_schedule_event(s, 500000, callback1, NULL); - when1 = when + 500000; - when = span_schedule_next(s); - printf("1: Event %d, earliest is %" PRId64 "\n", id, when); -} - -static void callback2(span_sched_state_t *s, void *user_data) -{ - int id; - uint64_t when; - - when = span_schedule_time(s); - printf("2: Callback at %f %" PRId64 "\n", (float) when/1000000.0, when - when2); - id = span_schedule_event(s, 550000, callback2, NULL); - if ((when - when2) != 10000) - { - printf("Callback occured at the wrong time.\n"); - exit(2); - } - when2 = when + 550000; - when = span_schedule_next(s); - printf("2: Event %d, earliest is %" PRId64 "\n", id, when); -} - -int main(int argc, char *argv[]) -{ - int i; - span_sched_state_t sched; - uint64_t when; - - span_schedule_init(&sched); - - span_schedule_event(&sched, 500000, callback1, NULL); - span_schedule_event(&sched, 550000, callback2, NULL); - when1 = span_schedule_time(&sched) + 500000; - when2 = span_schedule_time(&sched) + 550000; - //span_schedule_del(&sched, id); - - for (i = 0; i < 100000000; i += 20000) - span_schedule_update(&sched, 20000); - when = span_schedule_time(&sched); - if ((when1 - when) < 0 || (when1 - when) > 500000 || (when2 - when) < 0 || (when2 - when) > 550000) - { - printf("Callback failed to occur.\n"); - exit(2); - } - span_schedule_release(&sched); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/sig_tone_tests.c b/libs/spandsp/tests/sig_tone_tests.c deleted file mode 100644 index 61f93ccb0e..0000000000 --- a/libs/spandsp/tests/sig_tone_tests.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * sig_tone_tests.c - * - * 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 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 sig_tone_tests_page The 2280/2400/2600Hz signalling tone Rx/Tx tests -\section sig_tone_tests_sec_1 What does it do? -???. - -\section sig_tone_tests_sec_2 How does it work? -???. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUT_FILE_NAME "sig_tone.wav" - -#define SAMPLES_PER_CHUNK 160 - -#define MITEL_DIR "../test-data/mitel/" -#define BELLCORE_DIR "../test-data/bellcore/" - -const char *bellcore_files[] = -{ - MITEL_DIR "mitel-cm7291-talkoff.wav", - BELLCORE_DIR "tr-tsy-00763-1.wav", - BELLCORE_DIR "tr-tsy-00763-2.wav", - BELLCORE_DIR "tr-tsy-00763-3.wav", - BELLCORE_DIR "tr-tsy-00763-4.wav", - BELLCORE_DIR "tr-tsy-00763-5.wav", - BELLCORE_DIR "tr-tsy-00763-6.wav", - "" -}; - -typedef struct -{ - double freq; - double min_level; - double max_level; -} template_t; - -static int number_of_tones = 1; - -static int sampleno = 0; -static int tone_1_present = 0; -static int tone_2_present = 0; -static int tx_section = 0; -static int dial_pulses = 0; - -static int rx_handler_callbacks = 0; -static int tx_handler_callbacks = 0; - -static bool use_gui = false; - -static void plot_frequency_response(void) -{ - FILE *gnucmd; - - if ((gnucmd = popen("gnuplot", "w")) == NULL) - { - exit(2); - } - - fprintf(gnucmd, "set autoscale\n"); - fprintf(gnucmd, "unset log\n"); - fprintf(gnucmd, "unset label\n"); - fprintf(gnucmd, "set xtic auto\n"); - fprintf(gnucmd, "set ytic auto\n"); - fprintf(gnucmd, "set title 'Notch filter frequency response'\n"); - fprintf(gnucmd, "set xlabel 'Frequency (Hz)'\n"); - fprintf(gnucmd, "set ylabel 'Gain (dB)'\n"); - fprintf(gnucmd, "plot 'sig_tone_notch' using 1:3 title 'min' with lines," - "'sig_tone_notch' using 1:6 title 'actual' with lines," - "'sig_tone_notch' using 1:9 title 'max' with lines\n"); - fflush(gnucmd); - getchar(); - if (pclose(gnucmd) == -1) - { - exit(2); - } -} -/*- End of function --------------------------------------------------------*/ - -static void tx_handler(void *user_data, int what, int level, int duration) -{ - sig_tone_tx_state_t *s; - int tone; - int time; - static const int pattern_1_tone[][2] = - { - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {600, SIG_TONE_1_PRESENT}, - {0, 0} - }; - static const int pattern_2_tones[][2] = - { -#if 0 - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, - {33, SIG_TONE_1_PRESENT}, - {67, 0}, -#endif - {100, SIG_TONE_1_PRESENT}, - {100, SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT}, - {100, SIG_TONE_2_PRESENT}, -#if 0 - {100, 0}, - {100, SIG_TONE_2_PRESENT}, - {100, SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT}, - {100, SIG_TONE_1_PRESENT}, -#endif - {0, 0} - }; - - s = (sig_tone_tx_state_t *) user_data; - tx_handler_callbacks++; - //printf("What - %d, duration - %d\n", what, duration); - if ((what & SIG_TONE_TX_UPDATE_REQUEST)) - { - /* The sig tone transmit side wants to know what to do next */ - printf("Tx: update request\n"); - - if (number_of_tones == 1) - { - time = pattern_1_tone[tx_section][0]; - tone = pattern_1_tone[tx_section][1]; - } - else - { - time = pattern_2_tones[tx_section][0]; - tone = pattern_2_tones[tx_section][1]; - } - if (time) - { - printf("Tx: [%04x] %s %s for %d samples (%dms)\n", - tone, - (tone & SIG_TONE_1_PRESENT) ? "on " : "off", - (tone & SIG_TONE_2_PRESENT) ? "on " : "off", - ms_to_samples(time), - time); - sig_tone_tx_set_mode(s, tone, ms_to_samples(time)); - tx_section++; - } - else - { - printf("End of sequence\n"); - } - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void rx_handler(void *user_data, int what, int level, int duration) -{ - float ms; - int x; - - rx_handler_callbacks++; - ms = 1000.0f*(float) duration/(float) SAMPLE_RATE; - printf("Rx: [%04x]", what); - x = what & SIG_TONE_1_PRESENT; - if ((what & SIG_TONE_1_CHANGE)) - { - printf(" %s", (x) ? "on " : "off"); - if (x == tone_1_present) - exit(2); - tone_1_present = x; - } - else - { - printf(" ---"); - if (x != tone_1_present) - exit(2); - } - /*endif*/ - x = what & SIG_TONE_2_PRESENT; - if ((what & SIG_TONE_2_CHANGE)) - { - printf(" %s", (x) ? "on " : "off"); - if (x == tone_2_present) - exit(2); - tone_2_present = x; - } - else - { - if (x != tone_2_present) - exit(2); - printf(" ---"); - } - /*endif*/ - printf(" after %d samples (%.3fms)\n", duration, ms); -} -/*- End of function --------------------------------------------------------*/ - -static void map_frequency_response(sig_tone_rx_state_t *s, template_t template[]) -{ - int16_t buf[SAMPLES_PER_CHUNK]; - int i; - int len; - double sumin; - double sumout; - swept_tone_state_t *swept; - double freq; - double gain; - int template_entry; - FILE *file; - - /* Things like noise don't highlight the frequency response of the high Q notch - very well. We use a slowly swept frequency to check it. */ - printf("Frequency response test\n"); - sig_tone_rx_set_mode(s, SIG_TONE_RX_PASSTHROUGH | SIG_TONE_RX_FILTER_TONE, 0); - swept = swept_tone_init(NULL, 200.0f, 3900.0f, -10.0f, 120*SAMPLE_RATE, 0); - template_entry = 0; - file = fopen("sig_tone_notch", "wb"); - for (;;) - { - if ((len = swept_tone(swept, buf, SAMPLES_PER_CHUNK)) <= 0) - break; - /*endif*/ - sumin = 0.0; - for (i = 0; i < len; i++) - sumin += (double) buf[i]*(double) buf[i]; - /*endfor*/ - sig_tone_rx(s, buf, len); - sumout = 0.0; - for (i = 0; i < len; i++) - sumout += (double) buf[i]*(double) buf[i]; - /*endfor*/ - freq = swept_tone_current_frequency(swept); - gain = (sumin != 0.0) ? 10.0*log10(sumout/sumin + 1.0e-10) : 0.0; - printf("%7.1f Hz %.3f dBm0 < %.3f dBm0 < %.3f dBm0\n", - freq, - template[template_entry].min_level, - gain, - template[template_entry].max_level); - if (file) - { - fprintf(file, - "%7.1f Hz %.3f dBm0 < %.3f dBm0 < %.3f dBm0\n", - freq, - template[template_entry].min_level, - gain, - template[template_entry].max_level); - } - /*endif*/ - if (gain < template[template_entry].min_level || gain > template[template_entry].max_level) - { - printf("Expected: %.3f dBm0 to %.3f dBm0\n", - template[template_entry].min_level, - template[template_entry].max_level); - printf(" Failed\n"); - exit(2); - } - /*endif*/ - if (freq > template[template_entry].freq) - template_entry++; - } - /*endfor*/ - swept_tone_free(swept); - if (file) - { - fclose(file); - if (use_gui) - plot_frequency_response(); - /*endif*/ - } - /*endif*/ - printf(" Passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void speech_immunity_tests(sig_tone_rx_state_t *s) -{ - int j; - int total_hits; - SNDFILE *inhandle; - int16_t amp[SAMPLE_RATE]; - int frames; - - printf("Speech immunity test\n"); - total_hits = 0; - for (j = 0; bellcore_files[j][0]; j++) - { - /* Push some silence through, so we should be in the tone off state */ - vec_zeroi16(amp, SAMPLE_RATE); - sig_tone_rx(s, amp, SAMPLE_RATE); - rx_handler_callbacks = 0; - if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) - { - printf(" Cannot open speech file '%s'\n", bellcore_files[j]); - exit(2); - } - /*endif*/ - while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE))) - { - sig_tone_rx(s, amp, frames); - } - /*endwhile*/ - if (sf_close_telephony(inhandle)) - { - printf(" Cannot close speech file '%s'\n", bellcore_files[j]); - exit(2); - } - /*endif*/ - printf(" File %d gave %d false hits.\n", j + 1, rx_handler_callbacks); - total_hits += rx_handler_callbacks; - } - /*endfor*/ - printf(" %d hits in total\n", total_hits); - if (total_hits > 0) - { - printf(" Failed\n"); - exit(2); - } - /*endif*/ - printf(" Passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void level_and_ratio_tests(sig_tone_rx_state_t *s, double pitch[2]) -{ - awgn_state_t noise_source; - int32_t phase_rate[2]; - uint32_t phase[2]; - int16_t gain; - int16_t amp[SAMPLE_RATE]; - int i; - int j; - int k; - int l; - float noise_level; - float tone_level; - power_meter_t noise_meter; - power_meter_t tone_meter; - int16_t noise; - int16_t tone; - - printf("Acceptable level and ratio test - %.2f Hz + %.2f Hz\n", pitch[0], pitch[1]); - for (l = 0; l < 2; l++) - { - phase[l] = 0; - phase_rate[l] = (pitch[l] != 0.0) ? dds_phase_rate(pitch[l]) : 0; - } - for (k = -25; k > -60; k--) - { - noise_level = k; - awgn_init_dbm0(&noise_source, 1234567, noise_level); - tone_level = noise_level; - /* Push some silence through, so we should be in the tone off state */ - vec_zeroi16(amp, SAMPLE_RATE); - sig_tone_rx(s, amp, SAMPLE_RATE); - power_meter_init(&noise_meter, 6); - power_meter_init(&tone_meter, 6); - for (j = 0; j < 20; j++) - { - rx_handler_callbacks = 0; - gain = dds_scaling_dbm0(tone_level); - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - { - noise = awgn(&noise_source); - tone = dds_mod(&phase[0], phase_rate[0], gain, 0); - if (phase_rate[1]) - tone += dds_mod(&phase[1], phase_rate[1], gain, 0); - power_meter_update(&noise_meter, noise); - power_meter_update(&tone_meter, tone); - amp[i] = noise + tone; - } - /*endfor*/ - sig_tone_rx(s, amp, SAMPLES_PER_CHUNK); - if (rx_handler_callbacks) - { - printf("Hit at tone = %.2fdBm0, noise = %.2fdBm0\n", tone_level, noise_level); - printf("Measured tone = %.2fdBm0, noise = %.2fdBm0\n", power_meter_current_dbm0(&tone_meter), power_meter_current_dbm0(&noise_meter)); - if (rx_handler_callbacks != 1) - printf("Callbacks = %d\n", rx_handler_callbacks); - } - /*endif*/ - tone_level += 1.0f; - } - /*endfor*/ - } - /*endfor*/ - printf(" Passed\n"); -} -/*- End of function --------------------------------------------------------*/ - -static void sequence_tests(sig_tone_tx_state_t *tx_state, sig_tone_rx_state_t *rx_state, codec_munge_state_t *munge) -{ - int i; - awgn_state_t noise_source; - SNDFILE *outhandle; - int16_t amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int rx_samples; - int tx_samples; - - printf("Signalling sequence test\n"); - tx_section = 0; - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - /*endif*/ - - awgn_init_dbm0(&noise_source, 1234567, -20.0f); - sig_tone_tx_set_mode(tx_state, SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT | SIG_TONE_TX_PASSTHROUGH, 0); - sig_tone_rx_set_mode(rx_state, SIG_TONE_RX_PASSTHROUGH, 0); - for (sampleno = 0; sampleno < 4000; sampleno += SAMPLES_PER_CHUNK) - { - if (sampleno == 800) - { - /* 100ms seize */ - printf("Tx: [0000] off off for %d samples (%dms)\n", ms_to_samples(100), 100); - dial_pulses = 0; - sig_tone_tx_set_mode(tx_state, 0, ms_to_samples(100)); - } - /*endif*/ - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - amp[i] = awgn(&noise_source); - /*endfor*/ - tx_samples = sig_tone_tx(tx_state, amp, SAMPLES_PER_CHUNK); - for (i = 0; i < tx_samples; i++) - out_amp[2*i] = amp[i]; - /*endfor*/ - codec_munge(munge, amp, tx_samples); - rx_samples = sig_tone_rx(rx_state, amp, tx_samples); - for (i = 0; i < rx_samples; i++) - out_amp[2*i + 1] = amp[i]; - /*endfor*/ - outframes = sf_writef_short(outhandle, out_amp, rx_samples); - if (outframes != rx_samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endfor*/ - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int type; - sig_tone_tx_state_t tx_state; - sig_tone_rx_state_t rx_state; - codec_munge_state_t *munge; - double fc[2]; - int i; - template_t template[10]; - int opt; - - use_gui = false; - while ((opt = getopt(argc, argv, "g")) != -1) - { - switch (opt) - { - case 'g': - use_gui = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - for (type = 1; type <= 3; type++) - { - sampleno = 0; - tone_1_present = 0; - tone_2_present = 0; - munge = NULL; - for (i = 0; i < 10; i++) - { - template[i].freq = 0.0; - template[i].min_level = 0.0; - template[i].max_level = 0.0; - } - fc[0] = - fc[1] = 0.0; - switch (type) - { - case 1: - printf("2280Hz tests.\n"); - munge = codec_munge_init(MUNGE_CODEC_ALAW, 0); - sig_tone_tx_init(&tx_state, SIG_TONE_2280HZ, tx_handler, &tx_state); - sig_tone_rx_init(&rx_state, SIG_TONE_2280HZ, rx_handler, &rx_state); - number_of_tones = 1; - fc[0] = 2280.0; - - /* From BTNR 181 2.3.3.1 */ - template[0].freq = 1150.0; - template[0].min_level = -0.2; - template[0].max_level = 0.0; - template[1].freq = 1880.0; - template[1].min_level = -0.5; - template[1].max_level = 0.0; - template[2].freq = 2080.0; - template[2].min_level = -5.0; - template[2].max_level = 0.0; - template[3].freq = 2280.0 - 20.0; - template[3].min_level = -99.0; - template[3].max_level = 0.0; - template[4].freq = 2280.0 + 20.0; - template[4].min_level = -99.0; - template[4].max_level = -30.0; - template[5].freq = 2480.0; - template[5].min_level = -99.0; - template[5].max_level = 0.0; - template[6].freq = 2680.0; - template[6].min_level = -5.0; - template[6].max_level = 0.0; - template[7].freq = 4000.0; - template[7].min_level = -0.5; - template[7].max_level = 0.0; - break; - case 2: - printf("2600Hz tests.\n"); - munge = codec_munge_init(MUNGE_CODEC_ULAW, 0); - sig_tone_tx_init(&tx_state, SIG_TONE_2600HZ, tx_handler, &tx_state); - sig_tone_rx_init(&rx_state, SIG_TONE_2600HZ, rx_handler, &rx_state); - number_of_tones = 1; - fc[0] = 2600.0; - - template[0].freq = 2600.0 - 200.0; - template[0].min_level = -1.0; - template[0].max_level = 0.0; - template[1].freq = 2600.0 - 20.0; - template[1].min_level = -99.0; - template[1].max_level = 0.0; - template[2].freq = 2600.0 + 20.0; - template[2].min_level = -99.0; - template[2].max_level = -30.0; - template[3].freq = 2600.0 + 200.0; - template[3].min_level = -99.0; - template[3].max_level = 0.0; - template[4].freq = 4000.0; - template[4].min_level = -1.0; - template[4].max_level = 0.0; - break; - case 3: - printf("2400Hz/2600Hz tests.\n"); - munge = codec_munge_init(MUNGE_CODEC_ULAW, 0); - sig_tone_tx_init(&tx_state, SIG_TONE_2400HZ_2600HZ, tx_handler, &tx_state); - sig_tone_rx_init(&rx_state, SIG_TONE_2400HZ_2600HZ, rx_handler, &rx_state); - number_of_tones = 2; - fc[0] = 2400.0; - fc[1] = 2600.0; - - template[0].freq = 2400.0 - 200.0; - template[0].min_level = -1.0; - template[0].max_level = 0.0; - template[1].freq = 2400.0 - 20.0; - template[1].min_level = -99.0; - template[1].max_level = 0.0; - template[2].freq = 2400.0 + 20.0; - template[2].min_level = -99.0; - template[2].max_level = -30.0; - template[3].freq = 2600.0 - 20.0; - template[3].min_level = -99.0; - template[3].max_level = 0.0; - template[4].freq = 2600.0 + 20.0; - template[4].min_level = -99.0; - template[4].max_level = -30.0; - template[5].freq = 2600.0 + 200.0; - template[5].min_level = -99.0; - template[5].max_level = 0.0; - template[6].freq = 4000.0; - template[6].min_level = -1.0; - template[6].max_level = 0.0; - break; - } - /*endswitch*/ - map_frequency_response(&rx_state, template); - speech_immunity_tests(&rx_state); - level_and_ratio_tests(&rx_state, fc); - sequence_tests(&tx_state, &rx_state, munge); - if (munge) - codec_munge_free(munge); - } - /*endfor*/ - - printf("Tests completed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/socket_harness.c b/libs/spandsp/tests/socket_harness.c deleted file mode 100644 index 73b09e230a..0000000000 --- a/libs/spandsp/tests/socket_harness.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * socket_harness.c - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - - -/*! \page bitstream_tests_page Bitstream tests -\section bitstream_tests_page_sec_1 What does it do? - -\section bitstream_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#include "pseudo_terminals.h" -#include "socket_harness.h" - -//#define SIMULATE_RING 1 - -#define CLOSE_COUNT_MAX 100 - -/* static data */ -static int16_t inbuf[4096]; -static int16_t outbuf[4096]; - -static volatile sig_atomic_t keep_running = true; - -static void log_signal(int signum) -{ - fprintf(stderr, "Signal %d: mark termination.\n", signum); - keep_running = false; - exit(2); -} -/*- End of function --------------------------------------------------------*/ - -int terminal_write(void *user_data, const char *buf, int len) -{ - socket_harness_state_t *s; - - s = (socket_harness_state_t *) user_data; - return write(s->pty_fd, buf, len); -} -/*- End of function --------------------------------------------------------*/ - -int socket_harness_run(socket_harness_state_t *s, int kick) -{ - struct timeval tmo; - fd_set rset; - fd_set eset; - struct termios termios; - int max_fd; - int count; - int samples; - int tx_samples; - int ret; - - if (kick) - { - samples = 160; - tx_samples = s->tx_callback(s->user_data, outbuf, samples); - if (tx_samples < samples) - memset(&outbuf[tx_samples], 0, (samples - tx_samples)*2); - - if ((count = write(s->audio_fd, outbuf, samples*2)) < 0) - { - if (errno != EAGAIN) - { - fprintf(stderr, "Error: audio write: %s\n", strerror(errno)); - return -1; - } - /* TODO: */ - } - } - while (keep_running) - { - //if (s->modem->event) - // modem_event(s->modem); -#if defined(SIMULATE_RING) - tmo.tv_sec = 0; - tmo.tv_usec= 1000000/RING_HZ; -#else - tmo.tv_sec = 1; - tmo.tv_usec= 0; -#endif - max_fd = 0; - FD_ZERO(&rset); - FD_ZERO(&eset); - FD_SET(s->audio_fd, &rset); - FD_SET(s->audio_fd, &eset); - FD_SET(s->pty_fd, &rset); - FD_SET(s->pty_fd, &eset); - if (s->audio_fd > max_fd) - max_fd = s->audio_fd; - if (s->pty_fd > max_fd) - max_fd = s->pty_fd; - if (s->pty_closed && s->close_count) - { - if (!s->started || s->close_count++ > CLOSE_COUNT_MAX) - s->close_count = 0; - } - else if (s->terminal_free_space_callback(s->user_data)) - { - FD_SET(s->pty_fd, &rset); - if (s->pty_fd > max_fd) - max_fd = s->pty_fd; - } - if ((ret = select(max_fd + 1, &rset, NULL, &eset, &tmo)) < 0) - { - if (errno == EINTR) - continue; - fprintf(stderr, "Error: select: %s\n", strerror(errno)); - return ret; - } - if (ret == 0) - { - /* Timeout */ -#if defined(SIMULATE_RING) - if (!modem->modem->started) - { - rcount++; - if (rcount <= RING_ON) - modem_ring(modem->modem); - else if (rcount > RING_OFF) - rcount = 0; - } -#endif - continue; - } - - if (FD_ISSET(s->audio_fd, &rset)) - { - if ((count = read(s->audio_fd, inbuf, sizeof(inbuf)/2)) < 0) - { - if (errno != EAGAIN) - { - fprintf(stderr, "Error: audio read: %s\n", strerror(errno)); - return -1; - } - count = 0; - } - if (count == 0) - { - fprintf(stderr, "Audio socket closed\n"); - return 0; - } - samples = count/2; - usleep(125*samples); - - s->rx_callback(s->user_data, inbuf, samples); - tx_samples = s->tx_callback(s->user_data, outbuf, samples); - if (tx_samples < samples) - memset(&outbuf[tx_samples], 0, (samples - tx_samples)*2); - - if ((count = write(s->audio_fd, outbuf, samples*2)) < 0) - { - if (errno != EAGAIN) - { - fprintf(stderr, "Error: audio write: %s\n", strerror(errno)); - return -1; - } - /* TODO: */ - } - if (count != samples*2) - fprintf(stderr, "audio write = %d\n", count); - } - - if (FD_ISSET(s->pty_fd, &rset)) - { - /* Check termios */ - tcgetattr(s->pty_fd, &termios); - if (memcmp(&termios, &s->termios, sizeof(termios))) - s->termios_callback(s->user_data, &termios); - /* Read data */ - if ((count = s->terminal_free_space_callback(s->user_data))) - { - if (count > sizeof(inbuf)) - count = sizeof(inbuf); - if ((count = read(s->pty_fd, inbuf, count)) < 0) - { - if (errno == EAGAIN) - { - fprintf(stderr, "pty read, errno = EAGAIN\n"); - } - else - { - if (errno == EIO) - { - if (!s->pty_closed) - { - fprintf(stderr, "pty closed.\n"); - s->pty_closed = 1; - if ((termios.c_cflag & HUPCL)) - s->hangup_callback(s->user_data, 0); - } - s->close_count = 1; - } - else - { - fprintf(stderr, "Error: pty read: %s\n", strerror(errno)); - return -1; - } - } - } - else - { - if (count == 0) - fprintf(stderr, "pty read = 0\n"); - s->pty_closed = false; - s->terminal_callback(s->user_data, (uint8_t *) inbuf, count); - } - } - } - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -socket_harness_state_t *socket_harness_init(socket_harness_state_t *s, - const char *socket_name, - const char *tag, - int caller, - put_msg_func_t terminal_callback, - termio_update_func_t termios_callback, - modem_status_func_t hangup_callback, - put_msg_free_space_func_t terminal_free_space_callback, - span_rx_handler_t rx_callback, - span_rx_fillin_handler_t rx_fillin_callback, - span_tx_handler_t tx_callback, - void *user_data) -{ - int sockfd; - int listensockfd; - struct sockaddr_un serv_addr; - struct sockaddr_un cli_addr; - socklen_t servlen; - socklen_t clilen; - - if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - fprintf(stderr, "Socket failed - errno = %d\n", errno); - return NULL; - } - - if (s == NULL) - { - if ((s = (socket_harness_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - signal(SIGINT, log_signal); - signal(SIGTERM, log_signal); - - s->terminal_callback = terminal_callback; - s->termios_callback = termios_callback; - s->hangup_callback = hangup_callback; - s->terminal_free_space_callback = terminal_free_space_callback; - - s->rx_callback = rx_callback; - s->rx_fillin_callback = rx_fillin_callback; - s->tx_callback = tx_callback; - - s->user_data = user_data; - - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sun_family = AF_UNIX; - /* This is a generic Unix domain socket. */ - strcpy(serv_addr.sun_path, socket_name); - printf("Creating socket '%s'\n", serv_addr.sun_path); - servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family) + 1; - if (caller) - { - fprintf(stderr, "Connecting to '%s'\n", serv_addr.sun_path); - if (connect(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0) - { - fprintf(stderr, "Connect failed - errno = %d\n", errno); - exit(2); - } - fprintf(stderr, "Connected to '%s'\n", serv_addr.sun_path); - } - else - { - fprintf(stderr, "Listening to '%s'\n", serv_addr.sun_path); - listensockfd = sockfd; - /* The file may or may not exist. Just try to delete it anyway. */ - unlink(serv_addr.sun_path); - if (bind(listensockfd, (struct sockaddr *) &serv_addr, servlen) < 0) - { - fprintf(stderr, "Bind failed - errno = %d\n", errno); - exit(2); - } - listen(listensockfd, 5); - clilen = sizeof(cli_addr); - if ((sockfd = accept(listensockfd, (struct sockaddr *) &cli_addr, &clilen)) < 0) - { - fprintf(stderr, "Accept failed - errno = %d", errno); - exit(2); - } - fprintf(stderr, "Accepted on '%s'\n", serv_addr.sun_path); - } - if (pseudo_terminal_create(&s->modem)) - { - fprintf(stderr, "Failed to create pseudo TTY\n"); - exit(2); - } - s->audio_fd = sockfd; - s->pty_fd = s->modem.master; - return s; -} -/*- End of function --------------------------------------------------------*/ - -int socket_harness_release(socket_harness_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int socket_harness_free(socket_harness_state_t *s) -{ - free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/socket_harness.h b/libs/spandsp/tests/socket_harness.h deleted file mode 100644 index c30485162f..0000000000 --- a/libs/spandsp/tests/socket_harness.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * socket_harness.h - * - * 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. - */ - -typedef int (*termio_update_func_t)(void *user_data, struct termios *termios); - -typedef int (*put_msg_free_space_func_t)(void *user_data); - -typedef struct socket_harness_state_s -{ - void *user_data; - - put_msg_func_t terminal_callback; - termio_update_func_t termios_callback; - modem_status_func_t hangup_callback; - put_msg_free_space_func_t terminal_free_space_callback; - - span_rx_handler_t rx_callback; - span_rx_fillin_handler_t rx_fillin_callback; - span_tx_handler_t tx_callback; - - int audio_fd; - int pty_fd; - logging_state_t logging; - struct termios termios; - - unsigned int delay; - unsigned int started; - unsigned pty_closed; - unsigned close_count; - - modem_t modem; -} socket_harness_state_t; - -int socket_harness_run(socket_harness_state_t *s, int kick); - -int terminal_write(void *user_data, const char *buf, int len); - -socket_harness_state_t *socket_harness_init(socket_harness_state_t *s, - const char *socket_name, - const char *tag, - int caller, - put_msg_func_t terminal_callback, - termio_update_func_t termios_callback, - modem_status_func_t hangup_callback, - put_msg_free_space_func_t terminal_free_space_callback, - span_rx_handler_t rx_callback, - span_rx_fillin_handler_t rx_fillin_callback, - span_tx_handler_t tx_callback, - void *user_data); - -int socket_harness_release(socket_harness_state_t *s); - -int socket_harness_free(socket_harness_state_t *s); diff --git a/libs/spandsp/tests/super_tone_rx_tests.c b/libs/spandsp/tests/super_tone_rx_tests.c deleted file mode 100644 index 01d340c052..0000000000 --- a/libs/spandsp/tests/super_tone_rx_tests.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * super_tone_detect_tests.c - * - * 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 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 super_tone_rx_tests_page Supervisory tone detection tests -\section super_tone_rx_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_LIBXML_XMLMEMORY_H) -#include -#endif -#if defined(HAVE_LIBXML_PARSER_H) -#include -#endif -#if defined(HAVE_LIBXML_XINCLUDE_H) -#include -#endif - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define IN_FILE_NAME "super_tone.wav" - -#define MITEL_DIR "../test-data/mitel/" -#define BELLCORE_DIR "../test-data/bellcore/" - -const char *bellcore_files[] = -{ - MITEL_DIR "mitel-cm7291-talkoff.wav", - BELLCORE_DIR "tr-tsy-00763-1.wav", - BELLCORE_DIR "tr-tsy-00763-2.wav", - BELLCORE_DIR "tr-tsy-00763-3.wav", - BELLCORE_DIR "tr-tsy-00763-4.wav", - BELLCORE_DIR "tr-tsy-00763-5.wav", - BELLCORE_DIR "tr-tsy-00763-6.wav", - "" -}; - -const char *tone_names[20] = {NULL}; - -SNDFILE *inhandle; - -super_tone_rx_segment_t tone_segments[20][10]; - -super_tone_tx_step_t *dialtone_tree = NULL; -super_tone_tx_step_t *ringback_tree = NULL; -super_tone_tx_step_t *busytone_tree = NULL; -super_tone_tx_step_t *nutone_tree = NULL; -super_tone_tx_step_t *congestiontone_tree = NULL; -super_tone_tx_step_t *waitingtone_tree = NULL; - -int level; - -#define SAMPLES_PER_CHUNK 160 - -#if defined(HAVE_LIBXML2) -static int parse_tone(super_tone_rx_descriptor_t *desc, int tone_id, super_tone_tx_step_t **tree, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) -{ - xmlChar *x; - float f1; - float f2; - float f_tol; - float l1; - float l2; - float length; - float length_tol; - float recognition_length; - float recognition_length_tol; - int cycles; - super_tone_tx_step_t *treep; - int min_duration; - int max_duration; - - cur = cur->xmlChildrenNode; - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "step") == 0) - { - printf("Step - "); - /* Set some defaults */ - f1 = 0.0; - f2 = 0.0; - f_tol = 1.0; - l1 = -11.0; - l2 = -11.0; - length = 0.0; - length_tol = 10.0; - recognition_length = 0.0; - recognition_length_tol = 10.0; - cycles = 1; - if ((x = xmlGetProp(cur, (const xmlChar *) "freq"))) - { - sscanf((char *) x, "%f [%f%%]", &f1, &f_tol); - sscanf((char *) x, "%f+%f [%f%%]", &f1, &f2, &f_tol); - printf(" Frequency=%.2f+%.2f [%.2f%%]", f1, f2, f_tol); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "level"))) - { - if (sscanf((char *) x, "%f+%f", &l1, &l2) < 2) - l2 = l1; - printf(" Level=%.2f+%.2f", l1, l2); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "length"))) - { - sscanf((char *) x, "%f [%f%%]", &length, &length_tol); - printf(" Length=%.2f [%.2f%%]", length, length_tol); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "recognition-length"))) - { - sscanf((char *) x, "%f [%f%%]", &recognition_length, &recognition_length_tol); - printf(" Recognition length=%.2f [%.2f%%]", recognition_length, recognition_length_tol); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "cycles"))) - { - if (strcasecmp((char *) x, "endless") == 0) - cycles = 0; - else - cycles = atoi((char *) x); - printf(" Cycles='%d' ", cycles); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "recorded-announcement"))) - printf(" Recorded announcement='%s'", x); - printf("\n"); - if (f1 || f2 || length) - { - /* TODO: This cannot handle cycling patterns */ - if (length == 0.0) - { - if (recognition_length) - min_duration = recognition_length*1000.0 + 0.5; - else - min_duration = 700; - max_duration = 0; - } - else - { - if (recognition_length) - min_duration = recognition_length*1000.0 + 0.5; - else - min_duration = (length*1000.0 + 0.5)*(1.0 - length_tol/100.0) - 30; - max_duration = (length*1000.0 + 0.5)*(1.0 + length_tol/100.0) + 30; - } - printf(">>>Detector element %10d %10d %10d %10d\n", (int) (f1 + 0.5), (int) (f2 + 0.5), min_duration, max_duration); - super_tone_rx_add_element(desc, tone_id, f1 + 0.5, f2 + 0.5, min_duration, max_duration); - } - treep = super_tone_tx_make_step(NULL, - f1, - l1, - f2, - l2, - length*1000.0 + 0.5, - cycles); - *tree = treep; - tree = &treep->next; - parse_tone(desc, tone_id, &treep->nest, doc, ns, cur); - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void parse_tone_set(super_tone_rx_descriptor_t *desc, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) -{ - int tone_id; - - printf("Parsing tone set\n"); - cur = cur->xmlChildrenNode; - while (cur) - { - if (strcmp((char *) cur->name, "dial-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_id = super_tone_rx_add_tone(desc); - dialtone_tree = NULL; - parse_tone(desc, tone_id, &dialtone_tree, doc, ns, cur); - tone_names[tone_id] = "Dial tone"; - } - else if (strcmp((char *) cur->name, "ringback-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_id = super_tone_rx_add_tone(desc); - ringback_tree = NULL; - parse_tone(desc, tone_id, &ringback_tree, doc, ns, cur); - tone_names[tone_id] = "Ringback tone"; - } - else if (strcmp((char *) cur->name, "busy-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_id = super_tone_rx_add_tone(desc); - busytone_tree = NULL; - parse_tone(desc, tone_id, &busytone_tree, doc, ns, cur); - tone_names[tone_id] = "Busy tone"; - } - else if (strcmp((char *) cur->name, "number-unobtainable-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_id = super_tone_rx_add_tone(desc); - nutone_tree = NULL; - parse_tone(desc, tone_id, &nutone_tree, doc, ns, cur); - tone_names[tone_id] = "NU tone"; - } - else if (strcmp((char *) cur->name, "congestion-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_id = super_tone_rx_add_tone(desc); - congestiontone_tree = NULL; - parse_tone(desc, tone_id, &congestiontone_tree, doc, ns, cur); - tone_names[tone_id] = "Congestion tone"; - } - else if (strcmp((char *) cur->name, "waiting-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_id = super_tone_rx_add_tone(desc); - waitingtone_tree = NULL; - parse_tone(desc, tone_id, &waitingtone_tree, doc, ns, cur); - tone_names[tone_id] = "Waiting tone"; - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ -} -/*- End of function --------------------------------------------------------*/ - -static void get_tone_set(super_tone_rx_descriptor_t *desc, const char *tone_file, const char *set_id) -{ - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNsPtr ns; - xmlNodePtr cur; - xmlChar *x; - - ns = NULL; - xmlKeepBlanksDefault(0); - xmlCleanupParser(); - - if ((ctxt = xmlNewParserCtxt()) == NULL) - { - fprintf(stderr, "Failed to allocate parser context\n"); - printf("Test failed\n"); - exit(2); - } - /* parse the file, activating the DTD validation option */ - if ((doc = xmlCtxtReadFile(ctxt, tone_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL) - { - fprintf(stderr, "Failed to read the XML document\n"); - printf("Test failed\n"); - exit(2); - } - if (ctxt->valid == 0) - { - fprintf(stderr, "Failed to validate the XML document\n"); - xmlFreeDoc(doc); - xmlFreeParserCtxt(ctxt); - printf("Test failed\n"); - exit(2); - } - xmlFreeParserCtxt(ctxt); - - /* Check the document is of the right kind */ - if ((cur = xmlDocGetRootElement(doc)) == NULL) - { - fprintf(stderr, "Empty document\n"); - xmlFreeDoc(doc); - exit(2); - } - /*endif*/ - if (xmlStrcmp(cur->name, (const xmlChar *) "global-tones")) - { - fprintf(stderr, "Document of the wrong type, root node != global-tones"); - xmlFreeDoc(doc); - exit(2); - } - /*endif*/ - cur = cur->xmlChildrenNode; - while (cur && xmlIsBlankNode (cur)) - cur = cur->next; - /*endwhile*/ - if (cur == NULL) - exit(2); - /*endif*/ - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "tone-set") == 0) - { - if ((x = xmlGetProp(cur, (const xmlChar *) "uncode"))) - { - if (strcmp((char *) x, set_id) == 0) - parse_tone_set(desc, doc, ns, cur); - } - /*endif*/ - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - xmlFreeDoc(doc); -} -/*- End of function --------------------------------------------------------*/ -#endif - -static void super_tone_rx_fill_descriptor(super_tone_rx_descriptor_t *desc) -{ - int tone_id; - - tone_id = super_tone_rx_add_tone(desc); - super_tone_rx_add_element(desc, tone_id, 400, 0, 700, 0); - tone_names[tone_id] = "XXX"; - - tone_id = super_tone_rx_add_tone(desc); - super_tone_rx_add_element(desc, tone_id, 1100, 0, 400, 600); - super_tone_rx_add_element(desc, tone_id, 0, 0, 2800, 3200); - tone_names[tone_id] = "FAX tone"; -} -/*- End of function --------------------------------------------------------*/ - -static void wakeup(void *data, int code, int level, int delay) -{ - if (code >= 0) - printf("Current tone is %d '%s' '%s'\n", code, (tone_names[code]) ? tone_names[code] : "???", (char *) data); - else - printf("Tone off '%s'\n", (char *) data); -} -/*- End of function --------------------------------------------------------*/ - -static void tone_segment(void *data, int f1, int f2, int duration) -{ - if (f1 < 0) - printf("Result %5d silence\n", duration); - else if (f2 < 0) - printf("Result %5d %4d\n", duration, f1); - else - printf("Result %5d %4d + %4d\n", duration, f1, f2); -} -/*- End of function --------------------------------------------------------*/ - -static int talk_off_tests(super_tone_rx_state_t *super) -{ - int16_t amp[8000]; - int sample; - int frames; - int j; - int x; - - /* Test for voice immunity */ - printf("Talk off tests\n"); - for (j = 0; bellcore_files[j][0]; j++) - { - if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) - { - printf(" Cannot open audio file '%s'\n", bellcore_files[j]); - exit(2); - } - while ((frames = sf_readf_short(inhandle, amp, 8000))) - { - for (sample = 0; sample < frames; ) - { - x = super_tone_rx(super, amp + sample, frames - sample); - sample += x; - } - } - if (sf_close_telephony(inhandle)) - { - printf(" Cannot close speech file '%s'\n", bellcore_files[j]); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int detection_range_tests(super_tone_rx_state_t *super) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - int i; - int j; - uint32_t phase; - int32_t phase_inc; - int scale; - - printf("Detection range tests\n"); - super_tone_rx_tone_callback(super, wakeup, (void *) "test"); - phase = 0; - phase_inc = dds_phase_rate(440.0f); - for (level = -80; level < 0; level++) - { - printf("Testing at %ddBm0\n", level); - scale = dds_scaling_dbm0(level); - for (j = 0; j < 100; j++) - { - for (i = 0; i < SAMPLES_PER_CHUNK; i++) - amp[i] = (dds(&phase, phase_inc)*scale) >> 15; - super_tone_rx(super, amp, SAMPLES_PER_CHUNK); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int file_decode_tests(super_tone_rx_state_t *super, const char *file_name) -{ - int16_t amp[8000]; - int sample; - int frames; - int x; - awgn_state_t noise_source; - - printf("File decode tests\n"); - super_tone_rx_tone_callback(super, wakeup, (void *) "test"); - awgn_init_dbm0(&noise_source, 1234567, -30.0f); - printf("Processing file\n"); - if ((inhandle = sf_open_telephony_read(file_name, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", file_name); - exit(2); - } - while ((frames = sf_readf_short(inhandle, amp, 8000))) - { - /* Add some noise to the signal for a more meaningful test. */ - //for (sample = 0; sample < frames; sample++) - // amp[sample] += sat_add16(amp[sample], awgn (&noise_source)); - for (sample = 0; sample < frames; ) - { - x = super_tone_rx(super, amp + sample, frames - sample); - sample += x; - } - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", file_name); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - const char *file_name; - super_tone_rx_state_t *super; - super_tone_rx_descriptor_t desc; - - super_tone_rx_make_descriptor(&desc); -#if defined(HAVE_LIBXML2) - get_tone_set(&desc, "../spandsp/global-tones.xml", (argc > 1) ? argv[1] : "hk"); -#endif - super_tone_rx_fill_descriptor(&desc); - if ((super = super_tone_rx_init(NULL, &desc, wakeup, (void *) "test")) == NULL) - { - printf(" Failed to create detector.\n"); - exit(2); - } - super_tone_rx_segment_callback(super, tone_segment); - - detection_range_tests(super); - - file_name = IN_FILE_NAME; - file_decode_tests(super, file_name); - - talk_off_tests(super); - - super_tone_rx_free(super); - printf("Done\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/super_tone_tx_tests.c b/libs/spandsp/tests/super_tone_tx_tests.c deleted file mode 100644 index 68d65a7d42..0000000000 --- a/libs/spandsp/tests/super_tone_tx_tests.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * super_tone_generate_tests.c - * - * 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 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 super_tone_tx_tests_page Supervisory tone generation tests -\section super_tone_tx_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_LIBXML_XMLMEMORY_H) -#include -#endif -#if defined(HAVE_LIBXML_PARSER_H) -#include -#endif -#if defined(HAVE_LIBXML_XINCLUDE_H) -#include -#endif - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUT_FILE_NAME "super_tone.wav" - -SNDFILE *outhandle; - -super_tone_tx_step_t *tone_tree = NULL; - -#if defined(HAVE_LIBXML2) -static void play_tones(super_tone_tx_state_t *tone, int max_samples) -{ - int16_t amp[8000]; - int len; - int outframes; - int i; - int total_length; - - i = 500; - total_length = 0; - do - { - len = super_tone_tx(tone, amp, 160); - outframes = sf_writef_short(outhandle, amp, len); - if (outframes != len) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - total_length += len; - } - while (len > 0 && --i > 0); - printf("Tone length = %d samples (%dms)\n", total_length, total_length/8); -} -/*- End of function --------------------------------------------------------*/ - -static int parse_tone(super_tone_tx_step_t **tree, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) -{ - xmlChar *x; - float f1; - float f2; - float f_tol; - float l1; - float l2; - float length; - float length_tol; - int cycles; - super_tone_tx_step_t *treep; - - cur = cur->xmlChildrenNode; - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "step") == 0) - { - printf("Step - "); - /* Set some defaults */ - f1 = 0.0; - f2 = 0.0; - f_tol = 1.0; - l1 = -11.0; - l2 = -11.0; - length = 0.0; - length_tol = 10.0; - cycles = 1; - if ((x = xmlGetProp(cur, (const xmlChar *) "freq"))) - { - sscanf((char *) x, "%f [%f%%]", &f1, &f_tol); - sscanf((char *) x, "%f+%f [%f%%]", &f1, &f2, &f_tol); - printf("Frequency=%.2f+%.2f [%.2f%%]", f1, f2, f_tol); - xmlFree(x); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "level"))) - { - if (sscanf((char *) x, "%f+%f", &l1, &l2) < 2) - l2 = l1; - printf("Level=%.2f+%.2f", l1, l2); - xmlFree(x); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "length"))) - { - sscanf((char *) x, "%f [%f%%]", &length, &length_tol); - printf("Length=%.2f [%.2f%%]", length, length_tol); - xmlFree(x); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "recognition-length"))) - { - printf("Recognition length='%s'", x); - xmlFree(x); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "cycles"))) - { - if (strcasecmp((char *) x, "endless") == 0) - cycles = 0; - else - cycles = atoi((char *) x); - printf("Cycles=%d ", cycles); - xmlFree(x); - } - if ((x = xmlGetProp(cur, (const xmlChar *) "recorded-announcement"))) - { - printf("Recorded announcement='%s'", x); - xmlFree(x); - } - printf("\n"); - treep = super_tone_tx_make_step(NULL, - f1, - l1, - f2, - l2, - length*1000.0 + 0.5, - cycles); - *tree = treep; - tree = &treep->next; - parse_tone(&treep->nest, doc, ns, cur); - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void parse_tone_set(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) -{ - super_tone_tx_state_t tone; - - printf("Parsing tone set\n"); - cur = cur->xmlChildrenNode; - while (cur) - { - if (strcmp((char *) cur->name + strlen((char *) cur->name) - 5, "-tone") == 0) - { - printf("Hit %s\n", cur->name); - tone_tree = NULL; - parse_tone(&tone_tree, doc, ns, cur); - super_tone_tx_init(&tone, tone_tree); -//printf("Len %p %p %d %d\n", (void *) tone.levels[0], (void *) tone_tree, tone_tree->length, tone_tree->tone); - play_tones(&tone, 99999999); - super_tone_tx_free_tone(tone_tree); - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ -} -/*- End of function --------------------------------------------------------*/ - -static void get_tone_set(const char *tone_file, const char *set_id) -{ - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNsPtr ns; - xmlNodePtr cur; - xmlChar *x; - - ns = NULL; - xmlKeepBlanksDefault(0); - xmlCleanupParser(); - - if ((ctxt = xmlNewParserCtxt()) == NULL) - { - fprintf(stderr, "Failed to allocate parser context\n"); - printf("Test failed\n"); - exit(2); - } - /* parse the file, activating the DTD validation option */ - if ((doc = xmlCtxtReadFile(ctxt, tone_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL) - { - fprintf(stderr, "Failed to read the XML document\n"); - printf("Test failed\n"); - exit(2); - } - if (ctxt->valid == 0) - { - fprintf(stderr, "Failed to validate the XML document\n"); - xmlFreeDoc(doc); - xmlFreeParserCtxt(ctxt); - printf("Test failed\n"); - exit(2); - } - xmlFreeParserCtxt(ctxt); - - /* Check the document is of the right kind */ - if ((cur = xmlDocGetRootElement(doc)) == NULL) - { - fprintf(stderr, "Empty document\n"); - xmlFreeDoc(doc); - exit(2); - } - /*endif*/ - if (xmlStrcmp(cur->name, (const xmlChar *) "global-tones")) - { - fprintf(stderr, "Document of the wrong type, root node != global-tones"); - xmlFreeDoc(doc); - exit(2); - } - /*endif*/ - cur = cur->xmlChildrenNode; - while (cur && xmlIsBlankNode(cur)) - cur = cur->next; - /*endwhile*/ - if (cur == NULL) - exit(2); - /*endif*/ - while (cur) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "tone-set") == 0) - { - if ((x = xmlGetProp(cur, (const xmlChar *) "uncode"))) - { - if (strcmp((char *) x, set_id) == 0) - parse_tone_set(doc, ns, cur); - /*endif*/ - xmlFree(x); - } - /*endif*/ - } - /*endif*/ - cur = cur->next; - } - /*endwhile*/ - xmlFreeDoc(doc); -} -/*- End of function --------------------------------------------------------*/ -#endif - -int main(int argc, char *argv[]) -{ - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } -#if defined(HAVE_LIBXML2) - get_tone_set("../spandsp/global-tones.xml", (argc > 1) ? argv[1] : "hk"); -#endif - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - printf("Done\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/swept_tone_tests.c b/libs/spandsp/tests/swept_tone_tests.c deleted file mode 100644 index 8fef132295..0000000000 --- a/libs/spandsp/tests/swept_tone_tests.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * swept_tone_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "swept_tone.wav" - -#define BLOCK_LEN 160 - -int main(int argc, char *argv[]) -{ - int i; - int j; - int outframes; - int len; - SNDFILE *outhandle; - power_meter_t meter; - swept_tone_state_t *s; - int16_t buf[BLOCK_LEN]; - - power_meter_init(&meter, 10); - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - printf("Test with swept tone.\n"); - 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); - for (i = 0; i < len; i++) - power_meter_update(&meter, buf[i]); - outframes = sf_writef_short(outhandle, buf, len); - if (outframes != len) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } -#if 0 - printf("Current freq %.1fHz, Level is %fdBOv/%fdBm0\n", - swept_tone_current_frequency(s), - power_meter_current_dbov(&meter), - power_meter_current_dbm0(&meter)); -#else - printf("%.1f %f\n", - swept_tone_current_frequency(s), - power_meter_current_dbm0(&meter)); -#endif - } - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - swept_tone_free(s); - - power_meter_release(&meter); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t31_pseudo_terminal_tests.c b/libs/spandsp/tests/t31_pseudo_terminal_tests.c deleted file mode 100644 index bc7544a2dd..0000000000 --- a/libs/spandsp/tests/t31_pseudo_terminal_tests.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t31_pseudo_terminal_tests.c - - * - * 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 -#include -#elif defined(__FreeBSD__) -#include -#include -#include -#else -#include -#endif -#include -#include -#include -#include -#endif - -#include "spandsp.h" - -#include "spandsp-sim.h" - -#undef SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "pseudo_terminals.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif -#include "fax_utils.h" - -#define INPUT_FILE_NAME "../test-data/itu/fax/itutests.tif" -#define OUTPUT_FILE_NAME "t31_pseudo_terminal.tif" -#define OUTPUT_WAVE_FILE_NAME "t31_tests.wav" - -#define MANUFACTURER "www.soft-switch.org" - -#define SAMPLES_PER_CHUNK 160 - -typedef enum -{ - MODEM_POLL_READ = (1 << 0), - MODEM_POLL_WRITE = (1 << 1), - MODEM_POLL_ERROR = (1 << 2) -} modem_poll_t; - -g1050_state_t *path_a_to_b; -g1050_state_t *path_b_to_a; - -double when = 0.0; - -int t38_mode = false; - -struct modem_s modem[10]; - -char *decode_test_file = NULL; -int countdown = 0; -int answered = 0; -int done = false; - -int test_seq_ptr = 0; - -t31_state_t *t31_state; - -static int phase_b_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B", ch); - printf("%c: Phase B handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_rx_parameters(s, tag); - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static int phase_d_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D", ch); - printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_page_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static void phase_e_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E", ch); - printf("Phase E handler on channel %c\n", ch); - fax_log_final_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); -} -/*- End of function --------------------------------------------------------*/ - -static int at_tx_handler(void *user_data, const uint8_t *buf, size_t len) -{ -#if defined(WIN32) - DWORD res; - OVERLAPPED o; -#else - int res; -#endif - modem_t *modem; - -int i; - -printf("YYZ %d - ", (int) len); -for (i = 0; i < len; i++) - printf(" 0x%02x", buf[i]); -printf("\n"); - - modem = (modem_t *) user_data; -#if defined(WIN32) - o.hEvent = CreateEvent(NULL, true, false, NULL); - /* Initialize the rest of the OVERLAPPED structure to zero. */ - o.Internal = 0; - o.InternalHigh = 0; - o.Offset = 0; - o.OffsetHigh = 0; - assert(o.hEvent); - if (!WriteFile(modem->master, buf, (DWORD) len, &res, &o)) - GetOverlappedResult(modem->master, &o, &res, true); - CloseHandle(o.hEvent); -#else - res = write(modem->master, buf, len); -#endif - if (res != len) - { - printf("Failed to write the whole buffer to the device. %d bytes of %d written: %s\n", res, (int) len, strerror(errno)); - - if (res == -1) - res = 0; -#if !defined(WIN32) - if (tcflush(modem->master, TCOFLUSH)) - printf("Unable to flush pty master buffer: %s\n", strerror(errno)); - else if (tcflush(modem->slave, TCOFLUSH)) - printf("Unable to flush pty slave buffer: %s\n", strerror(errno)); - else - printf("Successfully flushed pty buffer\n"); -#endif - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t31_call_control(t31_state_t *s, void *user_data, int op, const char *num) -{ - uint8_t x[2]; - modem_t *modem; - - printf("Modem control - %s", at_modem_control_to_str(op)); - modem = (modem_t *) user_data; - switch (op) - { - case AT_MODEM_CONTROL_CALL: - printf(" %s", num); - t31_call_event(t31_state, AT_CALL_EVENT_CONNECTED); - answered = 2; - break; - case AT_MODEM_CONTROL_ANSWER: - answered = 1; - break; - case AT_MODEM_CONTROL_HANGUP: - //done = true; - break; - case AT_MODEM_CONTROL_OFFHOOK: - break; - case AT_MODEM_CONTROL_DTR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RTS: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CTS: - printf(" %d", (int) (intptr_t) num); - /* Use XON/XOFF characters for flow control */ - switch (t31_state->at_state.dte_dce_flow_control) - { - case 1: - x[0] = (num) ? 0x11 : 0x13; - at_tx_handler(user_data, x, 1); - break; - case 2: - break; - } - /*endswitch*/ - modem->block_read = (num == NULL); - break; - case AT_MODEM_CONTROL_CAR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RNG: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DSR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_SETID: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RESTART: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - printf(" %d", (int) (intptr_t) num); - break; - } - /*endswitch*/ - printf("\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - int i; - - /* This routine queues messages between two instances of T.38 processing, from the T.38 terminal side. */ - 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); - - for (i = 0; i < count; i++) - { - if (g1050_put(path_a_to_b, buf, len, s->tx_seq_no, when) < 0) - printf("Lost packet %d\n", s->tx_seq_no); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t31_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - int i; - - /* This routine queues messages between two instances of T.38 processing, from the T.31 modem side. */ - 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); - - for (i = 0; i < count; i++) - { - if (g1050_put(path_b_to_a, buf, len, s->tx_seq_no, when) < 0) - printf("Lost packet %d\n", s->tx_seq_no); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(WIN32) -static int modem_wait_sock(modem_t *modem, int ms, modem_poll_t flags) -{ - /* This method ignores ms and waits infinitely */ - DWORD dwEvtMask; - DWORD dwWait; - DWORD comerrors; - OVERLAPPED o; - BOOL result; - int ret; - HANDLE arHandles[2]; - - ret = MODEM_POLL_ERROR; - arHandles[0] = modem->threadAbort; - - o.hEvent = CreateEvent(NULL, true, false, NULL); - arHandles[1] = o.hEvent; - - /* Initialize the rest of the OVERLAPPED structure to zero. */ - o.Internal = 0; - o.InternalHigh = 0; - o.Offset = 0; - o.OffsetHigh = 0; - assert(o.hEvent); - - if ((result = WaitCommEvent(modem->master, &dwEvtMask, &o)) == 0) - { - if (GetLastError() != ERROR_IO_PENDING) - { - /* Something went horribly wrong with WaitCommEvent(), so - clear all errors and try again */ - ClearCommError(modem->master, &comerrors, 0); - } - else - { - /* IO is pending, wait for it to finish */ - dwWait = WaitForMultipleObjects(2, arHandles, false, INFINITE); - if (dwWait == WAIT_OBJECT_0 + 1 && !modem->block_read) - ret = MODEM_POLL_READ; - } - } - else - { - if (!modem->block_read) - ret = MODEM_POLL_READ; - } - - CloseHandle (o.hEvent); - return ret; -} -/*- End of function --------------------------------------------------------*/ -#else -static int modem_wait_sock(int sock, uint32_t ms, modem_poll_t flags) -{ - struct pollfd pfds[2] = {{0}}; - int s; - int ret; - - pfds[0].fd = sock; - - if ((flags & MODEM_POLL_READ)) - pfds[0].events |= POLLIN; - if ((flags & MODEM_POLL_WRITE)) - pfds[0].events |= POLLOUT; - if ((flags & MODEM_POLL_ERROR)) - pfds[0].events |= POLLERR; - - s = poll(pfds, (modem->block_read) ? 0 : 1, ms); - - ret = 0; - if (s < 0) - { - ret = s; - } - else if (s > 0) - { - if ((pfds[0].revents & POLLIN)) - ret |= MODEM_POLL_READ; - if ((pfds[0].revents & POLLOUT)) - ret |= MODEM_POLL_WRITE; - if ((pfds[0].revents & POLLERR)) - ret |= MODEM_POLL_ERROR; - } - - return ret; - -} -/*- End of function --------------------------------------------------------*/ -#endif - -static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int test_sending, int g1050_model_no, int g1050_speed_pattern_no) -{ - t38_terminal_state_t *t38_state; - fax_state_t *fax_state; - uint8_t msg[1024]; - char buf[1024]; - int len; - int msg_len; - int t30_len; - int t31_len; - int t38_version; - int without_pacing; - int use_tep; - int seq_no; - double tx_when; - double rx_when; - t30_state_t *t30; - t38_core_state_t *t38_core; - logging_state_t *logging; - int k; - int outframes; - int ret; - int16_t t30_amp[SAMPLES_PER_CHUNK]; - int16_t t31_amp[SAMPLES_PER_CHUNK]; - int16_t silence[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - SNDFILE *wave_handle; - SNDFILE *in_handle; - at_state_t *at_state; -#if defined(WIN32) - DWORD read_bytes; - OVERLAPPED o; -#endif - - /* Test the T.31 modem against the full FAX machine in spandsp */ - - /* Set up the test environment */ - t38_version = 1; - without_pacing = false; - use_tep = false; - - wave_handle = NULL; - if (log_audio) - { - if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - in_handle = NULL; - if (decode_test_file) - { - if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", decode_test_file); - exit(2); - } - } - - srand48(0x1234567); - if ((path_a_to_b = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL) - { - fprintf(stderr, "Failed to start IP network path model\n"); - exit(2); - } - if ((path_b_to_a = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL) - { - fprintf(stderr, "Failed to start IP network path model\n"); - exit(2); - } - - t38_state = NULL; - fax_state = NULL; - if (test_sending) - { - if (t38_mode) - { - 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); - } - t30 = t38_terminal_get_t30_state(t38_state); - } - else - { - fax_state = fax_init(NULL, false); - t30 = fax_get_t30_state(fax_state); - } - t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); - countdown = 0; - } - else - { - if (t38_mode) - { - 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); - } - t30 = t38_terminal_get_t30_state(t38_state); - } - else - { - fax_state = fax_init(NULL, true); - t30 = fax_get_t30_state(fax_state); - } - t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1); - countdown = 250; - } - - t30_set_ecm_capability(t30, use_ecm); - - if (t38_mode) - { - t38_core = t38_terminal_get_t38_core_state(t38_state); - t38_set_t38_version(t38_core, t38_version); - t38_terminal_set_config(t38_state, without_pacing); - t38_terminal_set_tep_mode(t38_state, use_tep); - } - - t30_set_tx_ident(t30, "11111111"); - t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); - //t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); - t30_set_phase_b_handler(t30, phase_b_handler, (void *) t30); - t30_set_phase_d_handler(t30, phase_d_handler, (void *) t30); - t30_set_phase_e_handler(t30, phase_e_handler, (void *) t30); - - if (t38_mode) - logging = t38_terminal_get_logging_state(t38_state); - else - logging = t30_get_logging_state(t30); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, (t38_mode) ? "T.38" : "FAX"); - - if (t38_mode) - { - t38_core = t38_terminal_get_t38_core_state(t38_state); - logging = t38_core_get_logging_state(t38_core); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - - logging = t30_get_logging_state(t30); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - } - else - { - logging = fax_get_logging_state(fax_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "FAX"); - } - - memset(silence, 0, sizeof(silence)); - memset(t30_amp, 0, sizeof(t30_amp)); - - /* Now set up and run the T.31 modem */ - if ((t31_state = t31_init(NULL, at_tx_handler, &modem[0], t31_call_control, &modem[0], t31_tx_packet_handler, NULL)) == NULL) - { - fprintf(stderr, " Cannot start the T.31 modem\n"); - exit(2); - } - at_state = t31_get_at_state(t31_state); - - logging = t31_get_logging_state(t31_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.31"); - - logging = at_get_logging_state(at_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.31"); - - if (t38_mode) - { - t38_core = t31_get_t38_core_state(t31_state); - logging = t38_core_get_logging_state(t38_core); - 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); - t38_set_t38_version(t38_core, t38_version); - } - - at_reset_call_info(at_state); - at_set_call_info(at_state, "DATE", "1231"); - at_set_call_info(at_state, "TIME", "1200"); - at_set_call_info(at_state, "NAME", "Name"); - at_set_call_info(at_state, "NMBR", "123456789"); - at_set_call_info(at_state, "ANID", "987654321"); - at_set_call_info(at_state, "USER", "User"); - at_set_call_info(at_state, "CDID", "234567890"); - at_set_call_info(at_state, "NDID", "345678901"); - -#if defined(ENABLE_GUI) - if (use_gui) - start_media_monitor(); -#endif - - while (!done) - { - /* Deal with call setup, through the AT interface. */ - if (test_sending) - { - } - else - { - if (answered == 0) - { - if (--countdown == 0) - { - t31_call_event(t31_state, AT_CALL_EVENT_ALERTING); - countdown = 250; - } - } - else if (answered == 1) - { -printf("ZZZ\n"); - answered = 2; - t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED); - } - } - - ret = modem_wait_sock(modem[0].master, 20, MODEM_POLL_READ); - if ((ret & MODEM_POLL_READ)) - { -#if defined(WIN32) - o.hEvent = CreateEvent(NULL, true, false, NULL); - - /* Initialize the rest of the OVERLAPPED structure to zero. */ - o.Internal = 0; - o.InternalHigh = 0; - o.Offset = 0; - o.OffsetHigh = 0; - assert(o.hEvent); - if (!ReadFile(modem->master, buf, avail, &read_bytes, &o)) - GetOverlappedResult(modem->master, &o, &read_bytes, true); - CloseHandle (o.hEvent); - if ((len = read_bytes)) -#else - if ((len = read(modem[0].master, buf, 1024))) -#endif -{ -int i; - -printf("YYY %d - ", len); -for (i = 0; i < len; i++) - printf(" 0x%02x", buf[i] & 0xFF); -printf("\n"); - t31_at_rx(t31_state, buf, len); -} - } - - if (answered == 2) - { - if (t38_mode) - { - while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(seq_no, tx_when, rx_when); -#endif - t38_core = t31_get_t38_core_state(t31_state); - t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); - } - while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(seq_no, tx_when, rx_when); -#endif - t38_core = t38_terminal_get_t38_core_state(t38_state); - t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); - } -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_update_display(); -#endif - /* Bump the G.1050 models along */ - when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE; - - /* Bump things along on the t38_terminal side */ - span_log_bump_samples(t38_terminal_get_logging_state(t38_state), SAMPLES_PER_CHUNK); - t38_core = t38_terminal_get_t38_core_state(t38_state); - span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK); - - t38_terminal_send_timeout(t38_state, SAMPLES_PER_CHUNK); - t31_t38_send_timeout(t31_state, SAMPLES_PER_CHUNK); - } - else - { - t30_len = fax_tx(fax_state, t30_amp, SAMPLES_PER_CHUNK); - /* The receive side always expects a full block of samples, but the - transmit side may not be sending any when it doesn't need to. We - may need to pad with some silence. */ - if (t30_len < SAMPLES_PER_CHUNK) - { - memset(t30_amp + t30_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len)); - t30_len = SAMPLES_PER_CHUNK; - } - if (log_audio) - { - for (k = 0; k < t30_len; k++) - out_amp[2*k] = t30_amp[k]; - } - if (t31_rx(t31_state, t30_amp, t30_len)) - break; - t31_len = t31_tx(t31_state, t31_amp, SAMPLES_PER_CHUNK); - if (t31_len < SAMPLES_PER_CHUNK) - { - memset(t31_amp + t31_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t31_len)); - t31_len = SAMPLES_PER_CHUNK; - } - if (log_audio) - { - for (k = 0; k < t31_len; k++) - out_amp[2*k + 1] = t31_amp[k]; - } - if (fax_rx(fax_state, t31_amp, SAMPLES_PER_CHUNK)) - break; - - if (log_audio) - { - outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - break; - } - - /* Bump things along on the FAX machine side */ - span_log_bump_samples(fax_get_logging_state(fax_state), SAMPLES_PER_CHUNK); - } - /* Bump things along on the FAX machine side */ - span_log_bump_samples(t30_get_logging_state(t30), SAMPLES_PER_CHUNK); - - /* Bump things along on the T.31 modem side */ - t38_core = t31_get_t38_core_state(t31_state); - span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK); - span_log_bump_samples(t31_get_logging_state(t31_state), SAMPLES_PER_CHUNK); - span_log_bump_samples(at_get_logging_state(t31_get_at_state(t31_state)), SAMPLES_PER_CHUNK); - } - } - - if (t38_mode) - t38_terminal_release(t38_state); - - if (decode_test_file) - { - if (sf_close_telephony(in_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - if (!done) - { - printf("Tests failed\n"); - return 2; - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int log_audio; - int t38_mode; - int test_sending; - int use_ecm; - int use_gui; - int g1050_model_no; - int g1050_speed_pattern_no; - int opt; -#if !defined(WIN32) - int tioflags; -#endif - - decode_test_file = NULL; - 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) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - case 'e': - use_ecm = true; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - case 'M': - g1050_model_no = optarg[0] - 'A' + 1; - break; - case 'r': - test_sending = false; - break; - case 'S': - g1050_speed_pattern_no = atoi(optarg); - break; - case 's': - test_sending = true; - break; - case 't': - t38_mode = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - if (pseudo_terminal_create(&modem[0])) - printf("Failure\n"); - -#if !defined(WIN32) - ioctl(modem[0].slave, TIOCMGET, &tioflags); - tioflags |= TIOCM_RI; - ioctl(modem[0].slave, TIOCMSET, &tioflags); -#endif - - t30_tests(t38_mode, use_ecm, use_gui, log_audio, test_sending, g1050_model_no, g1050_speed_pattern_no); - if (pseudo_terminal_close(&modem[0])) - printf("Failure\n"); - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t31_tests.c b/libs/spandsp/tests/t31_tests.c deleted file mode 100644 index beff7f9cce..0000000000 --- a/libs/spandsp/tests/t31_tests.c +++ /dev/null @@ -1,953 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t31_tests.c - Tests for the T.31 modem. - * - * 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 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 t31_tests_page T.31 tests -\section t31_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp/t30_fcf.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "media_monitor.h" -#endif -#include "fax_utils.h" - -#define INPUT_FILE_NAME "../test-data/itu/fax/itu1.tif" -#define OUTPUT_FILE_NAME "t31.tif" -#define OUTPUT_WAVE_FILE_NAME "t31_tests.wav" - -enum -{ - ETX = 0x03, - DLE = 0x10, - SUB = 0x1A -}; - -#define MANUFACTURER "www.soft-switch.org" - -#define SAMPLES_PER_CHUNK 160 - -struct command_response_s -{ - const char *command; - int len_command; - const char *response; - int len_response; -}; - -g1050_state_t *path_a_to_b; -g1050_state_t *path_b_to_a; - -double when = 0.0; - -int t38_mode = false; - -#define EXCHANGE(a,b) {a, sizeof(a) - 1, b, sizeof(b) - 1} -#define RESPONSE(b) {"", 0, b, sizeof(b) - 1} -#define FAST_RESPONSE(b) {NULL, -1, b, sizeof(b) - 1} -#define FAST_SEND(b) {(const char *) 1, -2, b, sizeof(b) - 1} -#define FAST_SEND_TCF(b) {(const char *) 2, -2, b, sizeof(b) - 1} -#define END_OF_SEQUENCE {NULL, -1, NULL, -1} - -static const struct command_response_s fax_send_test_seq[] = -{ - EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), - EXCHANGE("AT+FCLASS=1\r", "\r\nOK\r\n"), - EXCHANGE("ATD123456789\r", "\r\nCONNECT\r\n"), - // AT+FRH=3 is implied when dialing in the AT+FCLASS=1 state - //RESPONSE("\xFF\x03\x10\x03"), - //RESPONSE("\r\nOK\r\n"), - //EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x03\x40\x31\x31\x31\x31\x31\x31\x31\x31\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x1e\x46\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // -#if 1 - 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\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"), - EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x03\x43\x32\x32\x32\x32\x32\x32\x32\x32\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x10\x03", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x13\x83\x01\xC6\x80\x80\x80\x80\x01\x10\x03", "\r\nOK\r\n"), - //Do a wait for timed silence at this point, or there won't be one in the tests - EXCHANGE("AT+FRS=7\r", "\r\nOK\r\n"), - //EXCHANGE("AT+FTS=8;+FTM=96\r", "\r\nCONNECT\r\n"), - EXCHANGE("AT+FTS=8\r", "\r\nOK\r\n"), - EXCHANGE("AT+FTM=96\r", "\r\nCONNECT\r\n"), - // - FAST_SEND_TCF("\r\nOK\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x13\x84\xEA\x7D\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("AT+FTM=96\r", "\r\nCONNECT\r\n"), - // - FAST_SEND("\r\nOK\r\n"), - //EXCHANGE("AT+FTS=8;+FTH=3\r", "\r\nCONNECT\r\n"), - EXCHANGE("AT+FTS=8\r", "\r\nOK\r\n"), - EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x13\x2E\x10\x03", "\r\nOK\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x13\x8C\xA2\xF1\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x13\xFB\x10\x03", "\r\nOK\r\n"), - EXCHANGE("ATH0\r", "\r\nOK\r\n"), - END_OF_SEQUENCE -}; - -static const struct command_response_s fax_receive_test_seq[] = -{ - EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), - EXCHANGE("AT+FCLASS=1\r", "\r\nOK\r\n"), - RESPONSE("\r\nRING\r\n"), - EXCHANGE("ATA\r", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x03\x40\x32\x32\x32\x32\x32\x32\x32\x32\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x10\x03", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x13\x80\x01\xCE\xF4\x80\x80\x81\x80\x80\x80\x18\x10\x03", "\r\nOK\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x03\x43\x31\x31\x31\x31\x31\x31\x31\x31\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xAA\x1F\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x13\x83\x00\xC6\x74\x53\x00\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("AT+FRM=96\r", "\r\nCONNECT\r\n"), - // - FAST_RESPONSE(NULL), - RESPONSE("\r\nNO CARRIER\r\n"), - EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x13\x84\x10\x03", "\r\nOK\r\n"), - EXCHANGE("AT+FRM=96\r", "\r\nCONNECT\r\n"), - // - FAST_RESPONSE(NULL), - RESPONSE("\r\nNO CARRIER\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x13\x2F\x33\x66\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("AT+FTH=3\r", "\r\nCONNECT\r\n"), - // - EXCHANGE("\xFF\x13\x8C\x10\x03", "\r\nOK\r\n"), - EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), - // - RESPONSE("\xFF\x13\xfb\x9a\xf6\x10\x03"), - RESPONSE("\r\nOK\r\n"), - EXCHANGE("ATH0\r", "\r\nOK\r\n"), - END_OF_SEQUENCE -}; - -static const struct command_response_s v34_fax_send_test_seq[] = -{ - EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), - EXCHANGE("AT+A8E=3,,\r", "\r\nOK\r\n"), - EXCHANGE("AT+FCLASS=1.0\r", "\r\nOK\r\n"), - EXCHANGE("AT+F34=14,4,2\r", "\r\nOK\r\n"), - EXCHANGE("ATD123456789\r", "\r\n+A8A:1\r\nOK\r\n"), - EXCHANGE("AT+A8M=8185D490\r", "\r\n+A8M:8185D490\r\nOK\r\n"), - EXCHANGE("ATO\r", "\r\n+A8J:1\r\n+F34=14,2\r\nCONNECT\r\n"), - // - RESPONSE("\x10\x6B\x10\x7D\x10\x6F" "\xFF\x13\x80\x00\xEE\xF8\x80\x80\x91\x80\x80\x80\x18\x78\x57\x10\x03"), // For audio FAXing - //RESPONSE("\x10\x6B\x10\x7D\x10\x6F" ""\xFF\x13\x80\x04\xEE\xF8\x80\x80\x91\x80\x80\x80\x18\xE4\xE7\x10\x03"), // For T.38 FAXing - // - // - EXCHANGE("\xFF\x13\x83\x01\xC6\x80\x80\x80\x80\x01\xFD\x13\x10\x03", "\xFF\x13\x84\xEA\x7D\x10\x03"), - EXCHANGE("\x10\x04", "\x10\x04\x10\x7D"), - // - EXCHANGE("\x10\x6B", "\x10\x6B\x10\x79\x10\x6F"), - // - // - // - EXCHANGE("\x10\x03", "\xFF\x13\x8C\xA2\xF1\x10\x03"), - // - EXCHANGE("\xFF\x13\xFB\x10\x03\x10\x04", "\r\nOK\r\n"), - EXCHANGE("ATH\r", "\r\nOK\r\n"), - END_OF_SEQUENCE -}; - -static const struct command_response_s v34_fax_receive_test_seq[] = -{ - EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), - EXCHANGE("AT+A8E=,2,\r", "\r\nOK\r\n"), - EXCHANGE("AT+FCLASS=1.0\r", "\r\nOK\r\n"), - EXCHANGE("AT+F34=10\r", "\r\nOK\r\n"), - RESPONSE("\r\nRING\r\n"), - EXCHANGE("ATA\r", "\r\n+A8M:8185D490\r\nOK\r\n"), - EXCHANGE("AT+A8M=8185D490;O\r", "\r\n+A8J:1\r\n+F34:10,1\r\nCONNECT\r\n"), - RESPONSE("\x10\x10\x10"), - EXCHANGE("ATH\r", "\r\nOK\r\n"), - END_OF_SEQUENCE -}; - -static const struct command_response_s v34_fax_receive_a_test_seq[] = -{ - EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), - EXCHANGE("AT+A8E=,3,\r", "\r\nOK\r\n"), - EXCHANGE("AT+FCLASS=1.0\r", "\r\nOK\r\n"), - EXCHANGE("AT+F34=10\r", "\r\nOK\r\n"), - RESPONSE("\r\nRING\r\n"), - EXCHANGE("ATA\r", "\r\n+A8C:1\r\n+A8C:1\r\n"), - EXCHANGE("X", "\r\nOK\r\n"), - EXCHANGE("AT+A8E=,2,\r", "\r\n+A8M:8185D490\r\nOK\r\n"), - EXCHANGE("AT+A8M=8185D490\r", "\r\n+A8J:1\r\n+F34:10,1\r\nCONNECT\r\n"), - RESPONSE("\x10\x10\x10"), - EXCHANGE("ATH\r", "\r\nOK\r\n"), - END_OF_SEQUENCE -}; - -static const struct command_response_s v34_fax_receive_b_test_seq[] = -{ - EXCHANGE("ATE0\r", "ATE0\r\r\nOK\r\n"), - EXCHANGE("AT+A8E=,3,\r", "\r\nOK\r\n"), - EXCHANGE("AT+FCLASS=1.0\r", "\r\nOK\r\n"), - EXCHANGE("AT+F34=10\r", "\r\nOK\r\n"), - RESPONSE("\r\nRING\r\n"), - EXCHANGE("ATA\r", "\r\nA8I:81\r\n"), - RESPONSE("A8I:81\r\n"), - EXCHANGE("X", "\r\nOK\r\n"), - EXCHANGE("AT+A8E=,2,\r", "\r\n+A8M:8185D490\r\nOK\r\n"), - END_OF_SEQUENCE -}; - -char *decode_test_file = NULL; -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; - -static const struct command_response_s *fax_test_seq; - -int test_seq_ptr = 0; - -t31_state_t *t31_state; - -static int phase_b_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B", ch); - printf("%c: Phase B handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_rx_parameters(s, tag); - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static int phase_d_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D", ch); - printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_page_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static void phase_e_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E", ch); - printf("Phase E handler on channel %c\n", ch); - fax_log_final_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); -} -/*- End of function --------------------------------------------------------*/ - -static int modem_call_control(t31_state_t *s, void *user_data, int op, const char *num) -{ - printf("\nModem control - %s", at_modem_control_to_str(op)); - switch (op) - { - case AT_MODEM_CONTROL_CALL: - printf(" %s", num); - t31_call_event(t31_state, AT_CALL_EVENT_CONNECTED); - break; - case AT_MODEM_CONTROL_ANSWER: - answered = true; - break; - case AT_MODEM_CONTROL_HANGUP: - done = true; - break; - case AT_MODEM_CONTROL_OFFHOOK: - break; - case AT_MODEM_CONTROL_DTR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RTS: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CTS: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_CAR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RNG: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DSR: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_SETID: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_RESTART: - printf(" %d", (int) (intptr_t) num); - break; - case AT_MODEM_CONTROL_DTE_TIMEOUT: - printf(" %d", (int) (intptr_t) num); - break; - } - /*endswitch*/ - printf("\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int at_tx_handler(void *user_data, const uint8_t *buf, size_t len) -{ - size_t i; - - i = 0; - if (fax_test_seq[test_seq_ptr].command == NULL) - { - /* TCF or non-ECM image data expected */ - for ( ; i < len; i++) - { - if (dled) - { - if (buf[i] == ETX) - { - printf("\nFast data ended\n"); - response_buf_ptr = 0; - 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; - if (fax_test_seq[test_seq_ptr].command) - kick = true; - break; - } - dled = false; - } - else - { - if (buf[i] == DLE) - dled = true; - } - } - i++; - if (i >= len) - return 0; - } - for ( ; i < len; i++) - { - response_buf[response_buf_ptr++] = buf[i]; - putchar(buf[i]); - } - response_buf[response_buf_ptr] = '\0'; - printf("Expected "); - for (i = 0; i < response_buf_ptr; i++) - printf("%02x ", fax_test_seq[test_seq_ptr].response[i] & 0xFF); - printf("\n"); - printf("Response "); - for (i = 0; i < response_buf_ptr; i++) - printf("%02x ", response_buf[i] & 0xFF); - printf("\n"); - printf("Match %d against %d\n", response_buf_ptr, fax_test_seq[test_seq_ptr].len_response); - if (response_buf_ptr >= fax_test_seq[test_seq_ptr].len_response - && - memcmp(fax_test_seq[test_seq_ptr].response, response_buf, fax_test_seq[test_seq_ptr].len_response) == 0) - { - 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; - response_buf_ptr = 0; - response_buf[response_buf_ptr] = '\0'; - if (fax_test_seq[test_seq_ptr].command) - kick = true; - else - dled = false; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - int i; - - /* This routine queues messages between two instances of T.38 processing, from the T.38 terminal side. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); - - for (i = 0; i < count; i++) - { - if (g1050_put(path_a_to_b, buf, len, s->tx_seq_no, when) < 0) - printf("Lost packet %d\n", s->tx_seq_no); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t31_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - int i; - - /* This routine queues messages between two instances of T.38 processing, from the T.31 modem side. */ - span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); - - for (i = 0; i < count; i++) - { - if (g1050_put(path_b_to_a, buf, len, s->tx_seq_no, when) < 0) - printf("Lost packet %d\n", s->tx_seq_no); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, int g1050_model_no, int g1050_speed_pattern_no) -{ - t38_terminal_state_t *t38_state; - fax_state_t *fax_state; - int fast_send; - int fast_send_tcf; - int fast_blocks; - int msg_len; - int t30_len; - int t31_len; - int t38_version; - int without_pacing; - int use_tep; - int seq_no; - int i; - int k; - int outframes; - uint8_t fast_buf[1000]; - uint8_t msg[1024]; - double tx_when; - double rx_when; - t30_state_t *t30; - t38_core_state_t *t38_core; - logging_state_t *logging; - int16_t t30_amp[SAMPLES_PER_CHUNK]; - int16_t t31_amp[SAMPLES_PER_CHUNK]; - int16_t silence[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - SNDFILE *wave_handle; - SNDFILE *in_handle; - - /* Test the T.31 modem against the full FAX machine in spandsp */ - - /* Set up the test environment */ - t38_version = 1; - without_pacing = false; - use_tep = false; - - wave_handle = NULL; - if (log_audio) - { - if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - in_handle = NULL; - if (decode_test_file) - { - if ((in_handle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", decode_test_file); - exit(2); - } - } - - srand48(0x1234567); - if ((path_a_to_b = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL) - { - fprintf(stderr, "Failed to start IP network path model\n"); - exit(2); - } - if ((path_b_to_a = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL) - { - fprintf(stderr, "Failed to start IP network path model\n"); - exit(2); - } - - t38_state = NULL; - fax_state = NULL; - if (test_sending) - { - if (t38_mode) - { - 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); - } - t30 = t38_terminal_get_t30_state(t38_state); - } - else - { - fax_state = fax_init(NULL, false); - t30 = fax_get_t30_state(fax_state); - } - t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); - fax_test_seq = fax_send_test_seq; - countdown = 0; - } - else - { - if (t38_mode) - { - 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); - } - t30 = t38_terminal_get_t30_state(t38_state); - } - else - { - fax_state = fax_init(NULL, true); - t30 = fax_get_t30_state(fax_state); - } - t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1); - fax_test_seq = fax_receive_test_seq; - countdown = 250; - } - - if (t38_mode) - { - t38_core = t38_terminal_get_t38_core_state(t38_state); - t38_set_t38_version(t38_core, t38_version); - t38_terminal_set_config(t38_state, without_pacing); - t38_terminal_set_tep_mode(t38_state, use_tep); - } - - t30_set_tx_ident(t30, "11111111"); - t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); - //t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); - t30_set_phase_b_handler(t30, phase_b_handler, (void *) t30); - t30_set_phase_d_handler(t30, phase_d_handler, (void *) t30); - t30_set_phase_e_handler(t30, phase_e_handler, (void *) t30); - - if (t38_mode) - logging = t38_terminal_get_logging_state(t38_state); - else - logging = t30_get_logging_state(t30); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, (t38_mode) ? "T.38" : "FAX"); - - if (t38_mode) - { - t38_core = t38_terminal_get_t38_core_state(t38_state); - span_log_set_level(&t38_core->logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(&t38_core->logging, "T.38"); - - logging = t30_get_logging_state(t30); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - } - else - { - logging = fax_get_logging_state(fax_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "FAX"); - } - - memset(silence, 0, sizeof(silence)); - memset(t30_amp, 0, sizeof(t30_amp)); - - /* Now set up and run the T.31 modem */ - if ((t31_state = t31_init(NULL, at_tx_handler, NULL, modem_call_control, NULL, t31_tx_packet_handler, NULL)) == NULL) - { - fprintf(stderr, " Cannot start the T.31 modem\n"); - exit(2); - } - logging = t31_get_logging_state(t31_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.31"); - - logging = at_get_logging_state(t31_get_at_state(t31_state)); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.31"); - - if (t38_mode) - { - t38_core = t31_get_t38_core_state(t31_state); - logging = t38_core_get_logging_state(t38_core); - 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); - t38_set_t38_version(t38_core, t38_version); - } - - fast_send = false; - fast_send_tcf = true; - fast_blocks = 0; - kick = true; -#if defined(ENABLE_GUI) - if (use_gui) - start_media_monitor(); -#endif - while (!done) - { - if (countdown) - { - /* Deal with call setup, through the AT interface. */ - if (answered) - { - countdown = 0; - t31_call_event(t31_state, AT_CALL_EVENT_ANSWERED); - } - else if (--countdown == 0) - { - t31_call_event(t31_state, AT_CALL_EVENT_ALERTING); - countdown = 250; - } - } - - if (kick) - { - /* Work through the script */ - kick = false; - if (fax_test_seq[test_seq_ptr].command > (const char *) 2) - { - if (fax_test_seq[test_seq_ptr].command[0]) - { - printf("%s\n", fax_test_seq[test_seq_ptr].command); - t31_at_rx(t31_state, fax_test_seq[test_seq_ptr].command, fax_test_seq[test_seq_ptr].len_command); - } - } - else - { - if (fax_test_seq[test_seq_ptr].command == (const char *) 2) - { - printf("Fast send TCF\n"); - fast_send = true; - fast_send_tcf = true; - fast_blocks = 100; - } - else - { - printf("Fast send image\n"); - fast_send = true; - fast_send_tcf = false; - fast_blocks = 100; - } - } - } - if (fast_send) - { - /* Send fast modem data */ - if (fast_send_tcf) - { - /* If we are sending TCF, its simply zeros */ - memset(fast_buf, 0, 36); - if (fast_blocks == 1) - { - /* Tell the modem this is the end of the TCF data */ - fast_buf[34] = DLE; - fast_buf[35] = ETX; - } - } - else - { - /* If we are sending image data, we need to make it look like genuine image data, - with proper EOL and RTC markers. */ - if (fast_blocks > 1) - { - /* Create a chunk of white page, 1728 pixels wide. */ - for (i = 0; i < 36; i += 4) - { - fast_buf[i] = 0x00; - fast_buf[i + 1] = 0x80; - fast_buf[i + 2] = 0xB2; - fast_buf[i + 3] = 0x01; - } - } - else - { - /* Create the end of page condition. */ - for (i = 0; i < 36; i += 3) - { - fast_buf[i] = 0x00; - fast_buf[i + 1] = 0x08; - fast_buf[i + 2] = 0x80; - } - /* Tell the modem this is the end of the image data. */ - fast_buf[34] = DLE; - fast_buf[35] = ETX; - } - } - t31_at_rx(t31_state, (char *) fast_buf, 36); - if (--fast_blocks == 0) - fast_send = false; - } - - if (t38_mode) - { - while ((msg_len = g1050_get(path_a_to_b, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(seq_no, tx_when, rx_when); -#endif - t38_core = t31_get_t38_core_state(t31_state); - t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); - } - while ((msg_len = g1050_get(path_b_to_a, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0) - { -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_rx(seq_no, tx_when, rx_when); -#endif - t38_core = t38_terminal_get_t38_core_state(t38_state); - t38_core_rx_ifp_packet(t38_core, msg, msg_len, seq_no); - } -#if defined(ENABLE_GUI) - if (use_gui) - media_monitor_update_display(); -#endif - /* Bump the G.1050 models along */ - when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE; - - /* Bump things along on the t38_terminal side */ - span_log_bump_samples(t38_terminal_get_logging_state(t38_state), SAMPLES_PER_CHUNK); - t38_core = t38_terminal_get_t38_core_state(t38_state); - span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK); - - t38_terminal_send_timeout(t38_state, SAMPLES_PER_CHUNK); - t31_t38_send_timeout(t31_state, SAMPLES_PER_CHUNK); - } - else - { - t30_len = fax_tx(fax_state, t30_amp, SAMPLES_PER_CHUNK); - /* The receive side always expects a full block of samples, but the - transmit side may not be sending any when it doesn't need to. We - may need to pad with some silence. */ - if (t30_len < SAMPLES_PER_CHUNK) - { - memset(t30_amp + t30_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len)); - t30_len = SAMPLES_PER_CHUNK; - } - if (log_audio) - { - for (k = 0; k < t30_len; k++) - out_amp[2*k] = t30_amp[k]; - } - if (t31_rx(t31_state, t30_amp, t30_len)) - break; - t31_len = t31_tx(t31_state, t31_amp, SAMPLES_PER_CHUNK); - if (t31_len < SAMPLES_PER_CHUNK) - { - memset(t31_amp + t31_len, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t31_len)); - t31_len = SAMPLES_PER_CHUNK; - } - if (log_audio) - { - for (k = 0; k < t31_len; k++) - out_amp[2*k + 1] = t31_amp[k]; - } - if (fax_rx(fax_state, t31_amp, SAMPLES_PER_CHUNK)) - break; - - if (log_audio) - { - outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK); - if (outframes != SAMPLES_PER_CHUNK) - break; - } - - /* Bump things along on the FAX machine side */ - span_log_bump_samples(fax_get_logging_state(fax_state), SAMPLES_PER_CHUNK); - } - - /* Bump things along on the FAX machine side */ - span_log_bump_samples(t30_get_logging_state(t30), SAMPLES_PER_CHUNK); - - /* Bump things along on the T.31 modem side */ - t38_core = t31_get_t38_core_state(t31_state); - span_log_bump_samples(t38_core_get_logging_state(t38_core), SAMPLES_PER_CHUNK); - span_log_bump_samples(t31_get_logging_state(t31_state), SAMPLES_PER_CHUNK); - span_log_bump_samples(at_get_logging_state(t31_get_at_state(t31_state)), SAMPLES_PER_CHUNK); - } - - g1050_free(path_a_to_b); - g1050_free(path_b_to_a); - if (t38_mode) - t38_terminal_free(t38_state); - else - fax_free(fax_state); - t31_free(t31_state); - - if (decode_test_file) - { - if (sf_close_telephony(in_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - if (!done || !sequence_terminated) - { - printf("Tests failed\n"); - return -1; - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int log_audio; - int t38_mode; - int test_sending; - int use_gui; - int g1050_model_no; - int g1050_speed_pattern_no; - int opt; - - decode_test_file = NULL; - 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) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - case 'M': - g1050_model_no = optarg[0] - 'A' + 1; - break; - case 'r': - test_sending = false; - break; - case 'S': - g1050_speed_pattern_no = atoi(optarg); - break; - case 's': - test_sending = true; - break; - case 't': - t38_mode = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - 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; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t35_tests.c b/libs/spandsp/tests/t35_tests.c deleted file mode 100644 index b65e30189d..0000000000 --- a/libs/spandsp/tests/t35_tests.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t35_tests.c - Tests for T.35. - * - * 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. - */ - -/*! \file */ - -/*! \page t35_tests_page T.35 tests -\section t35_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -int main(int argc, char *argv[]) -{ - int i; - int j; - uint8_t msg[50]; - const char *vendor; - const char *country; - const char *model; - const char *real_country; - bool first_hit; - - printf("Sweep through all the possible countries\n"); - for (i = 0; i < 256; i++) - { - country = t35_country_code_to_str(i, 0); - real_country = t35_real_country_code_to_str(i, 0); - if (country || real_country) - { - printf("%3d '%s' %d '%s'\n", - i, - (country) ? country : "???", - t35_real_country_code(i, 0), - (real_country) ? real_country : "???"); - } - } - - printf("\nSweep through all the possible vendors within each country\n"); - for (i = 0; i < 256; i++) - { - msg[0] = i; - msg[1] = '\x00'; - msg[2] = '\x00'; - first_hit = true; - for (j = 0; j < 65536; j++) - { - msg[1] = (j >> 8) & 0xFF; - msg[2] = j & 0xFF; - if ((vendor = t35_vendor_to_str(msg, 3))) - { - if (first_hit) - { - if ((real_country = t35_real_country_code_to_str(i, 0))) - printf("%s\n", real_country); - else - printf("???\n"); - first_hit = false; - } - printf(" 0x%02x 0x%02x 0x%02x '%s'\n", msg[0], msg[1], msg[2], vendor); - } - } - } - - printf("\nTry a decode of a full NSF string\n"); - t35_decode((uint8_t *) "\x00\x00\x0E\x00\x00\x00\x96\x0F\x01\x02\x00\x10\x05\x02\x95\xC8\x08\x01\x49\x02\x41\x53\x54\x47", - 13, - &country, - &vendor, - &model); - printf("Decoded as %s %s %s\n", (country) ? country : "???", (vendor) ? vendor : "???", (model) ? model : "???"); - - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t38_core_tests.c b/libs/spandsp/tests/t38_core_tests.c deleted file mode 100644 index 21c131bf3c..0000000000 --- a/libs/spandsp/tests/t38_core_tests.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_core_tests.c - Tests for the T.38 FoIP core module. - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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 t38_core_tests_page T.38 core tests -\section t38_core_tests_page_sec_1 What does it do? -These tests exercise the T.38 core ASN.1 processing code. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#if !defined(WIN32) -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define MAX_FIELDS 42 -#define MAX_FIELD_LEN 8192 - -static bool succeeded = true; -static int t38_version; -static int ok_indicator_packets; -static int bad_indicator_packets; -static int ok_data_packets; -static int bad_data_packets; -static int missing_packets; - -static int skip; - -static uint8_t field_body[MAX_FIELDS][MAX_FIELD_LEN]; -static int field_len[MAX_FIELDS]; -static int seq_no; - -static int msg_list[1000000]; -static int msg_list_ptr; -static int msg_list_ptr2; -static uint8_t concat[1000000]; -static int concat_len; - -static int rx_missing_attack_handler(t38_core_state_t *s, void *user_data, int rx_seq_no, int expected_seq_no) -{ - //printf("Hit missing\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_indicator_attack_handler(t38_core_state_t *s, void *user_data, int indicator) -{ - //printf("Hit indicator %d\n", indicator); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_data_attack_handler(t38_core_state_t *s, void *user_data, int data_type, int field_type, const uint8_t *buf, int len) -{ - //printf("Hit data %d, field %d\n", data_type, field_type); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_missing_handler(t38_core_state_t *s, void *user_data, int rx_seq_no, int expected_seq_no) -{ - missing_packets++; - //printf("Hit missing\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_indicator_handler(t38_core_state_t *s, void *user_data, int indicator) -{ - if (indicator == msg_list[msg_list_ptr2++]) - ok_indicator_packets++; - else - bad_indicator_packets++; - //printf("Hit indicator %d\n", indicator); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int rx_data_handler(t38_core_state_t *s, void *user_data, int data_type, int field_type, const uint8_t *buf, int len) -{ - if (data_type == msg_list[msg_list_ptr2] && field_type == msg_list[msg_list_ptr2 + 1]) - ok_data_packets++; - else - bad_data_packets++; - msg_list_ptr2 += 2; - //printf("Hit data %d, field %d\n", data_type, field_type); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - t38_core_state_t *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; - seq_no++; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int tx_concat_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - 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); - memcpy(&concat[concat_len], buf, len); - concat_len += len; - seq_no++; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int encode_decode_tests(t38_core_state_t *a, t38_core_state_t *b) -{ - t38_data_field_t field[MAX_FIELDS]; - int i; - int j; - - ok_indicator_packets = 0; - bad_indicator_packets = 0; - ok_data_packets = 0; - bad_data_packets = 0; - missing_packets = 0; - - msg_list_ptr = 0; - msg_list_ptr2 = 0; - - /* Try all the indicator types */ - for (i = 0; i < 100; i++) - { - msg_list[msg_list_ptr++] = i; - if (t38_core_send_indicator(a, i) < 0) - { - msg_list_ptr--; - break; - } - } - - /* Try all the data types, as single field messages with no data */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = j; - skip = 99; - if (t38_core_send_data(a, i, j, (uint8_t *) "", 0, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - { - msg_list_ptr -= 2; - break; - } - } - if (j == 0) - break; - } - - /* Try all the data types and field types, as single field messages with data */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = j; - skip = 99; - if (t38_core_send_data(a, i, j, (uint8_t *) "ABCD", 4, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - { - msg_list_ptr -= 2; - break; - } - } - if (j == 0) - break; - } - - /* Try all the data types and field types, as multi-field messages, but with 0 fields */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - skip = 1; - if (t38_core_send_data_multi_field(a, i, field, 0, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - break; - } - if (j == 0) - break; - } - - /* Try all the data types and field types, as multi-field messages */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = j; - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = T38_FIELD_T4_NON_ECM_SIG_END; - skip = 1; - - field_len[0] = 444; - field_len[1] = 333; - - field[0].field_type = j; - field[0].field = field_body[0]; - field[0].field_len = field_len[0]; - field[1].field_type = T38_FIELD_T4_NON_ECM_SIG_END; - field[1].field = field_body[1]; - field[1].field_len = field_len[1]; - if (t38_core_send_data_multi_field(a, i, field, 2, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - { - msg_list_ptr -= 4; - break; - } - } - if (j == 0) - break; - } - - printf("Indicator packets: OK = %d, bad = %d\n", ok_indicator_packets, bad_indicator_packets); - printf("Data packets: OK = %d, bad = %d\n", ok_data_packets, bad_data_packets); - printf("Missing packets = %d\n", missing_packets); - - if (t38_version == 0) - { - if (ok_indicator_packets != 16 || bad_indicator_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - if (ok_data_packets != 288 || bad_data_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - } - else - { - if (ok_indicator_packets != 23 || bad_indicator_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - if (ok_data_packets != 720 || bad_data_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - } - if (missing_packets > 0) - { - printf("Tests failed\n"); - return -1; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int encode_then_decode_tests(t38_core_state_t *a, t38_core_state_t *b) -{ - t38_data_field_t field[MAX_FIELDS]; - int len; - int i; - int j; - - ok_indicator_packets = 0; - bad_indicator_packets = 0; - ok_data_packets = 0; - bad_data_packets = 0; - missing_packets = 0; - - msg_list_ptr = 0; - msg_list_ptr2 = 0; - - /* Try all the indicator types */ - for (i = 0; i < 100; i++) - { - msg_list[msg_list_ptr++] = i; - if (t38_core_send_indicator(a, i) < 0) - { - msg_list_ptr--; - break; - } - } - - /* Try all the data types, as single field messages with no data */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = j; - skip = 99; - if (t38_core_send_data(a, i, j, (uint8_t *) "", 0, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - { - msg_list_ptr -= 2; - break; - } - } - if (j == 0) - break; - } - - /* Try all the data types and field types, as single field messages with data */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = j; - skip = 99; - if (t38_core_send_data(a, i, j, (uint8_t *) "ABCD", 4, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - { - msg_list_ptr -= 2; - break; - } - } - if (j == 0) - break; - } - - /* Try all the data types and field types, as multi-field messages, but with 0 fields */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - skip = 1; - if (t38_core_send_data_multi_field(a, i, field, 0, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - break; - } - if (j == 0) - break; - } - - /* Try all the data types and field types, as multi-field messages */ - for (i = 0; i < 100; i++) - { - for (j = 0; j < 100; j++) - { - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = j; - msg_list[msg_list_ptr++] = i; - msg_list[msg_list_ptr++] = T38_FIELD_T4_NON_ECM_SIG_END; - skip = 1; - - field_len[0] = 444; - field_len[1] = 333; - - field[0].field_type = j; - field[0].field = field_body[0]; - field[0].field_len = field_len[0]; - field[1].field_type = T38_FIELD_T4_NON_ECM_SIG_END; - field[1].field = field_body[1]; - field[1].field_len = field_len[1]; - if (t38_core_send_data_multi_field(a, i, field, 2, T38_PACKET_CATEGORY_CONTROL_DATA) < 0) - { - msg_list_ptr -= 4; - break; - } - } - if (j == 0) - break; - } - - /* Now split up the big concatented block of IFP packets. */ - 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; - seq_no++; - } - - printf("Indicator packets: OK = %d, bad = %d\n", ok_indicator_packets, bad_indicator_packets); - printf("Data packets: OK = %d, bad = %d\n", ok_data_packets, bad_data_packets); - printf("Missing packets = %d\n", missing_packets); - - if (t38_version == 0) - { - if (ok_indicator_packets != 16 || bad_indicator_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - if (ok_data_packets != 288 || bad_data_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - } - else - { - if (ok_indicator_packets != 23 || bad_indicator_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - if (ok_data_packets != 720 || bad_data_packets != 0) - { - printf("Tests failed\n"); - return -1; - } - } - if (missing_packets > 0) - { - printf("Tests failed\n"); - return -1; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int attack_tests(t38_core_state_t *s, int packets) -{ - int i; - int j; - int len; - uint8_t buf[1024]; - int seq_no; - - srand(1234567); - /* Send lots of random junk, of increasing length. Much of this will decode - as valid IFP frames, but none of it should cause trouble. */ - seq_no = 0; - for (len = 1; len < 70; len++) - { - for (i = 0; i < packets; i++) - { - for (j = 0; j < len; j++) - buf[j] = (rand() >> 16) & 0xFF; - t38_core_rx_ifp_packet(s, buf, len, seq_no); - seq_no = (seq_no + 1) & 0xFFFF; - } - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - t38_core_state_t t38_core_ax; - t38_core_state_t t38_core_bx; - t38_core_state_t *t38_core_a; - t38_core_state_t *t38_core_b; - int attack_packets; - int opt; - - attack_packets = 100000; - while ((opt = getopt(argc, argv, "a:")) != -1) - { - switch (opt) - { - case 'a': - attack_packets = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - - /* Tests in UDP type mode, for UDPTL and RTP */ - for (t38_version = 0; t38_version < 2; t38_version++) - { - seq_no = 0; - - printf("Using T.38 version %d\n", t38_version); - - if ((t38_core_a = t38_core_init(&t38_core_ax, - rx_indicator_handler, - rx_data_handler, - rx_missing_handler, - &t38_core_bx, - tx_packet_handler, - &t38_core_bx)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - if ((t38_core_b = t38_core_init(&t38_core_bx, - rx_indicator_handler, - rx_data_handler, - rx_missing_handler, - &t38_core_ax, - tx_packet_handler, - &t38_core_ax)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - - t38_set_t38_version(t38_core_a, t38_version); - t38_set_t38_version(t38_core_b, t38_version); - - span_log_set_level(t38_core_get_logging_state(t38_core_a), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - span_log_set_tag(t38_core_get_logging_state(t38_core_a), "T.38-A"); - span_log_set_level(t38_core_get_logging_state(t38_core_b), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - span_log_set_tag(t38_core_get_logging_state(t38_core_b), "T.38-B"); - - /* Encode and decode all possible frame types, one by one */ - if (encode_decode_tests(t38_core_a, t38_core_b)) - { - printf("Encode/decode tests failed\n"); - exit(2); - } - - if ((t38_core_a = t38_core_init(&t38_core_ax, - rx_indicator_attack_handler, - rx_data_attack_handler, - rx_missing_attack_handler, - &t38_core_bx, - tx_packet_handler, - &t38_core_bx)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - - t38_set_t38_version(t38_core_a, t38_version); - - //span_log_set_level(t38_core_get_logging_state(t38_core_a), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - //span_log_set_tag(t38_core_get_logging_state(t38_core_a), "T.38-A"); - - if (attack_tests(t38_core_a, attack_packets)) - { - printf("Attack tests failed\n"); - exit(2); - } - } - - /* Tests in TCP without TPKT mode, like T.38 version 0 */ - for (t38_version = 0; t38_version < 2; t38_version++) - { - seq_no = 0; - concat_len = 0; - - printf("Using T.38 version %d\n", t38_version); - - if ((t38_core_a = t38_core_init(&t38_core_ax, - rx_indicator_handler, - rx_data_handler, - rx_missing_handler, - &t38_core_bx, - tx_concat_packet_handler, - &t38_core_bx)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - if ((t38_core_b = t38_core_init(&t38_core_bx, - rx_indicator_handler, - rx_data_handler, - rx_missing_handler, - &t38_core_ax, - tx_concat_packet_handler, - &t38_core_ax)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - - 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_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP); - t38_set_data_transport_protocol(t38_core_b, T38_TRANSPORT_TCP); - - span_log_set_level(t38_core_get_logging_state(t38_core_a), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - span_log_set_tag(t38_core_get_logging_state(t38_core_a), "T.38-A"); - span_log_set_level(t38_core_get_logging_state(t38_core_b), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - span_log_set_tag(t38_core_get_logging_state(t38_core_b), "T.38-B"); - - /* Encode all possible frames types into a large block, and then decode them */ - if (encode_then_decode_tests(t38_core_a, t38_core_b)) - { - printf("Encode then decode tests failed\n"); - exit(2); - } - - if ((t38_core_a = t38_core_init(&t38_core_ax, - rx_indicator_attack_handler, - rx_data_attack_handler, - rx_missing_attack_handler, - &t38_core_bx, - tx_packet_handler, - &t38_core_bx)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - - t38_set_t38_version(t38_core_a, t38_version); - - t38_set_pace_transmission(t38_core_a, false); - - t38_set_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP); - - //span_log_set_level(t38_core_get_logging_state(t38_core_a), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - //span_log_set_tag(t38_core_get_logging_state(t38_core_a), "T.38-A"); - - if (attack_tests(t38_core_a, attack_packets)) - { - printf("Attack tests failed\n"); - exit(2); - } - } - - /* Tests in TCP with TPKT mode, like T.38 versions >0 */ - for (t38_version = 0; t38_version < 2; t38_version++) - { - seq_no = 0; - concat_len = 0; - - printf("Using T.38 version %d\n", t38_version); - - if ((t38_core_a = t38_core_init(&t38_core_ax, - rx_indicator_handler, - rx_data_handler, - rx_missing_handler, - &t38_core_bx, - tx_concat_packet_handler, - &t38_core_bx)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - if ((t38_core_b = t38_core_init(&t38_core_bx, - rx_indicator_handler, - rx_data_handler, - rx_missing_handler, - &t38_core_ax, - tx_concat_packet_handler, - &t38_core_ax)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - - 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_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP_TPKT); - t38_set_data_transport_protocol(t38_core_b, T38_TRANSPORT_TCP_TPKT); - - span_log_set_level(t38_core_get_logging_state(t38_core_a), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - span_log_set_tag(t38_core_get_logging_state(t38_core_a), "T.38-A"); - span_log_set_level(t38_core_get_logging_state(t38_core_b), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - span_log_set_tag(t38_core_get_logging_state(t38_core_b), "T.38-B"); - - /* Encode all possible frames types into a large block, and then decode them */ - if (encode_then_decode_tests(t38_core_a, t38_core_b)) - { - printf("Encode then decode tests failed\n"); - exit(2); - } - - if ((t38_core_a = t38_core_init(&t38_core_ax, - rx_indicator_attack_handler, - rx_data_attack_handler, - rx_missing_attack_handler, - &t38_core_bx, - tx_packet_handler, - &t38_core_bx)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 core\n"); - exit(2); - } - t38_set_t38_version(t38_core_a, t38_version); - - t38_set_pace_transmission(t38_core_a, false); - - t38_set_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP_TPKT); - - //span_log_set_level(t38_core_get_logging_state(t38_core_a), SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG); - //span_log_set_tag(t38_core_get_logging_state(t38_core_a), "T.38-A"); - - if (attack_tests(t38_core_a, attack_packets)) - { - printf("Attack tests failed\n"); - exit(2); - } - } - - if (!succeeded) - { - printf("Tests failed\n"); - exit(2); - } - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t38_decode.c b/libs/spandsp/tests/t38_decode.c deleted file mode 100644 index 1716f96cc0..0000000000 --- a/libs/spandsp/tests/t38_decode.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_decode.c - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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 */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#endif - -#include "udptl.h" -#include "spandsp.h" -#include "spandsp-sim.h" - -#include "fax_utils.h" -#include "pcap_parse.h" - -#define INPUT_FILE_NAME "t38.pcap" -#define INPUT_TIFF_FILE_NAME "../test-data/itu/fax/itutests.tif" -#define OUTPUT_TIFF_FILE_NAME "t38pcap.tif" - -#define OUTPUT_WAVE_FILE_NAME "t38_decode2.wav" - -#define SAMPLES_PER_CHUNK 160 - -static t38_core_state_t *t38_core; -static t38_terminal_state_t *t38_terminal_state; -static t38_gateway_state_t *t38_gateway_state; -static fax_state_t *fax_state; -static struct timeval now; -static SNDFILE *wave_handle; - -static int log_audio; -static int use_transmit_on_idle; -static int done = false; - -static int started = false; -static int64_t current = 0; - -static int phase_b_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B", ch); - printf("%c: Phase B handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_rx_parameters(s, tag); - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static int phase_d_handler(void *user_data, int result) -{ - int ch; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D", ch); - printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result)); - fax_log_page_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); - return T30_ERR_OK; -} -/*- End of function --------------------------------------------------------*/ - -static void phase_e_handler(void *user_data, int result) -{ - int ch; - t30_stats_t t; - t30_state_t *s; - char tag[20]; - - ch = 'A'; - s = (t30_state_t *) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E", ch); - printf("%c: Phase E handler on channel %c - (%d) %s\n", ch, ch, result, t30_completion_code_to_str(result)); - fax_log_final_transfer_statistics(s, tag); - fax_log_tx_parameters(s, tag); - fax_log_rx_parameters(s, tag); - t30_get_transfer_statistics(s, &t); -} -/*- End of function --------------------------------------------------------*/ - -static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_terminal_timing_update(void *user_data, struct timeval *ts) -{ - t30_state_t *t30; - logging_state_t *logging; - int samples; - int partial; - int64_t when; - int64_t diff; - - memcpy(&now, ts, sizeof(now)); - - when = ts->tv_sec*1000000LL + ts->tv_usec; - if (current == 0) - { - if (started) - current = when; - return 0; - } - - diff = when - current; - samples = diff/125LL; - while (samples > 0) - { - partial = (samples > SAMPLES_PER_CHUNK) ? SAMPLES_PER_CHUNK : samples; - //fprintf(stderr, "Update time by %d samples\n", partial); - logging = t38_terminal_get_logging_state(t38_terminal_state); - span_log_bump_samples(logging, partial); - logging = t38_core_get_logging_state(t38_core); - span_log_bump_samples(logging, partial); - t30 = t38_terminal_get_t30_state(t38_terminal_state); - logging = t30_get_logging_state(t30); - span_log_bump_samples(logging, partial); - - t38_terminal_send_timeout(t38_terminal_state, partial); - current = when; - samples -= partial; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int t38_gateway_timing_update(void *user_data, struct timeval *ts) -{ - t30_state_t *t30; - logging_state_t *logging; - int samples; - int partial; - int64_t when; - int64_t diff; - int16_t t38_amp[SAMPLES_PER_CHUNK]; - int16_t t30_amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int t38_len; - int t30_len; - int outframes; - int i; - - memcpy(&now, ts, sizeof(now)); - - when = ts->tv_sec*1000000LL + ts->tv_usec; - if (current == 0) - { - if (started) - current = when; - return 0; - } - - diff = when - current; - samples = diff/125LL; - while (samples > 0) - { - partial = (samples > SAMPLES_PER_CHUNK) ? SAMPLES_PER_CHUNK : samples; - //fprintf(stderr, "Update time by %d samples\n", partial); - logging = t38_gateway_get_logging_state(t38_gateway_state); - span_log_bump_samples(logging, partial); - logging = t38_core_get_logging_state(t38_core); - span_log_bump_samples(logging, partial); - logging = fax_get_logging_state(fax_state); - span_log_bump_samples(logging, partial); - t30 = fax_get_t30_state(fax_state); - logging = t30_get_logging_state(t30); - span_log_bump_samples(logging, partial); - - memset(out_amp, 0, sizeof(out_amp)); - - t30_len = fax_tx(fax_state, t30_amp, partial); - if (!use_transmit_on_idle) - { - /* The receive side always expects a full block of samples, but the - transmit side may not be sending any when it doesn't need to. We - may need to pad with some silence. */ - if (t30_len < partial) - { - memset(t30_amp + t30_len, 0, sizeof(int16_t)*(partial - t30_len)); - t30_len = partial; - } - } - if (log_audio) - { - for (i = 0; i < t30_len; i++) - out_amp[2*i + 1] = t30_amp[i]; - } - if (t38_gateway_rx(t38_gateway_state, t30_amp, t30_len)) - break; - - t38_len = t38_gateway_tx(t38_gateway_state, t38_amp, partial); - if (!use_transmit_on_idle) - { - if (t38_len < partial) - { - memset(t38_amp + t38_len, 0, sizeof(int16_t)*(partial - t38_len)); - t38_len = partial; - } - } - if (log_audio) - { - for (i = 0; i < t38_len; i++) - out_amp[2*i] = t38_amp[i]; - } - if (fax_rx(fax_state, t38_amp, partial)) - break; - - if (log_audio) - { - outframes = sf_writef_short(wave_handle, out_amp, partial); - if (outframes != partial) - break; - } - - if (done) - break; - - current = when; - samples -= partial; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int ifp_handler(void *user_data, const uint8_t msg[], int len, int seq_no) -{ - int i; - - started = true; - - printf("%5d >>> ", seq_no); - for (i = 0; i < len; i++) - printf("%02X ", msg[i]); - printf("\n"); - - t38_core_rx_ifp_packet(t38_core, msg, len, seq_no); - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int process_packet(void *user_data, const uint8_t *pkt, int len) -{ - static udptl_state_t *state = NULL; - - if (state == NULL) - state = udptl_init(NULL, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, ifp_handler, NULL); - - udptl_rx_packet(state, pkt, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static uint32_t parse_inet_addr(const char *s) -{ - int i; - uint32_t a; - uint32_t b; - uint32_t c; - uint32_t d; - - a = 0; - b = 0; - c = 0; - d = 0; - i = sscanf(s, "%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32, &a, &b, &c, &d); - switch (i) - { - case 4: - c = (c << 8) | d; - case 3: - b = (b << 16) | c; - case 2: - a = (a << 24) | b; - } - return a; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - t30_state_t *t30; - logging_state_t *logging; - const char *input_file_name; - const char *input_tiff_file_name; - int t38_version; - int caller; - int use_ecm; - int use_tep; - int options; - int supported_modems; - int fill_removal; - int opt; - int t38_terminal_operation; - uint32_t src_addr; - uint16_t src_port; - uint32_t dest_addr; - uint16_t dest_port; - - caller = false; - use_ecm = false; - t38_version = 0; - options = 0; - input_file_name = INPUT_FILE_NAME; - input_tiff_file_name = INPUT_TIFF_FILE_NAME; - 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; - src_addr = 0; - src_port = 0; - dest_addr = 0; - dest_port = 0; - while ((opt = getopt(argc, argv, "cD:d:eFGi:lm:oS:s:T:tv:")) != -1) - { - switch (opt) - { - case 'c': - caller = true; - break; - case 'D': - dest_addr = parse_inet_addr(optarg); - break; - case 'd': - dest_port = atoi(optarg); - break; - case 'e': - use_ecm = true; - break; - case 'F': - fill_removal = true; - break; - case 'G': - t38_terminal_operation = false; - break; - case 'i': - input_file_name = optarg; - break; - case 'l': - log_audio = true; - break; - case 'm': - supported_modems = atoi(optarg); - break; - case 'o': - options = atoi(optarg); - break; - case 'S': - src_addr = parse_inet_addr(optarg); - break; - case 's': - src_port = atoi(optarg); - break; - case 'T': - input_tiff_file_name = optarg; - break; - case 't': - use_tep = true; - break; - case 'v': - t38_version = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - - printf("Using T.38 version %d\n", t38_version); - - if (t38_terminal_operation) - { - if ((t38_terminal_state = t38_terminal_init(NULL, caller, tx_packet_handler, NULL)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 channel\n"); - exit(2); - } - t30 = t38_terminal_get_t30_state(t38_terminal_state); - t38_core = t38_terminal_get_t38_core_state(t38_terminal_state); - t38_set_t38_version(t38_core, t38_version); - t38_terminal_set_config(t38_terminal_state, options); - t38_terminal_set_tep_mode(t38_terminal_state, use_tep); - t38_terminal_set_fill_bit_removal(t38_terminal_state, fill_removal); - - logging = t38_terminal_get_logging_state(t38_terminal_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - - logging = t38_core_get_logging_state(t38_core); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - - logging = t30_get_logging_state(t30); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - - t30_set_supported_modems(t30, supported_modems); - t30_set_tx_ident(t30, "11111111"); - t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); - if (caller) - t30_set_tx_file(t30, input_tiff_file_name, -1, -1); - else - t30_set_rx_file(t30, OUTPUT_TIFF_FILE_NAME, -1); - t30_set_phase_b_handler(t30, phase_b_handler, (void *) t30); - t30_set_phase_d_handler(t30, phase_d_handler, (void *) t30); - t30_set_phase_e_handler(t30, phase_e_handler, (void *) t30); - t30_set_ecm_capability(t30, use_ecm); - 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); - /* Push the time along, to flush out any remaining activity from the application. */ - now.tv_sec += 60; - t38_terminal_timing_update(NULL, &now); - } - else - { - wave_handle = NULL; - if (log_audio) - { - if ((wave_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - - if ((t38_gateway_state = t38_gateway_init(NULL, tx_packet_handler, NULL)) == NULL) - { - fprintf(stderr, "Cannot start the T.38 channel\n"); - exit(2); - } - t38_core = t38_gateway_get_t38_core_state(t38_gateway_state); - t38_gateway_set_transmit_on_idle(t38_gateway_state, use_transmit_on_idle); - t38_set_t38_version(t38_core, t38_version); - t38_gateway_set_ecm_capability(t38_gateway_state, use_ecm); - - logging = t38_gateway_get_logging_state(t38_gateway_state); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - - logging = t38_core_get_logging_state(t38_core); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "T.38"); - - if ((fax_state = fax_init(NULL, caller)) == NULL) - { - fprintf(stderr, "Cannot start FAX\n"); - exit(2); - } - t30 = fax_get_t30_state(fax_state); - fax_set_transmit_on_idle(fax_state, use_transmit_on_idle); - fax_set_tep_mode(fax_state, use_tep); - t30_set_supported_modems(t30, supported_modems); - t30_set_tx_ident(t30, "22222222"); - t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12); - if (caller) - t30_set_tx_file(t30, input_tiff_file_name, -1, -1); - else - t30_set_rx_file(t30, OUTPUT_TIFF_FILE_NAME, -1); - t30_set_phase_b_handler(t30, phase_b_handler, (void *) t30); - t30_set_phase_d_handler(t30, phase_d_handler, (void *) t30); - t30_set_phase_e_handler(t30, phase_e_handler, (void *) t30); - t30_set_ecm_capability(t30, use_ecm); - 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); - span_log_set_tag(logging, "FAX "); - - logging = t30_get_logging_state(t30); - span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(logging, "FAX "); - - if (pcap_scan_pkts(input_file_name, src_addr, src_port, dest_addr, dest_port, t38_gateway_timing_update, process_packet, NULL)) - exit(2); - /* Push the time along, to flush out any remaining activity from the application. */ - now.tv_sec += 60; - t38_gateway_timing_update(NULL, &now); - - fax_release(fax_state); - t38_gateway_release(t38_gateway_state); - if (log_audio) - { - if (sf_close_telephony(wave_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - exit(2); - } - } - } -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c deleted file mode 100644 index 4ed2bcf7d2..0000000000 --- a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c +++ /dev/null @@ -1,710 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t38_non_ecm_buffer_tests.c - Tests for the T.38 non-ECM image data buffer module. - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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 t38_non_ecm_buffer_tests_page T.38 non-ECM buffer tests -\section t38_non_ecm_buffer_tests_page_sec_1 What does it do? -These tests exercise the flow controlling non-ECM image data buffer -module, used for T.38 gateways. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -/* A pattern of widening gaps between ones, until at 11 apart an - EOL should be registered */ -static const uint8_t spreader[] = -{ - 0x55, - 0x55, - 0x55, - 0x55, - 0x55, - 0x55, - 0x55, - 0x55, /* 1 apart */ - 0x22, /* 2 and 3 apart */ - 0x10, /* 4 apart */ - 0x40, /* 5 apart */ - 0x80, /* 6 apart */ - 0x80, /* 7 apart */ - 0x40, /* 8 apart */ - 0x10, /* 9 apart */ - 0x02, /* 10 apart */ - 0x00, - 0x25 /* 11 apart */ -}; - -static int bit_no; - -static int xxx(t38_non_ecm_buffer_state_t *s, logging_state_t *l, int log_bits, int n, int expected) -{ - int i; - int j; - int bit; - - t38_non_ecm_buffer_inject(s, &spreader[n], 1); - if (expected >= 0) - { - for (i = 0; i < 128; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) s); - if (log_bits) - printf("Rx bit %d - %d\n", bit_no, bit); - if (bit != expected) - { - printf("Tests failed - %d %d %d\n", bit_no, bit, expected); - exit(2); - } - bit_no++; - } - } - else - { - j = -1; - for (i = 0; i < 256; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) s); - if (log_bits) - printf("Rx bit %d - %d\n", bit_no, bit); - if (j < 0) - { - if (bit == 1) - j = 18*8 - 5; - } - else - { - expected = (spreader[j >> 3] >> (7 - (j & 7))) & 1; - if (bit != expected) - { - printf("Tests failed - %d %d %d\n", bit_no, bit, expected); - exit(2); - } - j++; - if (j >= 18*8) - j = 0; - } - bit_no++; - if (j == 17*8) - return 0; - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - t38_non_ecm_buffer_state_t buffer; - logging_state_t logging; - uint8_t buf[1024]; - int bit; - int n; - int log_bits; - int i; - - log_bits = (argc > 1); - printf("T.38 non-ECM rate adapting buffer tests.\n"); - span_log_init(&logging, SPAN_LOG_FLOW, NULL); - 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); - n = 0; - bit_no = 0; - /* We should get ones until the buffers recognises an EOL */ - printf(" We should get ones here\n"); - for (i = 0; i < 17; i++) - xxx(&buffer, &logging, log_bits, i, 1); - printf(" We should change to zeros here\n"); - xxx(&buffer, &logging, log_bits, i, 0); - for (i = 0; i < 17; i++) - xxx(&buffer, &logging, log_bits, i, 0); - printf(" We should get the first row here\n"); - xxx(&buffer, &logging, log_bits, i, -1); - for (i = 0; i < 17; i++) - xxx(&buffer, &logging, log_bits, i, 0); - printf(" We should get the second row here\n"); - xxx(&buffer, &logging, log_bits, i, -1); - for (i = 0; i < 17; i++) - xxx(&buffer, &logging, log_bits, i, 0); - printf(" We should get the third row here\n"); - xxx(&buffer, &logging, log_bits, i, -1); - printf(" Done\n"); - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - printf("2 - Impose no minimum for the bits per row, different alignment\n"); - 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 */ - memset(buf + 10, 0x55, 10); - /* EOL 2 */ - buf[25] = 0x20; - /* EOL 3 */ - memset(buf + 30, 0x55, 10); - /* EOL 4 */ - buf[45] = 0x10; - t38_non_ecm_buffer_inject(&buffer, buf, 50); - t38_non_ecm_buffer_push(&buffer); - for (;;) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n, bit); - n++; - if (bit == SIG_STATUS_END_OF_DATA) - { - if (n != 337) - { - printf("Tests failed\n"); - exit(2); - } - break; - } - if (n >= 18 && n <= 96) - { - if (bit == (n & 1)) - { - printf("Tests failed\n"); - exit(2); - } - } - else if (n >= 178 && n <= 256) - { - if (bit == (n & 1)) - { - printf("Tests failed\n"); - exit(2); - } - } - else if (n == 139 || n == 300) - { - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - else - { - if (bit != 0) - { - printf("Tests failed\n"); - exit(2); - } - } - } - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - printf("3 - Demand a fairly high minimum for the bits per row\n"); - 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 */ - memset(buf + 10, 0x55, 10); - /* EOL 2 */ - buf[25] = 0x08; - /* EOL 3 */ - memset(buf + 30, 0x55, 10); - /* EOL 4 */ - buf[45] = 0x04; - t38_non_ecm_buffer_inject(&buffer, buf, 50); - t38_non_ecm_buffer_push(&buffer); - for (;;) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n, bit); - n++; - if (bit == SIG_STATUS_END_OF_DATA) - { - if (n != 1273) - { - printf("Tests failed\n"); - exit(2); - } - break; - } - if (n >= 18 && n <= 96) - { - if (bit == (n & 1)) - { - printf("Tests failed\n"); - exit(2); - } - } - else if (n >= 834 && n <= 912) - { - if (bit == (n & 1)) - { - printf("Tests failed\n"); - exit(2); - } - } - else if (n == 429 || n == 1238) - { - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - else - { - if (bit != 0) - { - printf("Tests failed\n"); - exit(2); - } - } - } - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - 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); - n = 0; - /* Get some initial bits from an empty buffer. These should be ones */ - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Initial ones OK\n"); - /* Now put some zeros into the buffer, but no EOL. We should continue - getting ones out. */ - memset(buf, 0, sizeof(buf)); - t38_non_ecm_buffer_inject(&buffer, buf, 20); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Continuing initial ones OK\n"); - /* Now add a one, to make an EOL. We should see the zeros come out. */ - buf[0] = 0x01; - t38_non_ecm_buffer_inject(&buffer, buf, 1); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 0) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" First EOL caused zeros to output OK\n"); - /* Now add another line. We should see the first line come out. This means just the - 23rd bit from now will be a one. */ - buf[0] = 0x00; - buf[4] = 0x01; - t38_non_ecm_buffer_inject(&buffer, buf, 5); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if ((i == 23 && bit == 0) || (i != 23 && bit != 0)) - { - printf("Tests failed (%d)\n", i); - exit(2); - } - } - printf(" Second EOL caused the first row to output OK\n"); - /* Now inject an RTC - 6 EOLs */ - memset(buf, 0, sizeof(buf)); - /* T.4 1D style */ - for (i = 10; i < 19; i += 3) - { - buf[i] = 0x00; - buf[i + 1] = 0x10; - buf[i + 2] = 0x01; - } - /* T.4 2D style */ - buf[25 + 0] = 0x00; - buf[25 + 1] = 0x18; - buf[25 + 2] = 0x00; - buf[25 + 3] = 0xC0; - buf[25 + 4] = 0x06; - buf[25 + 5] = 0x00; - buf[25 + 6] = 0x30; - buf[25 + 7] = 0x01; - buf[25 + 8] = 0x80; - buf[25 + 9] = 0x0C; - t38_non_ecm_buffer_inject(&buffer, buf, 50); - t38_non_ecm_buffer_push(&buffer); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (i == 7 - || - i == 400 + 11 + 0*12 - || - i == 400 + 11 + 1*12 - || - i == 400 + 11 + 2*12 - || - i == 400 + 11 + 3*12 - || - i == 400 + 11 + 4*12 - || - i == 400 + 11 + 5*12 - || - i == 400 + 11 + 60 + 400 + 4 + 0*13 - || - i == 400 + 11 + 60 + 400 + 4 + 0*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 1*13 - || - i == 400 + 11 + 60 + 400 + 4 + 1*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 2*13 - || - i == 400 + 11 + 60 + 400 + 4 + 2*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 3*13 - || - i == 400 + 11 + 60 + 400 + 4 + 3*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 4*13 - || - i == 400 + 11 + 60 + 400 + 4 + 4*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 5*13 - || - i == 400 + 11 + 60 + 400 + 4 + 5*13 + 1) - { - if (bit == 0) - { - printf("Tests failed (%d)\n", i); - exit(2); - } - } - else - { - if (bit == 1) - { - printf("Tests failed (%d)\n", i); - exit(2); - } - } - } - printf(" RTC output OK\n"); - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - 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); - n = 0; - /* Inject some ones. */ - memset(buf, 0xFF, 100); - t38_non_ecm_buffer_inject(&buffer, buf, 100); - /* Inject some zeros */ - memset(buf, 0, sizeof(buf)); - t38_non_ecm_buffer_inject(&buffer, buf, 100); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Initial ones OK\n"); - /* Now add a one, to make an EOL. We should see the zeros come out. */ - buf[0] = 0x01; - t38_non_ecm_buffer_inject(&buffer, buf, 1); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 0) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" First EOL caused zeros to output OK\n"); - /* Now add another line. We should see the first line come out. This means just the - 23rd bit from now will be a one. */ - buf[0] = 0x00; - buf[4] = 0x01; - t38_non_ecm_buffer_inject(&buffer, buf, 5); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if ((i == 23 && bit == 0) || (i != 23 && bit != 0)) - { - printf("Tests failed (%d)\n", i); - exit(2); - } - } - printf(" Second EOL caused the first row to output OK\n"); - /* Now inject an RTC - 6 EOLs */ - memset(buf, 0, sizeof(buf)); - /* T.4 1D style */ - for (i = 10; i < 19; i += 3) - { - buf[i] = 0x00; - buf[i + 1] = 0x10; - buf[i + 2] = 0x01; - } - /* T.4 2D style */ - buf[25 + 0] = 0x00; - buf[25 + 1] = 0x18; - buf[25 + 2] = 0x00; - buf[25 + 3] = 0xC0; - buf[25 + 4] = 0x06; - buf[25 + 5] = 0x00; - buf[25 + 6] = 0x30; - buf[25 + 7] = 0x01; - buf[25 + 8] = 0x80; - buf[25 + 9] = 0x0C; - t38_non_ecm_buffer_inject(&buffer, buf, 50); - t38_non_ecm_buffer_push(&buffer); - for (i = 0; i < 1000; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (i == 7 - || - i == 400 + 11 + 0*12 - || - i == 400 + 11 + 1*12 - || - i == 400 + 11 + 2*12 - || - i == 400 + 11 + 3*12 - || - i == 400 + 11 + 4*12 - || - i == 400 + 11 + 5*12 - || - i == 400 + 11 + 60 + 400 + 4 + 0*13 - || - i == 400 + 11 + 60 + 400 + 4 + 0*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 1*13 - || - i == 400 + 11 + 60 + 400 + 4 + 1*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 2*13 - || - i == 400 + 11 + 60 + 400 + 4 + 2*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 3*13 - || - i == 400 + 11 + 60 + 400 + 4 + 3*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 4*13 - || - i == 400 + 11 + 60 + 400 + 4 + 4*13 + 1 - || - i == 400 + 11 + 60 + 400 + 4 + 5*13 - || - i == 400 + 11 + 60 + 400 + 4 + 5*13 + 1) - { - if (bit == 0) - { - printf("Tests failed (%d)\n", i); - exit(2); - } - } - else - { - if (bit == 1) - { - printf("Tests failed (%d)\n", i); - exit(2); - } - } - } - printf(" RTC output OK\n"); - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - printf("6 - TCF without leading ones\n"); - 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++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Initial ones from an empty TCF buffer OK\n"); - /* Now send some TCF through, and see that it comes out */ - memset(buf, 0x00, sizeof(buf)); - t38_non_ecm_buffer_inject(&buffer, buf, 500); - t38_non_ecm_buffer_push(&buffer); - for (i = 0; i < 500*8; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 0) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Passthrough of TCF OK\n"); - /* Check the right number of bits was buffered */ - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != SIG_STATUS_END_OF_DATA) - { - printf("Tests failed\n"); - exit(2); - } - printf(" End of data seen OK\n"); - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - printf("7 - TCF with leading ones\n"); - 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++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Initial ones from an empty TCF buffer OK\n"); - - /* Now send some initial ones, and see that we continue to get all ones - as the stuffing. */ - memset(buf, 0xFF, 500); - t38_non_ecm_buffer_inject(&buffer, buf, 500); - for (i = 0; i < 500*8; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != 1) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Sustaining ones OK\n"); - - /* Now send some initial ones, and some TCF through, and see that only - the TCF comes out */ - memset(buf, 0x00, sizeof(buf)); - memset(buf, 0xFF, 100); - /* End the ones mid byte */ - buf[100] = 0xF0; - t38_non_ecm_buffer_inject(&buffer, buf, 500); - t38_non_ecm_buffer_push(&buffer); - for (i = 0; i < 400*8; i++) - { - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if ((i < 4 && bit == 0) || (i >= 4 && bit != 0)) - { - printf("Tests failed\n"); - exit(2); - } - } - printf(" Passthrough of TCF OK\n"); - /* Check the right number of bits was buffered */ - bit = t38_non_ecm_buffer_get_bit((void *) &buffer); - if (log_bits) - printf("Rx bit %d - %d\n", n++, bit); - if (bit != SIG_STATUS_END_OF_DATA) - { - printf("Tests failed\n"); - exit(2); - } - printf(" End of data seen OK\n"); - t38_non_ecm_buffer_report_input_status(&buffer, &logging); - t38_non_ecm_buffer_report_output_status(&buffer, &logging); - t38_non_ecm_buffer_release(&buffer); - - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t42_tests.c b/libs/spandsp/tests/t42_tests.c deleted file mode 100644 index fd42133dfd..0000000000 --- a/libs/spandsp/tests/t42_tests.c +++ /dev/null @@ -1,623 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t42_tests.c - ITU T.42 JPEG for 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 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 t42_tests_page T.42 tests -\section t42_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) && defined(HAVE_TIF_DIR_H) -#include -#endif - -#define IN_FILE_NAME "../test-data/itu/t24/F21B400.TIF" -#define OUT_FILE_NAME "t42_tests_receive.tif" - -uint8_t data5[50000000]; -int data5_ptr = 0; -int plane = 0; -int bit_mask; - -uint8_t colour_map[3*256]; - -lab_params_t lab_param; - -int write_row = 0; - -static __inline__ uint16_t pack_16(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(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 int t85_row_write_handler(void *user_data, const uint8_t buf[], size_t len) -{ - int i; - int j; - - for (i = 0; i < len; i++) - { - for (j = 0; j < 8; j++) - { - if ((buf[i] & (0x80 >> j))) - data5[data5_ptr + 3*(8*i + j)] |= bit_mask; - else - data5[data5_ptr + 3*(8*i + j)] &= ~bit_mask; - } - } - data5_ptr += 3*8*len; - write_row++; - 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 --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - TIFF *tif; - uint32_t w; - uint32_t h; - tstrip_t nstrips; - uint32_t totdata; - tsize_t off; - uint8_t *data; - uint8_t *data2; - int row; - uint16_t compression; - int16_t photometric; - int16_t YCbCrSubsampleHoriz; - int16_t YCbCrSubsampleVert; - int16_t bits_per_pixel; - int16_t samples_per_pixel; - int16_t planar_config; - int bytes_per_row; - tsize_t outsize; - char *outptr; - const char *source_file; - int i; - int j; - int len; - tsize_t total_image_len; - tsize_t total_len; - int process_raw; - int result; - t85_decode_state_t t85_dec; - uint64_t start; - uint64_t end; - uint16_t *map_L; - uint16_t *map_a; - 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) && defined(HAVE_TIF_DIR_H) - TIFF_FX_init(); -#endif - - /* 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 */ - if ((tif = TIFFOpen(source_file, "r")) == NULL) - { - printf("Unable to open '%s'!\n", source_file); - return 1; - } - if (TIFFSetDirectory(tif, (tdir_t) 0) < 0) - { - printf("Unable to set directory '%s'!\n", source_file); - return 1; - } - - w = 0; - TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); - h = 0; - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); - bits_per_pixel = 0; - TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_pixel); - samples_per_pixel = 0; - TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); - compression = 0; - TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression); - photometric = 0; - TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric); - YCbCrSubsampleHoriz = 0; - YCbCrSubsampleVert = 0; - TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, &YCbCrSubsampleHoriz, &YCbCrSubsampleVert); - planar_config = PLANARCONFIG_CONTIG; - TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar_config); - off = 0; - - 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)) - { -#if 0 - /* Sweep the colormap in the proper order */ - for (i = 0; i < (1 << bits_per_pixel); i++) - { - colour_map[3*i] = (map_L[i] >> 8) & 0xFF; - colour_map[3*i + 1] = (map_a[i] >> 8) & 0xFF; - colour_map[3*i + 2] = (map_b[i] >> 8) & 0xFF; - printf("Map %3d - %5d %5d %5d\n", i, colour_map[3*i], colour_map[3*i + 1], colour_map[3*i + 2]); - } -#else - /* Sweep the colormap in the order that seems to work for l04x_02x.tif */ - for (i = 0; i < (1 << bits_per_pixel); i++) - { - colour_map[i] = (map_L[i] >> 8) & 0xFF; - colour_map[256 + i] = (map_a[i] >> 8) & 0xFF; - colour_map[2*256 + i] = (map_b[i] >> 8) & 0xFF; - } -#endif - lab_params_t lab; - - /* 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]); - } - else - { - printf("There is no colour map\n"); - } - process_raw = false; - printf("Compression is "); - switch (compression) - { - case COMPRESSION_CCITT_T4: - printf("T.4\n"); - return 0; - case COMPRESSION_CCITT_T6: - printf("T.6\n"); - return 0; - case COMPRESSION_T85: - printf("T.85\n"); - process_raw = true; - break; - case COMPRESSION_T43: - printf("T.43\n"); - process_raw = true; - break; - case COMPRESSION_JPEG: - printf("JPEG"); - if (photometric == PHOTOMETRIC_ITULAB) - { - printf(" ITULAB"); - process_raw = true; - } - printf("\n"); - break; - case COMPRESSION_NONE: - printf("No compression\n"); - break; - default: - printf("Unexpected compression %d\n", compression); - break; - } - - outsize = 0; - if (process_raw) - { - uint8_t *jpeg_table; - - nstrips = TIFFNumberOfStrips(tif); - - total_image_len = 0; - jpeg_table_len = 0; - if (TIFFGetField(tif, TIFFTAG_JPEGTABLES, &jpeg_table_len, &jpeg_table)) - { - total_image_len += (jpeg_table_len - 4); - printf("JPEG tables %u\n", jpeg_table_len); - printf("YYY %d - %x %x %x %x\n", jpeg_table_len, jpeg_table[0], jpeg_table[1], jpeg_table[2], jpeg_table[3]); - } - - for (i = 0, total_image_len = 0; i < nstrips; i++) - total_image_len += TIFFRawStripSize(tif, i); - if ((data = malloc(total_image_len)) == NULL) - { - printf("Failed to allocate buffer\n"); - exit(2); - } - for (i = 0, total_len = 0; i < nstrips; i++, total_len += len) - { - 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); - - if (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) - { - case COMPRESSION_CCITT_T4: - break; - case COMPRESSION_CCITT_T6: - break; - case COMPRESSION_T85: - 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); - t85_decode_set_comment_handler(&t85_dec, 1000, t85_comment_handler, NULL); - result = t85_decode_put(&t85_dec, data, total_len); - if (result == T4_DECODE_MORE_DATA) - result = t85_decode_put(&t85_dec, NULL, 0); - len = t85_decode_get_compressed_image_size(&t85_dec); - printf("Compressed image is %d bytes, %d rows\n", len/8, write_row); - t85_decode_release(&t85_dec); - return 0; - case COMPRESSION_T43: - printf("T.43 image %ld bytes\n", (long int) total_len); - if (pack_16(data) == 0xFFA8) - { - data += 2; - total_len -= 2; - for (;;) - { - if (pack_16(data) == 0xFFE1) - { - data += 2; - total_len -= 2; - len = pack_16(data); - data += len; - total_len -= len; - } - else if (pack_16(data) == 0xFFE3) - { - data += 2; - total_len -= 2; - len = pack_32(data); - data += len; - total_len -= len; - } - else - { - break; - } - } - } - - bit_mask = 0x80; - t85_decode_init(&t85_dec, t85_row_write_handler, NULL); - t85_decode_set_comment_handler(&t85_dec, 1000, t85_comment_handler, NULL); - t85_dec.min_bit_planes = 1; - t85_dec.max_bit_planes = 8; - data5_ptr = 0; - result = t85_decode_put(&t85_dec, data, total_len); - len = t85_decode_get_compressed_image_size(&t85_dec); - printf("Compressed image is %d bytes, %d rows\n", len/8, write_row); - - for (j = 1; j < t85_dec.bit_planes; j++) - { - bit_mask >>= 1; - data += len/8; - total_len -= len/8; - t85_decode_new_plane(&t85_dec); - data5_ptr = 0; - t85_decode_set_comment_handler(&t85_dec, 1000, t85_comment_handler, NULL); - result = t85_decode_put(&t85_dec, data, total_len); - len = t85_decode_get_compressed_image_size(&t85_dec); - printf("Compressed image is %d bytes, %d rows\n", len/8, write_row); - } - if (result == T4_DECODE_MORE_DATA) - { - printf("More\n"); - result = t85_decode_put(&t85_dec, NULL, 0); - } - len = t85_decode_get_compressed_image_size(&t85_dec); - printf("Compressed image is %d bytes, %d rows\n", len/8, write_row); - t85_decode_release(&t85_dec); - - for (j = 0; j < data5_ptr; j += 3) - { - i = data5[j] & 0xFF; -//printf("%d %d %d %d %d %d\n", data5_ptr, j, i, colour_map[3*i], colour_map[3*i + 1], colour_map[3*i + 2]); - data5[j] = colour_map[3*i]; - data5[j + 1] = colour_map[3*i + 1]; - data5[j + 2] = colour_map[3*i + 2]; - } - - if ((tif = TIFFOpen(OUT_FILE_NAME, "w")) == NULL) - { - printf("Unable to open '%s'!\n", OUT_FILE_NAME); - return 1; - } - TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w); - // libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL, - // or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h); - TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, (uint32) -1); - TIFFSetField(tif, TIFFTAG_XRESOLUTION, 200.0f); - TIFFSetField(tif, TIFFTAG_YRESOLUTION, 200.0f); - TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp"); - TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test"); - TIFFSetField(tif, TIFFTAG_DATETIME, "2012/07/03 12:30:45"); - TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org"); - TIFFSetField(tif, TIFFTAG_MODEL, "spandsp"); - TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org"); - - for (off = 0, i = 0; i < h; off += w*3, i++) - { - TIFFWriteScanline(tif, data5 + off, i, 0); - } - TIFFWriteDirectory(tif); - TIFFClose(tif); - return 0; - case COMPRESSION_JPEG: - break; - } - } - else - { - printf("Width %d, height %d, bits %d, samples %d\n", w, h, bits_per_pixel, samples_per_pixel); - - bytes_per_row = (bits_per_pixel + 7)/8; - bytes_per_row *= w*samples_per_pixel; - totdata = h*bytes_per_row; - printf("total %d\n", totdata); - - /* Read the image into memory. */ - if ((data = malloc(totdata)) == NULL) - { - printf("Failed to allocate buffer\n"); - exit(2); - } - off = 0; - for (row = 0; row < h; row++) - { - if (TIFFReadScanline(tif, data + off, row, 0) < 0) - return 1; - off += bytes_per_row; - } - 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 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; - } -#else - outptr = 0; -#endif - free(data); - data = (uint8_t *) outptr; - off = outsize; - } - else - { - start = rdtscll(); - switch (photometric) - { - case PHOTOMETRIC_CIELAB: - 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); - lab_to_srgb(&lab_param, data, data, w*h); - break; - case PHOTOMETRIC_ITULAB: - /* 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_jpeg(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h, 3)) - { - printf("Failed to convert to ITULAB\n"); - return 1; - } - end = rdtscll(); - printf("Duration %" PRIu64 "\n", end - start); - free(data); - data = (uint8_t *) outptr; - off = outsize; - } - } - TIFFClose(tif); - - 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 */ - - if ((tif = TIFFOpen(OUT_FILE_NAME, "w")) == NULL) - { - printf("Unable to open '%s'!\n", OUT_FILE_NAME); - return 1; - } - TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w); - /* libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL, - or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values */ - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h); - TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, (uint32) -1); - TIFFSetField(tif, TIFFTAG_XRESOLUTION, 200.0f); - TIFFSetField(tif, TIFFTAG_YRESOLUTION, 200.0f); - TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp"); - TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test"); - TIFFSetField(tif, TIFFTAG_DATETIME, "2012/07/03 12:30:45"); - TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org"); - TIFFSetField(tif, TIFFTAG_MODEL, "spandsp"); - TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org"); - - if (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 1 - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); -#else - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR); -#endif - if (YCbCrSubsampleHoriz || YCbCrSubsampleVert) - TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, YCbCrSubsampleHoriz, YCbCrSubsampleVert); - bytes_per_row = (bits_per_pixel + 7)/8; - bytes_per_row *= w*samples_per_pixel; - totdata = h*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; - t42_itulab_to_jpeg(logging, &lab_param, (void **) &data2, &totdata, data, off); - 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\n"); - return 1; - } - free(data); -#else - if ((data2 = malloc(totdata)) == NULL) - { - printf("Failed to allocate buffer\n"); - exit(2); - } - start = rdtscll(); - //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; - } - end = rdtscll(); - printf("Duration %" PRIu64 "\n", end - start); - free(data); - - off = 0; - bytes_per_row = (8 + 7)/8; - bytes_per_row *= (w*3); - for (row = 0; row < h; row++) - { - if (TIFFWriteScanline(tif, data2 + off, row, 0) < 0) - return 1; - off += bytes_per_row; - } -#endif - free(data2); - } - else - { -#if 1 - /* 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. */ - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB); -#else - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR); -#endif - if (YCbCrSubsampleHoriz || YCbCrSubsampleVert) - TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, YCbCrSubsampleHoriz, YCbCrSubsampleVert); - if (TIFFWriteRawStrip(tif, 0, (tdata_t) data, off) == -1) - { - printf("Write error to TIFF file\n"); - return 1; - } - free(data); - } - TIFFWriteDirectory(tif); - TIFFClose(tif); - printf("Done!\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t43_tests.c b/libs/spandsp/tests/t43_tests.c deleted file mode 100644 index 0896f8e6b3..0000000000 --- a/libs/spandsp/tests/t43_tests.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * 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) && defined(HAVE_TIF_DIR_H) -#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) && defined(HAVE_TIF_DIR_H) -/* 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) && defined(HAVE_TIF_DIR_H) - toff_t diroff; -#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) && defined(HAVE_TIF_DIR_H) - 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); - - diroff = 0; - if (!TIFFWriteCustomDirectory(tif, &diroff)) - printf("Failed to write custom directory.\n"); - - if (!TIFFSetDirectory(tif, (tdir_t) page)) - printf("Failed to set directory.\n"); - if (!TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, diroff)) - 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) && defined(HAVE_TIF_DIR_H) - 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; - toff_t diroff; -#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) && defined(HAVE_TIF_DIR_H) - 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) && defined(HAVE_TIF_DIR_H) - printf("Trying to get global parameters\n"); - if (TIFFGetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, &diroff)) - { - printf("Got global parameters - %" PRIu64 "\n", (uint64_t) diroff); - if (!TIFFReadCustomDirectory(tif, diroff, &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; - if ((meta->colour_map = malloc(3*entries))) - { -#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) && defined(HAVE_TIF_DIR_H) - toff_t diroff; -#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) && defined(HAVE_TIF_DIR_H) - 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; - } -#else - outsize = 0; -#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) && defined(HAVE_TIF_DIR_H) - /* 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 - if ((data2 = malloc(totdata)) == NULL) - { - printf("Failed to allocate buffer\n"); - exit(2); - } - 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) && defined(HAVE_TIF_DIR_H) - 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); - - diroff = 0; - if (!TIFFWriteCustomDirectory(tif, &diroff)) - 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, diroff)) - 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 deleted file mode 100644 index 476f737530..0000000000 --- a/libs/spandsp/tests/t4_t6_tests.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_t6_tests.c - ITU T.4 and T.6 FAX image compression and decompression tests - * - * Written by Steve Underwood - * - * Copyright (C) 2003, 2009 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 t4_t6_tests_page T.4 and T.6 image compress and decompression tests -\section t4_t6_tests_page_sec_1 What does it do -These tests exercise the image compression and decompression methods defined -in ITU specifications T.4 and T.6. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -//#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define XSIZE 1728 - -t4_t6_encode_state_t *send_state; -t4_t6_decode_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 - -#define TEST_ROWS 16 -static const char t4_t6_test_patterns[TEST_ROWS][XSIZE + 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). */ -}; - -#if 0 -static void dump_image_as_xxx(const uint8_t buf[], int bytes_per_row, int len) -{ - const uint8_t *s; - int i; - int j; - int k; - - /* Dump the entire image as text 'X's and spaces */ - printf("Image (%d pixels x %d pixels):\n", bytes_per_row*8, len/bytes_per_row); - s = buf; - for (i = 0; i < len; i++) - { - for (j = 0; j < bytes_per_row; j++) - { - for (k = 0; k < 8; k++) - printf((buf[i*bytes_per_row + j] & (0x80 >> k)) ? "X" : " "); - } - printf("\n"); - } -} -/*- End of function --------------------------------------------------------*/ -#endif - -static int row_read_handler(void *user_data, uint8_t buf[], size_t len) -{ - int i; - int j; - const char *s; - static int row = 0; - - /* Send the test pattern. */ - if (row >= TEST_ROWS) - { - row = 0; - return 0; - } - s = t4_t6_test_patterns[row++]; - 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, row); - 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; - static int row = 0; - uint8_t ref[8192]; - - /* Verify that what is received matches the test pattern. */ - //printf("Row %d\n", row); - if (len == 0) - return 0; - s = t4_t6_test_patterns[row++]; - if (row >= TEST_ROWS) - row = 0; - 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, row); - if (memcmp(buf, ref, len)) - { - printf("Test failed at row %d\n", row); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int detect_page_end(int bit, int page_ended) -{ - static int consecutive_eols; - static int max_consecutive_eols; - static int consecutive_zeros; - static int consecutive_ones; - static int eol_zeros; - static int eol_ones; - static int expected_eols; - static int end_marks; - - /* Check the EOLs are added properly to the end of an image. We can't rely on the - decoder giving the right answer, as a full set of EOLs is not needed for the - decoder to work. */ - if (bit == -1000000) - { - /* Reset */ - consecutive_eols = 0; - max_consecutive_eols = 0; - consecutive_zeros = 0; - consecutive_ones = 0; - end_marks = 0; - - eol_zeros = 11; - eol_ones = (page_ended == T4_COMPRESSION_T4_2D) ? 2 : 1; - expected_eols = (page_ended == T4_COMPRESSION_T6) ? 2 : 6; - return 0; - } - - /* Monitor whether the EOLs are there in the correct amount */ - if (bit == 0) - { - consecutive_zeros++; - consecutive_ones = 0; - } - else if (bit == 1) - { - if (++consecutive_ones == eol_ones) - { - if (consecutive_eols == 0 && consecutive_zeros >= eol_zeros) - consecutive_eols++; - else if (consecutive_zeros == eol_zeros) - consecutive_eols++; - else - consecutive_eols = 0; - consecutive_zeros = 0; - consecutive_ones = 0; - } - if (max_consecutive_eols < consecutive_eols) - max_consecutive_eols = consecutive_eols; - } - else if (bit == SIG_STATUS_END_OF_DATA) - { - if (end_marks == 0) - { - if (max_consecutive_eols != expected_eols) - { - printf("Only %d EOLs (should be %d)\n", max_consecutive_eols, expected_eols); - return 2; - } - consecutive_zeros = 0; - consecutive_eols = 0; - max_consecutive_eols = 0; - } - if (!page_ended) - { - /* We might need to push a few bits to get the receiver to report the - end of page condition (at least with T.6). */ - if (++end_marks > 50) - { - printf("Receiver missed the end of page mark\n"); - return 2; - } - return 0; - } - return 1; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - static const int compression_sequence[] = - { - T4_COMPRESSION_T4_1D, - T4_COMPRESSION_T4_2D, - T4_COMPRESSION_T6, - -1 - }; - int bit; - int end_of_page; - int end_marks; - int compression; - int compression_step; - int min_row_bits; - int opt; - int tests_failed; - int block_size; - int len; - int res; - uint8_t chunk_buf[1024]; - - tests_failed = 0; - compression = -1; - compression_step = 0; - /* Use a non-zero default minimum row length to ensure we test the consecutive EOLs part - properly. */ - min_row_bits = 50; - block_size = 0; - while ((opt = getopt(argc, argv, "b:c:m:")) != -1) - { - switch (opt) - { - case 'b': - block_size = atoi(optarg); - if (block_size > 1024) - block_size = 1024; - break; - case 'c': - if (strcmp(optarg, "T41D") == 0) - { - compression = T4_COMPRESSION_T4_1D; - compression_step = -1; - } - else if (strcmp(optarg, "T42D") == 0) - { - compression = T4_COMPRESSION_T4_2D; - compression_step = -1; - } - else if (strcmp(optarg, "T6") == 0) - { - compression = T4_COMPRESSION_T6; - compression_step = -1; - } - break; - case 'm': - min_row_bits = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - - 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, -1, row_read_handler, NULL)) == NULL) - { - printf("Failed to init T.4/T.6 encoder\n"); - exit(2); - } - span_log_set_level(t4_t6_encode_get_logging_state(send_state), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - t4_t6_encode_set_min_bits_per_row(send_state, min_row_bits); - t4_t6_encode_set_max_2d_rows_per_1d_row(send_state, 2); - - /* Receive end puts TIFF to a function. */ - if ((receive_state = t4_t6_decode_init(NULL, compression, 1728, row_write_handler, NULL)) == NULL) - { - printf("Failed to init T.4/T.6 decoder\n"); - exit(2); - } - span_log_set_level(t4_t6_decode_get_logging_state(receive_state), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - - /* 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) - break; - } - t4_t6_encode_set_encoding(send_state, compression); - t4_t6_decode_set_encoding(receive_state, compression); - - if (t4_t6_encode_restart(send_state, 1728, -1)) - break; - if (t4_t6_decode_restart(receive_state, 1728)) - break; - detect_page_end(-1000000, compression); - switch (block_size) - { - case 0: - end_of_page = false; - for (;;) - { - bit = t4_t6_encode_get_bit(send_state); - if ((res = detect_page_end(bit, end_of_page))) - { - if (res != 1) - { - printf("Test failed\n"); - exit(2); - } - break; - } - if (!end_of_page) - end_of_page = t4_t6_decode_put_bit(receive_state, bit & 1); - } - break; - default: - do - { - len = t4_t6_encode_get(send_state, chunk_buf, block_size); - if (len == 0) - { - if (++end_marks > 50) - { - printf("Receiver missed the end of page mark\n"); - tests_failed++; - break; - } - chunk_buf[0] = 0xFF; - len = 1; - } - end_of_page = t4_t6_decode_put(receive_state, chunk_buf, len); - } - while (!end_of_page); - break; - } - if (compression_step < 0) - break; - } - t4_t6_encode_free(send_state); - t4_t6_decode_free(receive_state); -#endif - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t4_tests.c b/libs/spandsp/tests/t4_tests.c deleted file mode 100644 index f8e1cfe367..0000000000 --- a/libs/spandsp/tests/t4_tests.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t4_tests.c - ITU T.4 FAX image to and from TIFF file tests - * - * 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 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 t4_tests_page T.4 tests -\section t4_tests_page_sec_1 What does it do -These tests exercise the image compression and decompression methods defined -in ITU specifications T.4 and T.6. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define IN_FILE_NAME "../test-data/itu/fax/itutests.tif" -#define OUT_FILE_NAME "t4_tests_receive.tif" - -#define XSIZE 1728 - -t4_tx_state_t *send_state; -t4_rx_state_t *receive_state; - -int rows_written = 0; -int rows_read = 0; - -static void dump_image_as_xxx(t4_rx_state_t *state) -{ -#if 0 - uint8_t *s; - int i; - int j; - int k; - - /* Dump the entire image as text 'X's and spaces */ - printf("Image (%d x %d):\n", state->t4_t6.image_width, state->t4_t6.image_length); - s = state->image_buffer; - for (i = 0; i < state->t4_t6.image_length; i++) - { - for (j = 0; j < state->t4_t6.bytes_per_row; j++) - { - for (k = 0; k < 8; k++) - printf((state->image_buffer[i*state->t4_t6.bytes_per_row + j] & (0x80 >> k)) ? "X" : " "); - } - printf("\n"); - } -#endif -} -/*- End of function --------------------------------------------------------*/ - -static void display_page_stats(t4_rx_state_t *s) -{ - t4_stats_t stats; - - t4_rx_get_transfer_statistics(s, &stats); - printf("Pages = %d\n", stats.pages_transferred); - 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); - printf("Raw image resolution = %d pels/m x %d pels/m\n", stats.image_x_resolution, stats.image_y_resolution); - printf("Image resolution = %d pels/m x %d pels/m\n", stats.x_resolution, stats.y_resolution); - printf("Bad rows = %d\n", stats.bad_rows); - printf("Longest bad row run = %d\n", stats.longest_bad_row_run); - printf("Bits per row - min %d, max %d\n", s->decoder.t4_t6.min_row_bits, s->decoder.t4_t6.max_row_bits); -} -/*- End of function --------------------------------------------------------*/ - -static int detect_non_ecm_page_end(int bit, int page_ended) -{ - static int consecutive_eols; - static int max_consecutive_eols; - static int consecutive_zeros; - static int consecutive_ones; - static int eol_zeros; - static int eol_ones; - static int expected_eols; - static int end_marks; - - /* Check the EOLs are added properly to the end of 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; - max_consecutive_eols = 0; - consecutive_zeros = 0; - consecutive_ones = 0; - end_marks = 0; - - eol_zeros = 11; - eol_ones = (page_ended == T4_COMPRESSION_T4_2D) ? 2 : 1; - expected_eols = (page_ended == T4_COMPRESSION_T6) ? 2 : 6; - return 0; - } - - /* Monitor whether the EOLs are there in the correct amount */ - if (bit == 0) - { - consecutive_zeros++; - consecutive_ones = 0; - } - else if (bit == 1) - { - if (++consecutive_ones == eol_ones) - { - if (consecutive_eols == 0 && consecutive_zeros >= eol_zeros) - consecutive_eols++; - else if (consecutive_zeros == eol_zeros) - consecutive_eols++; - else - consecutive_eols = 0; - consecutive_zeros = 0; - consecutive_ones = 0; - } - if (max_consecutive_eols < consecutive_eols) - max_consecutive_eols = consecutive_eols; - } - else if (bit == SIG_STATUS_END_OF_DATA) - { - if (end_marks == 0) - { - if (max_consecutive_eols != expected_eols) - { - printf("Only %d EOLs (should be %d)\n", max_consecutive_eols, expected_eols); - return 2; - } - consecutive_zeros = 0; - consecutive_eols = 0; - max_consecutive_eols = 0; - } - if (!page_ended) - { - /* We might need to push a few bits to get the receiver to report the - end of page condition (at least with T.6). */ - if (++end_marks > 50) - { - printf("Receiver missed the end of page mark\n"); - return 2; - } - return 0; - } - return 1; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - static const int compression_sequence[] = - { - //T4_COMPRESSION_NONE, - 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_T42_T81, - T4_COMPRESSION_SYCC_T81, -#endif -#if defined(SPANDSP_SUPPORT_T43x) - T4_COMPRESSION_T43, -#endif -#if defined(SPANDSP_SUPPORT_T45x) - T4_COMPRESSION_T45, -#endif - -1 - }; - int sends; - int bit; - int end_of_page; - int end_marks; - int res; - int compression; - int x_resolution; - int y_resolution; - int compression_step; - int min_row_bits; - int block_size; - char buf[1024]; - uint8_t block[1024]; - const char *in_file_name; - const char *decode_file_name; - const char *page_header_tz; - tz_t tz; - int opt; - int len; - int i; - int bit_error_rate; - int tests_failed; - int match_pos; - 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; - FILE *file; - - tests_failed = 0; - compression = -1; - compression_step = 0; - x_resolution = -1; - y_resolution = -1; - 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; - /* Use a non-zero default minimum row length to ensure we test the consecutive EOLs part - properly. */ - min_row_bits = 50; - block_size = 1; - bit_error_rate = 0; - dump_as_xxx = false; - while ((opt = getopt(argc, argv, "b:c:d:ehHrR:i:m:t:x")) != -1) - { - switch (opt) - { - case 'b': - block_size = atoi(optarg); - if (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_T4_1D; - compression_step = -1; - } - else if (strcmp(optarg, "T42D") == 0) - { - compression = T4_COMPRESSION_T4_2D; - compression_step = -1; - } - else if (strcmp(optarg, "T6") == 0) - { - compression = T4_COMPRESSION_T6; - compression_step = -1; - } - else if (strcmp(optarg, "T85") == 0) - { - 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; - break; - case 'e': - bit_error_rate = 0x3FF; - break; - case 'h': - add_page_headers = true; - overlay_page_headers = false; - break; - case 'H': - add_page_headers = true; - overlay_page_headers = true; - break; - case 'r': - restart_pages = true; - break; - case 'R': - if (strcmp(optarg, "standard") == 0) - { - y_resolution = T4_Y_RESOLUTION_STANDARD; - } - else if (strcmp(optarg, "fine") == 0) - { - y_resolution = T4_Y_RESOLUTION_FINE; - } - else if (strcmp(optarg, "superfine") == 0) - { - y_resolution = T4_Y_RESOLUTION_SUPERFINE; - } - break; - case 'i': - in_file_name = optarg; - break; - case 'm': - min_row_bits = atoi(optarg); - break; - case 't': - page_header_tz = optarg; - break; - case 'x': - dump_as_xxx = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - end_of_page = T4_DECODE_MORE_DATA; - if (decode_file_name) - { - if (compression < 0) - compression = T4_COMPRESSION_T4_1D; - if (x_resolution < 0) - x_resolution = T4_X_RESOLUTION_R8; - if (y_resolution < 0) - y_resolution = T4_Y_RESOLUTION_STANDARD; - /* 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_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_rx_encoding(receive_state, compression); - t4_rx_set_x_resolution(receive_state, x_resolution); - t4_rx_set_y_resolution(receive_state, y_resolution); - t4_rx_set_image_width(receive_state, XSIZE); - - t4_rx_start_page(receive_state); - last_pkt_no = 0; - file = fopen(decode_file_name, "r"); - while (fgets(buf, 1024, file)) - { - if (sscanf(buf, "HDLC: FCD: 06 %x", &pkt_no) == 1) - { - /* Useful for breaking up T.38 ECM logs */ - for (i = 0; i < 256; i++) - { - if (sscanf(&buf[18 + 3*i], "%x", (unsigned int *) &bit) != 1) - break; - block[i] = bit; - } - end_of_page = t4_rx_put(receive_state, block, i); - } - else if (sscanf(buf, "HDLC: %x", &pkt_no) == 1) - { - /* Useful for breaking up HDLC decodes of ECM logs */ - for (i = 0; i < 256; i++) - { - if (sscanf(&buf[19 + 3*i], "%x", (unsigned int *) &bit) != 1) - break; - block[i] = bit; - } - end_of_page = t4_rx_put(receive_state, block, i); - } - else if (sscanf(buf, "%*d:%*d:%*d.%*d T.38 Rx %d: IFP %x %x %x %x %x %n", &pkt_no, (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit, &match_pos) == 6) - { - /* Useful for breaking up T.38 non-ECM logs */ - if (pkt_no != last_pkt_no + 1) - printf("Packet %u\n", pkt_no); - last_pkt_no = pkt_no; - for (i = 0; i < 256; i++) - { - if (sscanf(&buf[match_pos + 3*i], "%x", (unsigned int *) &bit) != 1) - break; - block[i] = bit_reverse8(bit); - } - end_of_page = t4_rx_put(receive_state, block, i); - } - else if (strlen(buf) > 2 && sscanf(buf, "T.30 Rx: %x %x %x %x", (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &pkt_no) == 4) - { - /* Useful for breaking up ECM logs */ - if (pkt_no != last_pkt_no + 1) - printf("Packet %u\n", pkt_no); - last_pkt_no = pkt_no; - for (i = 0; i < 256; i++) - { - if (sscanf(&buf[22 + 3*i], "%x", (unsigned int *) &bit) != 1) - break; - block[i] = bit_reverse8(bit); - } - end_of_page = t4_rx_put(receive_state, block, i); - } - else if (sscanf(buf, "%04x %02x %02x %02x", (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit) == 4) - { - for (i = 0; i < 16; i++) - { - if (sscanf(&buf[6 + 3*i], "%x", (unsigned int *) &bit) != 1) - break; - block[i] = bit_reverse8(bit); - } - end_of_page = t4_rx_put(receive_state, block, i); - } - else if (sscanf(buf, "%08x %02x %02x %02x", (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit, (unsigned int *) &bit) == 4) - { - for (i = 0; i < 16; i++) - { - if (sscanf(&buf[10 + 3*i], "%x", (unsigned int *) &bit) != 1) - break; - block[i] = bit_reverse8(bit); - } - end_of_page = t4_rx_put(receive_state, block, i); - } - else if (sscanf(buf, "Rx bit %*d - %d", &bit) == 1) - { - if ((end_of_page = t4_rx_put_bit(receive_state, bit))) - { - printf("End of page detected\n"); - break; - } - } - } - fclose(file); - if (dump_as_xxx) - dump_image_as_xxx(receive_state); - t4_rx_end_page(receive_state); - display_page_stats(receive_state); - t4_rx_free(receive_state); - } - else - { -#if 1 - printf("Testing TIFF->compress->decompress->TIFF cycle\n"); - /* Send end gets TIFF from a file */ - if ((send_state = t4_tx_init(NULL, in_file_name, -1, -1)) == NULL) - { - printf("Failed to init T.4 send\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_min_bits_per_row(send_state, min_row_bits); - 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_T4_2D)) == NULL) - { - printf("Failed to init T.4 rx for '%s'\n", OUT_FILE_NAME); - 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); - - /* Now send and receive all the pages in the source TIFF file */ - sends = 0; - /* 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; - /* Add a header line to alternate pages, if required */ - if (add_page_headers && (sends & 2)) - t4_tx_set_header_info(send_state, "Header"); - else - t4_tx_set_header_info(send_state, NULL); - if (page_header_tz && page_header_tz[0]) - { - if (tz_init(&tz, page_header_tz)) - t4_tx_set_header_tz(send_state, &tz); - } - t4_tx_set_header_overlays_image(send_state, overlay_page_headers); - if (restart_pages && (sends & 1)) - { - /* Use restart, to send the page a second time */ - if (t4_tx_restart_page(send_state)) - break; - } - else - { - if (compression_step >= 0) - { - compression = compression_sequence[compression_step++]; - if (compression < 0 || (block_size == 0 && compression_step >= 3)) - { - compression_step = 0; - compression = compression_sequence[compression_step++]; - } - } - 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_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_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_non_ecm_page_end(bit, page_ended))) - { - printf("Incorrect EOLs - %d\n", res); - tests_failed += (res - 1); - break; - } - 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: - 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); - /* 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) - { - 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; - } - if (dump_as_xxx) - dump_image_as_xxx(receive_state); - display_page_stats(receive_state); - if (!restart_pages || (sends & 1)) - t4_tx_end_page(send_state); - t4_rx_end_page(receive_state); - sends++; - } - t4_tx_free(send_state); - t4_rx_free(receive_state); - /* And we should now have a matching received TIFF file. Note this will only match - at the image level. TIFF files allow a lot of ways to express the same thing, - so bit matching of the files is not the normal case. */ - fflush(stdout); - sprintf(buf, "tiffcmp -t %s %s", in_file_name, OUT_FILE_NAME); - if (tests_failed || system(buf)) - { - printf("Tests failed\n"); - exit(2); - } -#endif - printf("Tests passed\n"); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t81_t82_arith_coding_tests.c b/libs/spandsp/tests/t81_t82_arith_coding_tests.c deleted file mode 100644 index 7df59567ea..0000000000 --- a/libs/spandsp/tests/t81_t82_arith_coding_tests.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t81_t82_arith_coding_tests.c - Tests for the ITU T.81 and T.82 arithmetic - * encoder/decoder, based on the test description - * in T.82 - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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 t81_t82_arith_coding_tests_page T.81 and T.82 Arithmetic encoder/decoder tests -\section t81_t82_arith_coding_tests_pagesec_1 What does it do -These tests exercise the arithmetic encoder and decoder for T.81 and T.82. As T.85 is based -on T.82, this is also the arithmetic coder for T.85. - -These tests are based on T.82 section 7. Nothing beyond the prescibed tests is performed at -the present time. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define MSG_SIZE 10000 - -uint8_t msg[MSG_SIZE]; - -int32_t msg_len; - -static void write_byte(void *user_data, int byte) -{ - if (msg_len < MSG_SIZE) - msg[msg_len++] = byte; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - t81_t82_arith_encode_state_t *se; - t81_t82_arith_decode_state_t *sd; - int i; - int j; - int test_failed; - int pix; - const uint8_t *pp; - /* Test data from T.82 7.1 */ - static const uint16_t pix_7_1[16] = - { - 0x05E0, 0x0000, 0x8B00, 0x01C4, 0x1700, 0x0034, 0x7FFF, 0x1A3F, - 0x951B, 0x05D8, 0x1D17, 0xE770, 0x0000, 0x0000, 0x0656, 0x0E6A - }; - /* Test data from T.82 7.1 */ - static const uint16_t cx_7_1[16] = - { - 0x0FE0, 0x0000, 0x0F00, 0x00F0, 0xFF00, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 - }; - /* Test data from T.82 7.1 - scd with stuffing and SDNORM termination */ - static const uint8_t sde_7_1[32] = - { - 0x69, 0x89, 0x99, 0x5C, 0x32, 0xEA, 0xFA, 0xA0, - 0xD5, 0xFF, 0x00, 0x52, 0x7F, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0x00, 0x2D, 0x20, 0x82, 0x91, 0xFF, 0x02 - }; -#define SDE_7_1_LEN 30 /* Don't include the termination SDNORM */ -#define SDE_7_1_FULL_LEN 32 /* Include the termination SDNORM */ - - printf("T.81/T.82 arithmetic encoder tests, from ITU-T T.82\n\n"); - - printf("Arithmetic encoder tests from ITU-T T.82/7.1\n"); - if ((se = t81_t82_arith_encode_init(NULL, write_byte, NULL)) == NULL) - { - fprintf(stderr, "Failed to allocate arithmetic encoder!\n"); - exit(2); - } - msg_len = 0; - for (i = 0; i < 16; i++) - { - for (j = 0; j < 16; j++) - { - t81_t82_arith_encode(se, - (cx_7_1[i] >> (15 - j)) & 1, - (pix_7_1[i] >> (15 - j)) & 1); - } - } - t81_t82_arith_encode_flush(se); - if (msg_len != SDE_7_1_LEN || memcmp(msg, sde_7_1, SDE_7_1_LEN)) - { - printf("Encoded data: "); - for (i = 0; i < msg_len; i++) - printf("%02X", msg[i]); - printf("\n"); - printf("Expected data: "); - for (i = 0; i < SDE_7_1_LEN; i++) - printf("%02X", sde_7_1[i]); - printf("\n"); - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - - printf("Arithmetic decoder tests from ITU-T T.82/7.1\n"); - printf("Decoding byte by byte...\n"); - test_failed = false; - if ((sd = t81_t82_arith_decode_init(NULL)) == NULL) - { - fprintf(stderr, "Failed to allocate arithmetic decoder!\n"); - exit(2); - } - pp = sde_7_1; - sd->pscd_ptr = pp; - sd->pscd_end = pp + 1; - for (i = 0; i < 16; i++) - { - for (j = 0; j < 16; j++) - { - for (;;) - { - pix = t81_t82_arith_decode(sd, (cx_7_1[i] >> (15 - j)) & 1); - if ((pix >= 0 || sd->pscd_end >= sde_7_1 + SDE_7_1_FULL_LEN)) - break; - pp++; - if (sd->pscd_ptr != pp - 1) - sd->pscd_ptr = pp; - sd->pscd_end = pp + 1; - } - if (pix < 0) - { - printf("Bad pixel %d, byte %" PRIdPTR ".\n\n", - i*16 + j + 1, - sd->pscd_ptr - sd->pscd_end); - test_failed = true; - break; - } - if (pix != ((pix_7_1[i] >> (15 - j)) & 1)) - { - printf("Bad PIX (%d) at pixel %d.\n\n", - pix, - i*16 + j + 1); - test_failed = true; - break; - } - } - } - if (sd->pscd_ptr != sd->pscd_end - 2) - { - printf("%" PRIdPTR " bytes left after decoder finished.\n\n", - sd->pscd_end - sd->pscd_ptr - 2); - test_failed = true; - } - if (test_failed) - { - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - - printf("Decoding chunk by chunk...\n"); - 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; - for (i = 0; i < 16; i++) - { - for (j = 0; j < 16; j++) - { - pix = t81_t82_arith_decode(sd, (cx_7_1[i] >> (15 - j)) & 1); - if (pix < 0) - { - printf("Bad pixel %d, byte %" PRIdPTR ".\n\n", - i*16 + j + 1, - sd->pscd_ptr - sd->pscd_end); - test_failed = true; - break; - } - if (pix != ((pix_7_1[i] >> (15 - j)) & 1)) - { - printf("Bad PIX (%d) at pixel %d.\n\n", - pix, - i*16 + j + 1); - test_failed = true; - break; - } - } - } - if (sd->pscd_ptr != sd->pscd_end - 2) - { - printf("%" PRIdPTR " bytes left after decoder finished.\n\n", - sd->pscd_end - sd->pscd_ptr - 2); - test_failed = true; - } - if (test_failed) - { - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - t81_t82_arith_encode_free(se); - t81_t82_arith_decode_free(sd); - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t85_tests.c b/libs/spandsp/tests/t85_tests.c deleted file mode 100644 index 338fe30caf..0000000000 --- a/libs/spandsp/tests/t85_tests.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * t85_tests.c - ITU T.85 FAX image compression and decompression tests - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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. - */ - -/* - * These tests are based on code from Markus Kuhn's jbigkit. See - * http://www.cl.cam.ac.uk/~mgk25/ - * - * jbigkit is GPL2 licenced. This file is also GPL2 licenced, and our - * T.85 code is LGPL2.1 licenced. There are no licence incompatibilities - * in this reuse of Markus's work. - */ - -/*! \file */ - -/*! \page t85_tests_page T.85 image compress and decompression tests -\section t85_tests_page_sec_1 What does it do -These tests exercise the image compression and decompression methods defined -in ITU specifications T.85. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -#define TESTBUF_SIZE 400000 -#define TEST_IMAGE_SIZE (1951*1960/8) - -uint8_t testbuf[TESTBUF_SIZE]; -uint8_t test_image[TEST_IMAGE_SIZE]; - -size_t testbuf_len; - -int read_row = 0; -int write_row = 0; - -int clip_to_row = 0; - -static int row_read_handler(void *user_data, uint8_t buf[], size_t len) -{ - memcpy(buf, &test_image[len*read_row], len); - if (clip_to_row && read_row == clip_to_row) - { - clip_to_row = 0; - return 0; - } - read_row++; - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int row_write_handler(void *user_data, const uint8_t buf[], size_t len) -{ - uint8_t *bitmap; - - bitmap = (uint8_t *) user_data; - memcpy(&bitmap[len*write_row], buf, len); - //printf("Write row %d\n", write_row); - write_row++; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int 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 void create_test_image(uint8_t *pic) -{ - int i; - int j; - uint32_t sum; - uint32_t prsg; - uint32_t repeat[8]; - uint8_t *p; - - /* Cook up the test image defined in T.82/7.2.1. This image is 1960 x 1951 - pixels, and occupies a single plane (which it has to for T.85). */ - memset(pic, 0, TEST_IMAGE_SIZE); - p = pic; - prsg = 1; - for (i = 0; i < 1951; i++) - { - for (j = 0; j < 1960; j++) - { - if (i >= 192) - { - if (i < 1023 || (j & (3 << 3)) == 0) - { - sum = (prsg & 1) - + ((prsg >> 2) & 1) - + ((prsg >> 11) & 1) - + ((prsg >> 15) & 1); - prsg = (prsg << 1) + (sum & 1); - if ((prsg & 3) == 0) - { - *p |= (1 << (7 - (j & 7))); - repeat[j & 7] = 1; - } - else - { - repeat[j & 7] = 0; - } - } - else - { - if (repeat[j & 7]) - *p |= 1 << (7 - (j & 7)); - } - } - if ((j & 7) == 7) - ++p; - } - } - - /* Verify the test image has been generated OK, by checking the number of set pixels */ - sum = 0; - for (i = 0; i < TEST_IMAGE_SIZE; i++) - { - for (j = 0; j < 8; j++) - sum += ((pic[i] >> j) & 1); - } - if (sum != 861965) - { - printf("WARNING: Test image has %" PRIu32 " foreground pixels. There should be 861965.\n", - sum); - } -} -/*- End of function --------------------------------------------------------*/ - -/* Perform a test cycle, as defined in T.82/7, with one set of parameters. */ -static int test_cycle(const char *test_id, - const uint8_t *image, - uint32_t width, - uint32_t height, - uint32_t l0, - int mx, - int options, - int optionsx, - const uint8_t *comment, - size_t correct_length) -{ - t85_encode_state_t *t85_enc; - t85_decode_state_t *t85_dec; - long int l; - size_t image_size; - int result; - int len; - int max_len; - size_t bytes_per_row; - size_t cnt_a; - size_t cnt_b; - uint8_t *decoded_image; - - printf("%s: TPBON=%d, LRLTWO=%d, Mx=%d, L0=%" PRIu32 "\n", - test_id, - (options & T85_TPBON) ? 1 : 0, - (options & T85_LRLTWO) ? 1 : 0, - mx, - l0); - - printf("%s.1: Encode\n", test_id); - bytes_per_row = (width + 7)/8; - image_size = bytes_per_row*height; - - if ((optionsx & T85_VLENGTH)) - { - t85_enc = t85_encode_init(NULL, width, height + 10, row_read_handler, NULL); - clip_to_row = height; - } - else - { - t85_enc = t85_encode_init(NULL, width, height, row_read_handler, NULL); - clip_to_row = 0; - } - read_row = 0; - t85_encode_set_options(t85_enc, l0, mx, options); - /* A comment inserted here should always succeed. The later one, inserted some way - down the image, will only succeed if a new chunk is started afterwards. */ - if (comment) - t85_encode_comment(t85_enc, comment, strlen((const char *) comment) + 1); - - testbuf_len = 0; - max_len = 100; - while ((len = t85_encode_get(t85_enc, &testbuf[testbuf_len], max_len)) > 0) - { - testbuf_len += len; - max_len = 100; - if (testbuf_len + 100 > TESTBUF_SIZE) - max_len = TESTBUF_SIZE - testbuf_len; - if (comment && testbuf_len == 1000) - t85_encode_comment(t85_enc, comment, strlen((const char *) comment) + 1); - } - printf("Encoded BIE has %lu bytes\n", (unsigned long int) testbuf_len); - if (correct_length > 0) - { - if (testbuf_len != correct_length) - { - printf("Incorrect encoded length. Should have been %lu\n", (unsigned long int) correct_length); - printf("Test failed\n"); - exit(2); - } - printf("Test passed\n"); - } - - cnt_a = t85_encode_get_compressed_image_size(t85_enc); - t85_encode_free(t85_enc); - - printf("%s.2: Decode in one big chunk\n", test_id); - if ((decoded_image = (uint8_t *) malloc(image_size)) == NULL) - { - fprintf(stderr, "Out of memory!\n"); - exit(2); - } - t85_dec = t85_decode_init(NULL, row_write_handler, decoded_image); - if (comment && comment[0] != 'X') - t85_decode_set_comment_handler(t85_dec, 1000, comment_handler, NULL); - write_row = 0; - result = t85_decode_put(t85_dec, testbuf, testbuf_len); - if (result == T4_DECODE_MORE_DATA) - result = t85_decode_put(t85_dec, NULL, 0); - cnt_b = t85_decode_get_compressed_image_size(t85_dec); - if (cnt_a != cnt_b || cnt_a != testbuf_len*8 || result != T4_DECODE_OK) - { - printf("Decode result %d\n", result); - printf("%ld/%ld bits of %ld bits of BIE read. %lu lines decoded.\n", - (long int) cnt_a, - (long int) cnt_b, - (unsigned long int) testbuf_len*8, - (unsigned long int) t85_dec->y); - printf("Test failed\n"); - exit(2); - } - if (memcmp(decoded_image, image, image_size)) - { - printf("Image mismatch\n"); - printf("Test failed\n"); - exit(2); - } - free(decoded_image); - t85_decode_free(t85_dec); - printf("Test passed\n"); - - printf("%s.3: Decode byte by byte\n", test_id); - if ((decoded_image = (uint8_t *) malloc(image_size)) == NULL) - { - fprintf(stderr, "Out of memory!\n"); - exit(2); - } - t85_dec = t85_decode_init(NULL, row_write_handler, decoded_image); - if (comment && comment[0] != 'X') - t85_decode_set_comment_handler(t85_dec, 1000, comment_handler, NULL); - write_row = 0; - result = T4_DECODE_MORE_DATA; - for (l = 0; l < testbuf_len; l++) - { - result = t85_decode_put(t85_dec, &testbuf[l], 1); - if (result != T4_DECODE_MORE_DATA) - { - l++; - break; - } - } - if (result == T4_DECODE_MORE_DATA) - result = t85_decode_put(t85_dec, NULL, 0); - if (l != testbuf_len || result != T4_DECODE_OK) - { - printf("Decode result %d\n", result); - printf("%ld bytes of %ld bytes of BIE read. %lu lines decoded.\n", - (long int) l, - (unsigned long int) testbuf_len, - (unsigned long int) t85_dec->y); - printf("Test failed\n"); - exit(2); - } - if (memcmp(decoded_image, image, image_size)) - { - printf("Image mismatch\n"); - printf("Test failed\n"); - exit(2); - } - free(decoded_image); - t85_decode_free(t85_dec); - printf("Test passed\n"); - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char **argv) -{ - printf("T.85 JBIG for FAX encoder and decoder tests, from ITU-T T.82\n\n"); - - printf("Generating the test image from T.82...\n"); - create_test_image(test_image); - - /* Run through the tests in T.82/7.2, which are applicable to T.85 */ - test_cycle("1", test_image, 1960, 1951, 1951, 0, 0, 0, NULL, 317384); - test_cycle("2", test_image, 1960, 1951, 1951, 0, T85_LRLTWO, 0, NULL, 317132); - test_cycle("3", test_image, 1960, 1951, 128, 8, T85_TPBON, 0, NULL, 253653); - /* Again with a comment added and handled */ - test_cycle("4", test_image, 1960, 1951, 1951, 0, 0, 0, (const uint8_t *) "Comment 4", 317384 + 16); - test_cycle("5", test_image, 1960, 1951, 1951, 0, T85_LRLTWO, 0, (const uint8_t *) "Comment 5", 317132 + 16); - test_cycle("6", test_image, 1960, 1951, 128, 8, T85_TPBON, 0, (const uint8_t *) "Comment 6", 253653 + 2*16); - /* Again with a comment added, but not handled */ - test_cycle("7", test_image, 1960, 1951, 1951, 0, 0, 0, (const uint8_t *) "Xomment 7", 317384 + 16); - test_cycle("8", test_image, 1960, 1951, 1951, 0, T85_LRLTWO, 0, (const uint8_t *) "Xomment 8", 317132 + 16); - test_cycle("9", test_image, 1960, 1951, 128, 8, T85_TPBON, 0, (const uint8_t *) "Xomment 9", 253653 + 2*16); - /* Again with the image variable length and prematurely terminated */ - test_cycle("10", test_image, 1960, 1951, 1951, 0, T85_VLENGTH, T85_VLENGTH, NULL, 317384 + 8); - test_cycle("11", test_image, 1960, 1951, 1951, 0, T85_VLENGTH | T85_LRLTWO, T85_VLENGTH, NULL, 317132 + 8); - test_cycle("12", test_image, 1960, 1951, 128, 8, T85_VLENGTH | T85_TPBON, T85_VLENGTH, NULL, 253653 + 8); - /* Again with the image variable length but not prematurely terminated */ - test_cycle("13", test_image, 1960, 1951, 1951, 0, T85_VLENGTH, 0, NULL, 317384); - test_cycle("14", test_image, 1960, 1951, 1951, 0, T85_VLENGTH | T85_LRLTWO, 0, NULL, 317132); - test_cycle("15", test_image, 1960, 1951, 128, 8, T85_VLENGTH | T85_TPBON, 0, NULL, 253653); - - printf("Tests passed\n"); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/testadsi.c b/libs/spandsp/tests/testadsi.c deleted file mode 100644 index dc578a6ecd..0000000000 --- a/libs/spandsp/tests/testadsi.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * testadsi.c - * - * 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 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. - */ - -#if defined(HAVE_CONFIG_H) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_LIBUNICALL) - -#include -#include -#include -#include - -#include "unicall.h" -//#include "../libmfcr2/libmfcr2.h" -//#include "../libpri/libpri.h" - -#include "spandsp.h" - -#define FALSE 0 -#define TRUE (!FALSE) - -int caller_mode = FALSE; -static SNDFILE *rxhandle; -static SNDFILE *txhandle; - -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLASS_SDMF_CALLERID, 0); - len = adsi_add_field(s, msg, len, 0, "10011750", 8); - len = adsi_add_field(s, msg, len, 0, "6095551212", 10); - return len; -} -#endif -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLIP_MDMF_CALLERID, 0); - len = adsi_add_field(s, msg, len, CLIP_CALLTYPE, "\x81", 1); - len = adsi_add_field(s, msg, len, CLIP_DATETIME, "10011750", 8); - len = adsi_add_field(s, msg, len, CLIP_CALLER_NUMBER, "12345678", 8); - len = adsi_add_field(s, msg, len, CLIP_DIALED_NUMBER, "87654321", 8); - len = adsi_add_field(s, msg, len, CLIP_CALLER_NAME, "Steve Underwood", 15); - return len; -} -#endif -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLIP_MDMF_CALLERID, 0); - len = adsi_add_field(s, msg, len, CLIP_NUM_MSG, "\x03", 1); - return len; -} -#endif -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLIP_MDMF_MSG_WAITING, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_VISUAL_INDICATOR, "\x00", 1); - return len; -} -#endif -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLIP_MDMF_MSG_WAITING, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_VISUAL_INDICATOR, "\xFF", 1); - len = adsi_add_field(s, msg, len, CLIP_NUM_MSG, "\x05", 1); - return len; -} -#endif -#if 1 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLASS_SDMF_MSG_WAITING, NULL, 0); - len = adsi_add_field(s, msg, len, 0, "\x6F", 1); - len = adsi_add_field(s, msg, len, 0, "\x6F", 1); - len = adsi_add_field(s, msg, len, 0, "\x6F", 1); - return len; -} -#endif -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLASS_SDMF_MSG_WAITING, NULL, 0); - len = adsi_add_field(s, msg, len, 0, "\x42", 1); - len = adsi_add_field(s, msg, len, 0, "\x42", 1); - len = adsi_add_field(s, msg, len, 0, "\x42", 1); - return len; -} -#endif -#if 0 -int adsi_create_message(adsi_tx_state_t *s, uint8_t *msg) -{ - int len; - - len = adsi_add_field(s, msg, -1, CLIP_MDMF_SMS, NULL, 0); - len = adsi_add_field(s, msg, len, CLIP_DISPLAY_INFO, "\x00ABC", 4); - return len; -} -#endif - -struct -{ - pthread_t thread; - int chan; - int sig_fd; - int fd; - uc_call_t *call; - uc_crn_t crn; - int xxx; - int cause; - - dtmf_rx_state_t dtmf_state; - char dtmf[101]; - int dtmf_ptr; - - char *tag; - - char originating_number[32]; - char destination_number[32]; - - adsi_rx_state_t adsi_rx; - adsi_tx_state_t adsi_tx; -} chan_stuff[30]; - -tone_gen_descriptor_t tone_desc; -tone_gen_state_t gen; - -void channel_read_adsi_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int len); -int channel_write_adsi_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int max_len); -int channel_error(uc_t *uc, int chan, void *user_data, int cause); -int signaling_error(uc_t *uc, void *user_data, int cause); - -void channel_read_adsi_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int len) -{ - int i; - int xlen; - int16_t pcm_buf[1024]; - char *s; - int outframes; - - for (i = 0; i < len; i++) - pcm_buf[i] = alaw_to_linear(buf[i]); - /*endfor*/ - outframes = sf_writef_short(rxhandle, - AF_DEFAULT_TRACK, - pcm_buf, - len); - if (outframes != len) - { - printf("Failed to write %d samples\n", len); - exit(2); - } - - dtmf_rx(&chan_stuff[chan].dtmf_state, pcm_buf, len); - xlen = dtmf_rx_get(&chan_stuff[chan].dtmf_state, - chan_stuff[chan].dtmf + chan_stuff[chan].dtmf_ptr, - 100 - chan_stuff[chan].dtmf_ptr); - if (xlen > 0) - { - s = chan_stuff[chan].dtmf + chan_stuff[chan].dtmf_ptr; - while (*s) - { - if (*s == '#') - { - uc_set_channel_read_callback(uc, 0, NULL, 0); - uc_set_channel_write_callback(uc, 0, NULL, 0); - if (uc_call_control(uc, UC_OP_DROPCALL, chan_stuff[chan].crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - printf ("A Drop Call failed\n"); - /*endif*/ - break; - } - /*endif*/ - s++; - } - /*endwhile*/ - printf("Got '%s'\n", chan_stuff[chan].dtmf); - chan_stuff[chan].dtmf_ptr += xlen; - } - /*endif*/ - adsi_rx(&(chan_stuff[chan].adsi_rx), pcm_buf, len); -} -/*- End of function --------------------------------------------------------*/ - -int channel_write_adsi_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int max_len) -{ - int16_t pcm_buf[1024]; - int len; - int i; - static int block = 0; - uint8_t adsi_msg[256]; - int adsi_msg_len; - - if (++block == 100) - { - adsi_send_alert_tone(&(chan_stuff[chan].adsi_tx)); - printf("Alert tone sent\n"); - adsi_msg_len = adsi_create_message(&(chan_stuff[chan].adsi_tx), adsi_msg); - if ((len = adsi_put_message(&(chan_stuff[chan].adsi_tx), adsi_msg, adsi_msg_len)) > 0) - printf("Message put - %d bytes\n", len); - } - len = adsi_tx(&(chan_stuff[chan].adsi_tx), pcm_buf, max_len); - sf_writef_short(txhandle, - AF_DEFAULT_TRACK, - pcm_buf, - len); - for (i = 0; i < len; i++) - buf[i] = linear_to_alaw(pcm_buf[i]); - /*endfor*/ - return len; -} -/*- End of function --------------------------------------------------------*/ - -int channel_error(uc_t *uc, int chan, void *user_data, int cause) -{ - printf("Error %d\n", cause); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int signaling_error(uc_t *uc, void *user_data, int cause) -{ - printf("Error %d\n", cause); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void initiate_call(uc_t *uc, int chan, uc_event_t *e) -{ - uc_makecall_t makecall; - uc_callparms_t *callparms; - int ret; - - printf ("Initiating call\n"); - if ((callparms = uc_new_callparms(NULL)) == NULL) - return; - /*endif*/ - uc_callparm_originating_number(callparms, chan_stuff[chan].originating_number); - uc_callparm_destination_number(callparms, chan_stuff[chan].destination_number); - makecall.callparms = callparms; - makecall.crn = 0; - if (ret = uc_call_control(uc, UC_OP_MAKECALL, 0, (void *) &makecall) != UC_RET_OK) - fprintf(stderr, "Make Call failed - %d\n", ret); - /*endif*/ - chan_stuff[chan].crn = makecall.crn; - free(callparms); -} -/*- End of function --------------------------------------------------------*/ - -static void handle_uc_event(uc_t *uc, void *user_data, uc_event_t *e) -{ - int chan; - - chan = (int) user_data; - printf ("-- %s (%d)\n", uc_event2str(e->e), chan); - switch (e->e) - { - case UC_EVENT_DEVICEFAIL: - break; - case UC_EVENT_PROTOCOLFAIL: - printf("-- Protocol failure on channel %d, cause %d\n", e->gen.channel, e->gen.data); - break; - case UC_EVENT_SIGCHANSTATUS: - printf("-- Signalling channel status - %s\n", e->sigchanstatus.ok ? "Up" : "Down"); - break; - case UC_EVENT_ALARM: - printf("-- Alarm - 0x%X 0x%X\n", e->alarm.raised, e->alarm.cleared); - break; - case UC_EVENT_FARBLOCKED: - printf("-- Channel far end blocked! :-(\n"); - chan_stuff[chan].xxx &= ~1; - break; - case UC_EVENT_FARUNBLOCKED: - printf("-- Channel far end unblocked! :-)\n"); - chan_stuff[chan].xxx |= 1; - if (chan_stuff[chan].xxx == 3) - { - if (caller_mode) - initiate_call(uc, chan, e); - /*endif*/ - } - /*endif*/ - break; - case UC_EVENT_LOCALBLOCKED: - printf("-- Channel local end blocked! :-(\n"); - chan_stuff[chan].xxx &= ~2; - break; - case UC_EVENT_LOCALUNBLOCKED: - printf("-- Channel local end unblocked! :-)\n"); - chan_stuff[chan].xxx |= 2; - if (chan_stuff[chan].xxx == 3) - { - if (caller_mode) - initiate_call(uc, chan, e); - /*endif*/ - } - /*endif*/ - break; - case UC_EVENT_DIALING: - printf("-- Dialing on channel %d\n", e->gen.channel); - break; - case UC_EVENT_ACCEPTED: - printf("-- Accepted on channel %d\n", e->gen.channel); - if (uc_call_control(uc, UC_OP_ANSWERCALL, e->gen.crn, (void *) -1)) - fprintf(stderr, "Answer Call failed\n"); - /*endif*/ - break; - case UC_EVENT_DETECTED: - printf("-- Detected on channel %d\n", e->gen.channel); - break; - case UC_EVENT_ALERTING: - printf("-- Alerting on channel %d\n", e->gen.channel); - /* This is just a notification of call progress. We need take no action at this point. */ - break; - case UC_EVENT_FARDISCONNECTED: - printf("-- Far end disconnected on channel %d\n", e->fardisconnected.channel); - /* Kill any outstanding audio processing */ - uc_set_channel_read_callback(uc, 0, NULL, 0); - uc_set_channel_write_callback(uc, 0, NULL, 0); - if (uc_call_control(uc, UC_OP_DROPCALL, e->fardisconnected.crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - fprintf(stderr, "C Drop Call failed\n"); - /*endif*/ - break; - case UC_EVENT_DROPCALL: - printf("-- Drop call on channel %d\n", e->gen.channel); - if (uc_call_control(uc, UC_OP_RELEASECALL, e->gen.crn, NULL)) - fprintf(stderr, "uc_ReleaseCall failed\n"); - /*endif*/ - break; - case UC_EVENT_RELEASECALL: - printf("-- Released on channel %d\n", e->gen.channel); - if (caller_mode) - initiate_call(uc, chan, e); - /*endif*/ - break; - case UC_EVENT_OFFERED: - printf("-- Offered on channel %d, CRN %d (ANI: %s, DNIS: %s)\n", e->offered.channel, e->offered.crn, e->offered.parms.originating_number, e->offered.parms.destination_number); - if (!caller_mode) - { - switch (chan_stuff[chan].cause) - { - case 0: - if (uc_call_control(uc, UC_OP_ACCEPTCALL, e->offered.crn, (void *) -1)) - fprintf(stderr, "uc_AcceptCall failed\n"); - /*endif*/ - break; - case 1: - if (uc_call_control(uc, UC_OP_ANSWERCALL, e->offered.crn, (void *) -1)) - fprintf(stderr, "uc_AnswerCall failed\n"); - /*endif*/ - break; - case 2: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_USER_BUSY)) - fprintf(stderr, "E Drop Call failed\n"); - /*endif*/ - break; - case 3: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_UNASSIGNED_NUMBER)) - fprintf(stderr, "F Drop Call failed\n"); - /*endif*/ - break; - case 4: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_NETWORK_CONGESTION)) - fprintf(stderr, "G Drop Call failed\n"); - /*endif*/ - break; - case 5: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_DEST_OUT_OF_ORDER)) - fprintf(stderr, "H Drop Call failed\n"); - /*endif*/ - break; - } - /*endswitch*/ - if (++chan_stuff[chan].cause > 5) - chan_stuff[chan].cause = 0; - /*endif*/ - } - /*endif*/ - break; - case UC_EVENT_ANSWERED: - printf("-- Answered on channel %d\n", e->gen.channel); - uc_set_channel_read_callback(uc, 0, channel_read_adsi_channel, (void *) chan); -printf("XXX read callback set\n"); - uc_set_channel_write_callback(uc, 0, channel_write_adsi_channel, (void *) chan); -printf("XXX write callback set\n"); - adsi_tx_init(&(chan_stuff[chan].adsi_tx), ADSI_STANDARD_CLASS); -printf("XXX ADSI inited\n"); - dtmf_rx_init(&chan_stuff[chan].dtmf_state, NULL, NULL); -printf("XXX DTMF inited\n"); - break; - case UC_EVENT_CONNECTED: - printf("-- Connected on channel %d\n", e->gen.channel); - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - printf ("I Drop Call failed\n"); - /*endif*/ - break; - default: - fprintf(stderr, "--!! Unknown signaling event %d\n", e->e); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void *run_uc(void *arg) -{ - uc_t *uc; - uc_event_t *e; - struct timeval tv = {0,0}; - struct timeval *next; - fd_set rfds; - fd_set wfds; - fd_set efds; - int res; - int dfd; - int chan; - - chan = *((int *) arg); - - dfd = chan_stuff[chan].fd; - uc = uc_new(dfd, dfd, "mfcr2", "cn", UC_MODE_CPE, 1); - //uc = uc_new(dfd, dfd, "pri", "ctr4", UC_MODE_CPE, 1); - if (uc == NULL) - { - fprintf(stderr, "Unable to create instance\n"); - return NULL; - } - /*endif*/ - uc_set_signaling_callback(uc, handle_uc_event, (void *) chan); - uc_set_signaling_error_callback(uc, signaling_error, (void *) chan); - uc_set_channel_error_callback(uc, 0, channel_error, (void *) chan); - uc_set_logging(uc, 0x7FFFFFFF, 0, chan_stuff[chan].tag); - uc_call_control(uc, UC_OP_UNBLOCK, 0, (void *) -1); - for (;;) - { - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - FD_SET(dfd, &rfds); - FD_SET(dfd, &wfds); - FD_SET(dfd, &efds); - - if ((next = uc_schedule_next(uc))) - { - gettimeofday(&tv, NULL); - tv.tv_sec = next->tv_sec - tv.tv_sec; - tv.tv_usec = next->tv_usec - tv.tv_usec; - if (tv.tv_usec < 0) - { - tv.tv_usec += 1000000; - tv.tv_sec -= 1; - } - /*endif*/ - if (tv.tv_sec < 0) - { - tv.tv_sec = 0; - tv.tv_usec = 0; - } - /*endif*/ - } - /*endif*/ - res = select(dfd + 1, &rfds, NULL, &efds, next ? &tv : NULL); - e = NULL; - if (res == 0) - { - uc_schedule_run(uc); - } - else if (res > 0) - { - e = uc_check_event(uc); - } - else if (errno != EINTR) - { - fprintf(stderr, "Error (%d) on select: %s\n", errno, strerror(errno)); - } - /*endif*/ - - if (e) - { - printf("Non-callback signaling event\n"); - handle_uc_event(uc, (void *) chan, e); - } - /*endif*/ - } - /*endfor*/ - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - pthread_attr_t attr; - struct zt_bufferinfo b; - struct zt_gains g; - int chan; - int chanx; - char dev_name[20]; - AFfilesetup filesetup; - int j; - - filesetup = afNewFileSetup(); - if (filesetup == AF_NULL_FILESETUP) - { - fprintf(stderr, " Failed to create file setup\n"); - exit(2); - } - afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); - afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); - afInitFileFormat(filesetup, AF_FILE_WAVE); - afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); - rxhandle = afOpenFile("rxadsi.wav", "w", filesetup); - if (rxhandle == NULL) - { - fprintf(stderr, " Failed to open adsi audio file\n"); - exit(2); - } - txhandle = afOpenFile("txadsi.wav", "w", filesetup); - if (txhandle == NULL) - { - fprintf(stderr, " Failed to open adsi audio file\n"); - exit(2); - } - - uc_start(); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (argc < 1) - { - fprintf(stderr, "Usage: testcall [call]\n"); - exit(1); - } - /*endif*/ - for (chan = 0; chan < 1/*30*/; chan++) - { - chan_stuff[chan].sig_fd = open("/dev/zap/channel", O_RDWR | O_NONBLOCK); - if (chan_stuff[chan].sig_fd < 0) - { - fprintf(stderr, "Failed to open channel: %s\n", strerror(errno)); - exit(1); - } - /*endif*/ - chan_stuff[chan].fd = chan_stuff[chan].sig_fd; - - /* Allow for the missing channel at TS16 */ - if (chan < 15) - chanx = chan + 1; - else - chanx = chan + 2; - /*endif*/ - if (ioctl(chan_stuff[chan].fd, ZT_SPECIFY, &chanx)) - { - fprintf(stderr, "Failed to specify channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - if (ioctl(chan_stuff[chan].fd, ZT_GET_BUFINFO, &b)) - { - fprintf(stderr, "Unable to get buffer info on channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - printf ("%d %d %d %d %d %d\n", - b.rxbufpolicy, - b.txbufpolicy, - b.numbufs, - b.bufsize, - b.readbufs, - b.writebufs); - b.rxbufpolicy = ZT_POLICY_IMMEDIATE; - b.txbufpolicy = ZT_POLICY_IMMEDIATE; - b.numbufs = 4; - b.bufsize = 160; - if (ioctl(chan_stuff[chan].fd, ZT_SET_BUFINFO, &b)) - { - fprintf(stderr, "Unable to set buffer info on channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - if (ioctl(chan_stuff[chan].fd, ZT_GET_BUFINFO, &b)) - { - fprintf(stderr, "Unable to get buffer info on channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - for (j = 0; j < 256; j++) - { - g.rxgain[j] = j; - g.txgain[j] = j; - } - ioctl(chan_stuff[chan].fd, ZT_SETGAINS, &g); - printf("%d %d %d %d %d %d\n", - b.rxbufpolicy, - b.txbufpolicy, - b.numbufs, - b.bufsize, - b.readbufs, - b.writebufs); - - if (argc > 1) - caller_mode = TRUE; - /*endif*/ - chan_stuff[chan].chan = chan; - sprintf(dev_name, "Chan %2d:", chanx); - chan_stuff[chan].tag = strdup(dev_name); - sprintf(chan_stuff[chan].originating_number, "%d", 987654321 + chan); - sprintf(chan_stuff[chan].destination_number, "%d", 1234 + chan); - - printf("Thread for channel %d\n", chan); - if (pthread_create(&chan_stuff[chan].thread, &attr, run_uc, &chan_stuff[chan].chan)) - exit(2); - /*endif*/ - } - /*endfor*/ - for (;;) - { - sleep(5); - printf("Main thread\n"); - } - /*endfor*/ - exit(0); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -#else -int main(int argc, char *argv[]) -{ - printf("This program was not built with Unicall available\n"); -} -/*- End of function --------------------------------------------------------*/ -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/testfax.c b/libs/spandsp/tests/testfax.c deleted file mode 100644 index e484ee898c..0000000000 --- a/libs/spandsp/tests/testfax.c +++ /dev/null @@ -1,650 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * testfax.c - * - * 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 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. - */ - -#if defined(HAVE_CONFIG_H) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_LIBUNICALL) - -#include -#include -#include -#include - -#include "unicall.h" -//#include "../libmfcr2/libmfcr2.h" -//#include "../libpri/libpri.h" -//#include "../libpri/libfx.h" - -#include "spandsp.h" - -int caller_mode = FALSE; -static SNDFILE *rxhandle; -static SNDFILE *txhandle; - -typedef struct -{ - pthread_t thread; - int chan; - int sig_fd; - int fd; - uc_call_t *call; - uc_crn_t crn; - int xxx; - int cause; - uc_t *uc; - - dtmf_rx_state_t dtmf_state; - char dtmf[101]; - int dtmf_ptr; - - char *tag; - - char originating_number[32]; - char destination_number[32]; - - t30_state_t fax; -} chan_stuff_t; - -chan_stuff_t chan_stuff[30]; - -tone_gen_descriptor_t tone_desc; -tone_gen_state_t gen; - -pthread_mutex_t mutex; - -void channel_read_fax_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int len); -int channel_write_fax_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int max_len); -int channel_error(uc_t *uc, int chan, void *user_data, int cause); -int signaling_error(uc_t *uc, void *user_data, int cause); - -void channel_read_fax_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int len) -{ - int i; - int xlen; - char *s; - int outframes; - -#if 0 - outframes = sf_writef_short(rxhandle, - AF_DEFAULT_TRACK, - buf, - len >> 1); - if (outframes != len) - { - printf("Failed to write %d samples\n", len); - exit(2); - } -#endif - dtmf_rx(&chan_stuff[chan].dtmf_state, (int16_t *) buf, len); - xlen = dtmf_rx_get(&chan_stuff[chan].dtmf_state, - chan_stuff[chan].dtmf + chan_stuff[chan].dtmf_ptr, - 100 - chan_stuff[chan].dtmf_ptr); - if (xlen > 0) - { - s = chan_stuff[chan].dtmf + chan_stuff[chan].dtmf_ptr; - while (*s) - { - if (*s == '#') - { - uc_set_channel_read_callback(uc, 0, NULL, 0); - uc_set_channel_write_callback(uc, 0, NULL, 0); - if (uc_call_control(uc, UC_OP_DROPCALL, chan_stuff[chan].crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - printf ("A Drop Call failed\n"); - /*endif*/ - break; - } - /*endif*/ - s++; - } - /*endwhile*/ - printf("Got '%s'\n", chan_stuff[chan].dtmf); - chan_stuff[chan].dtmf_ptr += xlen; - } - /*endif*/ - t30_rx(&(chan_stuff[chan].fax), (int16_t *) buf, len); -} -/*- End of function --------------------------------------------------------*/ - -int channel_write_fax_channel(uc_t *uc, int chan, void *user_data, uint8_t *buf, int max_len) -{ - int len; - - len = t30_tx(&(chan_stuff[chan].fax), (int16_t *) buf, max_len >> 1); - sf_writef_short(txhandle, AF_DEFAULT_TRACK, buf, len); - if (len > 0) - len <<= 1; - return len; -} -/*- End of function --------------------------------------------------------*/ - -int channel_error(uc_t *uc, int chan, void *user_data, int cause) -{ - printf("Error %d\n", cause); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int signaling_error(uc_t *uc, void *user_data, int cause) -{ - printf("Error %d\n", cause); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void initiate_call(uc_t *uc, int chan, uc_event_t *e) -{ - uc_makecall_t makecall; - uc_callparms_t *callparms; - int ret; - - printf ("Initiating call\n"); - pthread_mutex_lock(&mutex); - if ((callparms = uc_new_callparms(NULL)) == NULL) - return; - /*endif*/ - pthread_mutex_unlock(&mutex); - uc_callparm_originating_number(callparms, chan_stuff[chan].originating_number); - uc_callparm_destination_number(callparms, chan_stuff[chan].destination_number); - makecall.callparms = callparms; - makecall.crn = 0; - if (ret = uc_call_control(uc, UC_OP_MAKECALL, 0, (void *) &makecall) != UC_RET_OK) - fprintf(stderr, "Make Call failed - %d\n", ret); - /*endif*/ - chan_stuff[chan].crn = makecall.crn; - free(callparms); -} -/*- End of function --------------------------------------------------------*/ - -static void phase_b_handler(t30_state_t *s, void *user_data, int msg) -{ - chan_stuff_t *t; - - t = (chan_stuff_t *) user_data; - printf("Phase B - %d\n", msg); -} -/*- End of function --------------------------------------------------------*/ - -static void phase_d_handler(t30_state_t *s, void *user_data, int msg) -{ - chan_stuff_t *t; - - t = (chan_stuff_t *) user_data; - printf("Phase D - %d\n", msg); -} -/*- End of function --------------------------------------------------------*/ - -static void phase_e_handler(t30_state_t *s, void *user_data, int result) -{ - chan_stuff_t *t; - - printf("Phase E - %d\n", result); - t = (chan_stuff_t *) user_data; - if (uc_call_control(t->uc, UC_OP_DROPCALL, t->crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - fprintf(stderr, "Phase E Drop Call failed\n"); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void flush_handler(t30_state_t *s, void *user_data, int which) -{ - chan_stuff_t *t; - - printf("Flush\n"); - t = (chan_stuff_t *) user_data; -} -/*- End of function --------------------------------------------------------*/ - -static void handle_uc_event(uc_t *uc, void *user_data, uc_event_t *e) -{ - int chan; - - chan = (int) user_data; - - printf ("-- %s (%d)\n", uc_event2str(e->e), chan); - switch (e->e) - { - case UC_EVENT_DEVICEFAIL: - break; - case UC_EVENT_PROTOCOLFAIL: - printf("-- Protocol failure on channel %d, cause %d\n", e->gen.channel, e->gen.data); - break; - case UC_EVENT_SIGCHANSTATUS: - printf("-- Signalling channel status - %s\n", e->sigchanstatus.ok ? "Up" : "Down"); - break; - case UC_EVENT_ALARM: - printf("-- Alarm - 0x%X 0x%X\n", e->alarm.raised, e->alarm.cleared); - break; - case UC_EVENT_FARBLOCKED: - printf("-- Channel far end blocked! :-(\n"); - chan_stuff[chan].xxx &= ~1; - break; - case UC_EVENT_FARUNBLOCKED: - printf("-- Channel far end unblocked! :-)\n"); - chan_stuff[chan].xxx |= 1; - if (chan_stuff[chan].xxx == 3) - { - if (caller_mode) - initiate_call(uc, chan, e); - /*endif*/ - } - /*endif*/ - break; - case UC_EVENT_LOCALBLOCKED: - printf("-- Channel local end blocked! :-(\n"); - chan_stuff[chan].xxx &= ~2; - break; - case UC_EVENT_LOCALUNBLOCKED: - printf("-- Channel local end unblocked! :-)\n"); - chan_stuff[chan].xxx |= 2; - if (chan_stuff[chan].xxx == 3) - { - if (caller_mode) - initiate_call(uc, chan, e); - /*endif*/ - } - /*endif*/ - break; - case UC_EVENT_DIALING: - printf("-- Dialing on channel %d\n", e->gen.channel); - break; - case UC_EVENT_PROCEEDING: - printf("-- Proceeding on channel %d\n", e->gen.channel); - break; - case UC_EVENT_ACCEPTED: - printf("-- Accepted on channel %d\n", e->gen.channel); - if (uc_call_control(uc, UC_OP_ANSWERCALL, e->gen.crn, (void *) -1)) - fprintf(stderr, "Answer Call failed\n"); - /*endif*/ - break; - case UC_EVENT_DETECTED: - printf("-- Detected on channel %d\n", e->gen.channel); - break; - case UC_EVENT_MOREDIGITS: - printf("-- More digits on channel %d, CRN %d (ANI: %s, DNIS: %s)\n", e->offered.channel, e->offered.crn, e->offered.parms.originating_number, e->offered.parms.destination_number); - break; - case UC_EVENT_ALERTING: - printf("-- Alerting on channel %d\n", e->gen.channel); - /* This is just a notification of call progress. We need take no action at this point. */ - break; - case UC_EVENT_FARDISCONNECTED: - printf("-- Far end disconnected on channel %d\n", e->fardisconnected.channel); - /* Kill any outstanding audio processing */ - uc_set_channel_read_callback(uc, 0, NULL, 0); - uc_set_channel_write_callback(uc, 0, NULL, 0); - if (uc_call_control(uc, UC_OP_DROPCALL, e->fardisconnected.crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - fprintf(stderr, "C Drop Call failed\n"); - /*endif*/ - break; - case UC_EVENT_DROPCALL: - printf("-- Drop call on channel %d\n", e->gen.channel); - if (uc_call_control(uc, UC_OP_RELEASECALL, e->gen.crn, NULL)) - fprintf(stderr, "uc_ReleaseCall failed\n"); - /*endif*/ - break; - case UC_EVENT_RELEASECALL: - printf("-- Released on channel %d\n", e->gen.channel); - if (caller_mode) - initiate_call(uc, chan, e); - /*endif*/ - break; - case UC_EVENT_OFFERED: - printf("-- Offered on channel %d, CRN %d (ANI: %s, DNIS: %s)\n", e->offered.channel, e->offered.crn, e->offered.parms.originating_number, e->offered.parms.destination_number); - if (!caller_mode) - { - switch (chan_stuff[chan].cause) - { - case 0: - if (uc_call_control(uc, UC_OP_ACCEPTCALL, e->offered.crn, (void *) -1)) - fprintf(stderr, "uc_AcceptCall failed\n"); - /*endif*/ - chan_stuff[chan].crn = e->offered.crn; - break; - case 1: - if (uc_call_control(uc, UC_OP_ANSWERCALL, e->offered.crn, (void *) -1)) - fprintf(stderr, "uc_AnswerCall failed\n"); - /*endif*/ - chan_stuff[chan].crn = e->offered.crn; - break; - case 2: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_USER_BUSY)) - fprintf(stderr, "E Drop Call failed\n"); - /*endif*/ - break; - case 3: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_UNASSIGNED_NUMBER)) - fprintf(stderr, "F Drop Call failed\n"); - /*endif*/ - break; - case 4: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_NETWORK_CONGESTION)) - fprintf(stderr, "G Drop Call failed\n"); - /*endif*/ - break; - case 5: - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_DEST_OUT_OF_ORDER)) - fprintf(stderr, "H Drop Call failed\n"); - /*endif*/ - break; - } - /*endswitch*/ - if (++chan_stuff[chan].cause > 5) - chan_stuff[chan].cause = 0; - /*endif*/ - } - /*endif*/ - break; - case UC_EVENT_ANSWERED: - printf("-- Answered on channel %d\n", e->gen.channel); - uc_set_channel_read_callback(uc, 0, channel_read_fax_channel, (void *) chan); -printf("XXX read callback set\n"); - uc_set_channel_write_callback(uc, 0, channel_write_fax_channel, (void *) chan); -printf("XXX write callback set\n"); - t30_init(&(chan_stuff[chan].fax), FALSE, uc); - t30_set_local_ident(&(chan_stuff[chan].fax), "12345678"); - t30_set_tx_file(&(chan_stuff[chan].fax), "tx.tif"); - //t30_set_rx_file(&(chan_stuff[chan].fax), "rx.tif"); - t30_set_phase_b_handler(&(chan_stuff[chan].fax), phase_b_handler, &(chan_stuff[chan])); - t30_set_phase_d_handler(&(chan_stuff[chan].fax), phase_d_handler, &(chan_stuff[chan])); - t30_set_phase_e_handler(&(chan_stuff[chan].fax), phase_e_handler, &(chan_stuff[chan])); - t30_set_flush_handler(&(chan_stuff[chan].fax), flush_handler, &(chan_stuff[chan])); -printf("XXX FAX inited\n"); - dtmf_rx_init(&chan_stuff[chan].dtmf_state, NULL, NULL); -printf("XXX DTMF inited\n"); - break; - case UC_EVENT_CONNECTED: - printf("-- Connected on channel %d\n", e->gen.channel); - uc_set_channel_read_callback(uc, 0, channel_read_fax_channel, (void *) chan); -printf("XXX read callback set\n"); - uc_set_channel_write_callback(uc, 0, channel_write_fax_channel, (void *) chan); -printf("XXX write callback set\n"); - t30_init(&(chan_stuff[chan].fax), TRUE, uc); - t30_set_local_ident(&(chan_stuff[chan].fax), "87654321"); - t30_set_tx_file(&(chan_stuff[chan].fax), "tx.tif"); - //t30_set_rx_file(&(chan_stuff[chan].fax), "rx.tif"); - t30_set_phase_b_handler(&(chan_stuff[chan].fax), phase_b_handler, &(chan_stuff[chan])); - t30_set_phase_d_handler(&(chan_stuff[chan].fax), phase_d_handler, &(chan_stuff[chan])); - t30_set_phase_e_handler(&(chan_stuff[chan].fax), phase_e_handler, &(chan_stuff[chan])); -printf("XXX FAX inited\n"); -#if 0 - if (uc_call_control(uc, UC_OP_DROPCALL, e->offered.crn, (void *) UC_CAUSE_NORMAL_CLEARING)) - printf ("I Drop Call failed\n"); - /*endif*/ -#endif - break; - default: - fprintf(stderr, "--!! Unknown signaling event %d\n", e->e); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void *run_uc(void *arg) -{ - uc_t *uc; - uc_event_t *e; - struct timeval tv = {0,0}; - struct timeval *next; - fd_set rfds; - fd_set wfds; - fd_set efds; - int res; - int dfd; - int chan; - - chan = *((int *) arg); - - dfd = chan_stuff[chan].fd; - if (chan < 4) - uc = uc_new(dfd, dfd, "fx", "ls,us", UC_MODE_CO, 1); - else - uc = uc_new(dfd, dfd, "fx", "ls", UC_MODE_CPE, 1); - //uc = uc_new(dfd, dfd, "mfcr2", "cn", UC_MODE_CPE, 1); - //uc = uc_new(dfd, dfd, "pri", "ctr4", UC_MODE_CPE, 1); - if (uc == NULL) - { - fprintf(stderr, "Unable to create instance\n"); - return NULL; - } - /*endif*/ - uc_set_api_codec(uc, 0, UC_CODEC_LINEAR16); - - chan_stuff[chan].uc = uc; - uc_set_signaling_callback(uc, handle_uc_event, (void *) chan); - uc_set_signaling_error_callback(uc, signaling_error, (void *) chan); - uc_set_channel_error_callback(uc, 0, channel_error, (void *) chan); - uc_set_logging(uc, 0x7FFFFFFF, 0, chan_stuff[chan].tag); - uc_call_control(uc, UC_OP_UNBLOCK, 0, (void *) -1); - for (;;) - { - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - FD_SET(dfd, &rfds); - FD_SET(dfd, &wfds); - FD_SET(dfd, &efds); - - if ((next = uc_schedule_next(uc))) - { - gettimeofday(&tv, NULL); - tv.tv_sec = next->tv_sec - tv.tv_sec; - tv.tv_usec = next->tv_usec - tv.tv_usec; - if (tv.tv_usec < 0) - { - tv.tv_usec += 1000000; - tv.tv_sec -= 1; - } - /*endif*/ - if (tv.tv_sec < 0) - { - tv.tv_sec = 0; - tv.tv_usec = 0; - } - /*endif*/ - } - /*endif*/ - res = select(dfd + 1, &rfds, NULL, &efds, next ? &tv : NULL); - e = NULL; - if (res == 0) - { - uc_schedule_run(uc); - } - else if (res > 0) - { - e = uc_check_event(uc); - } - else if (errno != EINTR) - { - fprintf(stderr, "Error (%d) on select: %s\n", errno, strerror(errno)); - } - /*endif*/ - - if (e) - { - printf("Non-callback signaling event\n"); - handle_uc_event(uc, (void *) chan, e); - } - /*endif*/ - } - /*endfor*/ - return NULL; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - pthread_attr_t attr; - struct zt_bufferinfo b; - struct zt_gains g; - int chan; - int chanx; - char dev_name[20]; - AFfilesetup filesetup; - int j; - - filesetup = afNewFileSetup(); - if (filesetup == AF_NULL_FILESETUP) - { - fprintf(stderr, " Failed to create file setup\n"); - exit(2); - } - afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); - afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); - afInitFileFormat(filesetup, AF_FILE_WAVE); - afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); - rxhandle = afOpenFile("rxfax.wav", "w", filesetup); - if (rxhandle == NULL) - { - fprintf(stderr, " Failed to open fax audio file\n"); - exit(2); - } - txhandle = afOpenFile("txfax.wav", "w", filesetup); - if (txhandle == NULL) - { - fprintf(stderr, " Failed to open fax audio file\n"); - exit(2); - } - - if (argc < 1) - { - fprintf(stderr, "Usage: testcall [call]\n"); - exit(1); - } - /*endif*/ - uc_start(); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_mutex_init(&mutex, NULL); - for (chan = 0; chan < 5/*30*/; chan++) - { - chan_stuff[chan].sig_fd = open("/dev/zap/channel", O_RDWR | O_NONBLOCK); - if (chan_stuff[chan].sig_fd < 0) - { - fprintf(stderr, "Failed to open channel: %s\n", strerror(errno)); - exit(1); - } - /*endif*/ - chan_stuff[chan].fd = chan_stuff[chan].sig_fd; - - /* Allow for the missing channel at TS16 */ - chanx = chan + 1 + (chan + 15)%30; - chanx = chan + 125; - if (ioctl(chan_stuff[chan].fd, ZT_SPECIFY, &chanx)) - { - fprintf(stderr, "Failed to specify channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - if (ioctl(chan_stuff[chan].fd, ZT_GET_BUFINFO, &b)) - { - fprintf(stderr, "Unable to get buffer info on channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - printf ("%d %d %d %d %d %d\n", - b.rxbufpolicy, - b.txbufpolicy, - b.numbufs, - b.bufsize, - b.readbufs, - b.writebufs); - b.rxbufpolicy = ZT_POLICY_IMMEDIATE; - b.txbufpolicy = ZT_POLICY_IMMEDIATE; - b.numbufs = 4; - b.bufsize = 160; - if (ioctl(chan_stuff[chan].fd, ZT_SET_BUFINFO, &b)) - { - fprintf(stderr, "Unable to set buffer info on channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - if (ioctl(chan_stuff[chan].fd, ZT_GET_BUFINFO, &b)) - { - fprintf(stderr, "Unable to get buffer info on channel %d: %s\n", chanx, strerror(errno)); - exit(1); - } - /*endif*/ - for (j = 0; j < 256; j++) - { - g.rxgain[j] = j; - g.txgain[j] = j; - } - /*endif*/ - ioctl(chan_stuff[chan].fd, ZT_SETGAINS, &g); - printf("%d %d %d %d %d %d\n", - b.rxbufpolicy, - b.txbufpolicy, - b.numbufs, - b.bufsize, - b.readbufs, - b.writebufs); - - if (argc > 1) - caller_mode = TRUE; - /*endif*/ - chan_stuff[chan].chan = chan; - sprintf(dev_name, "Chan %2d:", chanx); - chan_stuff[chan].tag = strdup(dev_name); - sprintf(chan_stuff[chan].originating_number, "%d", 987654321 + chan); - sprintf(chan_stuff[chan].destination_number, "%d", 1234 + chan); - printf("Thread for channel %d\n", chan); - if (pthread_create(&chan_stuff[chan].thread, &attr, run_uc, &chan_stuff[chan].chan)) - exit(2); - /*endif*/ - } - /*endfor*/ - for (;;) - { - sleep(5); - printf("Main thread\n"); - } - /*endfor*/ - - return 0; -} -/*- End of function --------------------------------------------------------*/ -#else -int main(int argc, char *argv[]) -{ - printf("This program was not built with Unicall available\n"); -} -/*- End of function --------------------------------------------------------*/ -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/time_scale_tests.c b/libs/spandsp/tests/time_scale_tests.c deleted file mode 100644 index 4e902c2eae..0000000000 --- a/libs/spandsp/tests/time_scale_tests.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * time_scale_tests.c - * - * 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 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. - */ - -/*! \page time_scale_tests_page Time scaling tests -\section time_scale_tests_page_sec_1 What does it do? -These tests run a speech file through the time scaling routines. - -\section time_scale_tests_page_sec_2 How are the tests run? -These tests process a speech file called pre_time_scale.wav. This file should contain -8000 sample/second 16 bits/sample linear audio. The tests read this file, change the -time scale of its contents, and write the resulting audio to post_time_scale.wav. -This file also contains 8000 sample/second 16 bits/sample linear audio. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "spandsp.h" - -#include "spandsp/private/time_scale.h" - -#define BLOCK_LEN 160 - -#define IN_FILE_NAME "../test-data/local/short_nb_voice.wav" -#define OUT_FILE_NAME "time_scale_result.wav" - -int main(int argc, char *argv[]) -{ - SNDFILE *inhandle; - SNDFILE *outhandle; - SF_INFO info; - int16_t in[BLOCK_LEN]; - int16_t out[5*(BLOCK_LEN + TIME_SCALE_MAX_SAMPLE_RATE/TIME_SCALE_MIN_PITCH)]; - int frames; - int new_frames; - int out_frames; - int count; - int max; - int samples_in; - int samples_out; - time_scale_state_t state; - float rate; - float sample_rate; - const char *in_file_name; - bool sweep_rate; - int opt; - - rate = 1.8f; - sweep_rate = false; - in_file_name = IN_FILE_NAME; - while ((opt = getopt(argc, argv, "i:r:s")) != -1) - { - switch (opt) - { - case 'i': - in_file_name = optarg; - break; - case 'r': - rate = atof(optarg); - break; - case 's': - sweep_rate = true; - break; - default: - //usage(); - exit(2); - break; - } - } - memset(&info, 0, sizeof(info)); - if ((inhandle = sf_open(in_file_name, SFM_READ, &info)) == NULL) - { - printf(" Cannot open audio file '%s'\n", in_file_name); - exit(2); - } - if (info.channels != 1) - { - printf(" Unexpected number of channels in audio file '%s'\n", in_file_name); - exit(2); - } - sample_rate = info.samplerate; - - memset(&info, 0, sizeof(info)); - info.frames = 0; - info.samplerate = sample_rate; - info.channels = 1; - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - info.sections = 1; - info.seekable = 1; - - if ((outhandle = sf_open(OUT_FILE_NAME, SFM_WRITE, &info)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - - if ((time_scale_init(&state, (int) sample_rate, rate)) == NULL) - { - fprintf(stderr, " Cannot start the time scaler\n"); - exit(2); - } - max = time_scale_max_output_len(&state, BLOCK_LEN); - printf("Rate is %f, longest output block is %d\n", rate, max); - count = 0; - samples_in = 0; - samples_out = 0; - while ((frames = sf_readf_short(inhandle, in, BLOCK_LEN))) - { - samples_in += frames; - new_frames = time_scale(&state, out, in, frames); - if (new_frames > max) - { - printf("Generated signal has more than the expected maximum samples - %d vs %d\n", new_frames, max); - printf("Tests failed\n"); - exit(2); - } - samples_out += new_frames; - out_frames = sf_writef_short(outhandle, out, new_frames); - if (out_frames != new_frames) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - if (sweep_rate && ++count > 100) - { - if (rate > 0.5f) - { - rate -= 0.1f; - if (rate >= 0.99f && rate <= 1.01f) - rate -= 0.1f; - time_scale_init(&state, SAMPLE_RATE, rate); - max = time_scale_max_output_len(&state, BLOCK_LEN); - printf("Rate is %f, longest output block is %d\n", rate, max); - } - count = 0; - } - } - new_frames = time_scale_flush(&state, out); - if (new_frames > max) - { - printf("Generated signal has more than the expected maximum samples - %d vs %d\n", new_frames, max); - printf("Tests failed\n"); - exit(2); - } - samples_out += new_frames; - out_frames = sf_writef_short(outhandle, out, new_frames); - if (out_frames != new_frames) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - time_scale_release(&state); - if ((int) (rate*samples_in) < samples_out - 1 || (int) (rate*samples_in) > samples_out + 1) - { - printf("%d samples became %d samples\n", (int) (rate*samples_in), samples_out); - printf("Tests failed\n"); - exit(2); - } - if (sf_close(inhandle)) - { - printf(" Cannot close audio file '%s'\n", in_file_name); - exit(2); - } - if (sf_close(outhandle)) - { - printf(" Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/timezone_tests.c b/libs/spandsp/tests/timezone_tests.c deleted file mode 100644 index ab4efe6890..0000000000 --- a/libs/spandsp/tests/timezone_tests.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * timezone_tests.c - Timezone handling for time interpretation - * - * Written by Steve Underwood - * - * Copyright (C) 2010 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. - */ - -/*! \page timezone_tests_page Timezone handling tests -\section timezone_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "spandsp.h" - -int main(int argc, char *argv[]) -{ - struct tm tms; - struct tm *tmp = &tms; - time_t ltime; - tz_t *tz; - - /* Get the current time */ - ltime = time(NULL); - - /* Compute the local current time now for several localities, based on Posix tz strings */ - - tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0"); - tz_localtime(tz, tmp, ltime); - printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); - - tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0"); - tz_localtime(tz, tmp, ltime); - printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); - - tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0"); - tz_localtime(tz, tmp, ltime); - printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); - - tz_free(tz); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/tone_detect_tests.c b/libs/spandsp/tests/tone_detect_tests.c deleted file mode 100644 index 016e0096e3..0000000000 --- a/libs/spandsp/tests/tone_detect_tests.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tone_detect_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2007 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. - */ - -/*! \page tone_detect_tests_page Tone detection tests -\section tone_detect_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -#define DEC_SAMPLE_RATE 800 -#define DEC_RATIO 10 -#define BLOCK_LEN 56 -#define PG_WINDOW 56 -#define FREQ1 440.0f -#define FREQ2 480.0f - -static int periodogram_tests(void) -{ - int i; - int j; - int k; - int len; - complexf_t coeffs[PG_WINDOW/2]; - complexf_t camp[BLOCK_LEN]; - complexf_t last_result; - complexf_t result; - complexf_t phase_offset; - float freq_error; - float pg_scale; - float level; - float scale1; - float scale2; - int32_t phase_rate1; - int32_t phase_rate2; - uint32_t phase_acc1; - uint32_t phase_acc2; - awgn_state_t *noise_source_re; - awgn_state_t *noise_source_im; - - phase_rate1 = DEC_RATIO*dds_phase_ratef(FREQ1 - 5.0f); - phase_rate2 = DEC_RATIO*dds_phase_ratef(FREQ2); - phase_acc1 = 0; - phase_acc2 = 0; - len = periodogram_generate_coeffs(coeffs, FREQ1, DEC_SAMPLE_RATE, PG_WINDOW); - if (len != PG_WINDOW/2) - { - printf("Test failed\n"); - return -1; - } - pg_scale = periodogram_generate_phase_offset(&phase_offset, FREQ1, DEC_SAMPLE_RATE, PG_WINDOW); - scale1 = dds_scaling_dbm0f(-6.0f); - scale2 = dds_scaling_dbm0f(-6.0f); - - for (k = -50; k < 0; k++) - { - printf("Setting noise to %ddBm0\n", k); - noise_source_re = awgn_init_dbm0(NULL, 1234567, (float) k); - noise_source_im = awgn_init_dbm0(NULL, 7654321, (float) k); - last_result = complex_setf(0.0f, 0.0f); - for (i = 0; i < 100; i++) - { - for (j = 0; j < PG_WINDOW; j++) - { - result = dds_complexf(&phase_acc1, phase_rate1); - camp[j].re = result.re*scale1; - camp[j].im = result.im*scale1; - result = dds_complexf(&phase_acc2, phase_rate2); - camp[j].re += result.re*scale2; - camp[j].im += result.im*scale2; - camp[j].re += awgn(noise_source_re); - camp[j].im += awgn(noise_source_im); - } - result = periodogram(coeffs, camp, PG_WINDOW); - level = sqrtf(result.re*result.re + result.im*result.im); - freq_error = periodogram_freq_error(&phase_offset, pg_scale, &last_result, &result); - last_result = result; - if (i == 0) - continue; - - printf("Signal level = %.5f, freq error = %.5f\n", level, freq_error); - if (level < scale1*0.8f || level > scale1*1.2f) - { - printf("Test failed - %ddBm0 of noise, signal is %f (%f)\n", k, level, scale1); - return -1; - } - if (freq_error < -10.0f || freq_error > 10.0f) - { - printf("Test failed - %ddBm0 of noise, %fHz error\n", k, freq_error); - return -1; - } - } - awgn_free(noise_source_re); - awgn_free(noise_source_im); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - if (periodogram_tests()) - exit(2); - printf("Tests passed\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/tone_generate_tests.c b/libs/spandsp/tests/tone_generate_tests.c deleted file mode 100644 index ffa87eb3ad..0000000000 --- a/libs/spandsp/tests/tone_generate_tests.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tone_generate_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2001 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. - */ - -/*! \page tone_generate_tests_page Tone generation tests -\section tone_generate_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "tone_generate.wav" - -int main(int argc, char *argv[]) -{ - tone_gen_descriptor_t tone_desc; - tone_gen_state_t tone_state; - int i; - int16_t amp[16384]; - int len; - SNDFILE *outhandle; - - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - - /* Try a tone pair */ - tone_gen_descriptor_init(&tone_desc, - 440, - -10, - 620, - -15, - 100, - 200, - 300, - 400, - false); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try a different tone pair */ - tone_gen_descriptor_init(&tone_desc, - 350, - -10, - 440, - -15, - 400, - 300, - 200, - 100, - true); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try a different tone pair */ - tone_gen_descriptor_init(&tone_desc, - 400, - -10, - 450, - -10, - 100, - 200, - 300, - 400, - true); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try a single tone */ - tone_gen_descriptor_init(&tone_desc, - 400, - -10, - 0, - 0, - 100, - 200, - 300, - 400, - true); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try a single non-repeating tone */ - tone_gen_descriptor_init(&tone_desc, - 820, - -10, - 0, - 0, - 2000, - 0, - 0, - 0, - false); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try a single non-repeating tone at 0dBm0 */ - tone_gen_descriptor_init(&tone_desc, - 820, - 0, - 0, - 0, - 2000, - 0, - 0, - 0, - false); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try an AM modulated tone at a modest modulation level (25%) */ - tone_gen_descriptor_init(&tone_desc, - 425, - -10, - -50, - 25, - 100, - 200, - 300, - 400, - true); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - /* Try an AM modulated tone at maximum modulation level (100%) */ - tone_gen_descriptor_init(&tone_desc, - 425, - -10, - -50, - 100, - 100, - 200, - 300, - 400, - true); - tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) - { - len = tone_gen(&tone_state, amp, 160); - printf("Generated %d samples\n", len); - if (len <= 0) - break; - sf_writef_short(outhandle, amp, len); - } - tone_gen_release(&tone_state); - - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit (2); - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/tsb85_extra_tests.sh b/libs/spandsp/tests/tsb85_extra_tests.sh deleted file mode 100755 index 7d4b10146b..0000000000 --- a/libs/spandsp/tests/tsb85_extra_tests.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# spandsp fax tests -# -# 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 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. - -run_tsb85_test() -{ - rm -f tsb85_tests.tif - echo ./tsb85_tests ${TEST} - ./tsb85_tests -x ../spandsp/fax-tests.xml ${TEST} 2>xyzzy2 - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo tsb85_tests ${TEST} failed! - exit $RETVAL - fi -} - -for TEST in PPS-MPS-lost-PPS V17-12000-V29-9600 Phase-D-collision Modem-change-at-CTC ECM-DCN-clipped Non-ECM-DCN-clipped Tx-EOP-echo Tx-PPS-echo Invalid-signalling-rate No-caller-response No-answerer-response T1-after-EOM T1-after-EOMx -do - run_tsb85_test -done diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c deleted file mode 100644 index 5b199491f1..0000000000 --- a/libs/spandsp/tests/tsb85_tests.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * tsb85_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2008 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 -#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_LIBXML_XMLMEMORY_H) -#include -#endif -#if defined(HAVE_LIBXML_PARSER_H) -#include -#endif -#if defined(HAVE_LIBXML_XINCLUDE_H) -#include -#endif - -#include "spandsp.h" -#include "spandsp-sim.h" - -#include "fax_utils.h" -#include "fax_tester.h" - -#define OUTPUT_TIFF_FILE_NAME "tsb85.tif" - -#define OUTPUT_WAVE_FILE_NAME "tsb85.wav" - -#define SAMPLES_PER_CHUNK 160 - -SNDFILE *out_handle; - -const char *output_tiff_file_name; - -bool log_audio = false; - -faxtester_state_t *state; - -static void exchange(faxtester_state_t *s) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int len; - int i; - int total_audio_time; - logging_state_t *logging; - - output_tiff_file_name = OUTPUT_TIFF_FILE_NAME; - - if (log_audio) - { - if ((out_handle = sf_open_telephony_write(OUTPUT_WAVE_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - printf("Test failed\n"); - exit(2); - } - /*endif*/ - } - /*endif*/ - - total_audio_time = 0; - - faxtester_set_transmit_on_idle(s, true); - - s->far_fax = fax_init(NULL, false); - s->far_t30 = fax_get_t30_state(s->far_fax); - s->far_tag = 'A'; - - if (s->far_fax) - logging = fax_get_logging_state(s->far_fax); - else - logging = t38_terminal_get_logging_state(s->far_t38); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - - logging = t30_get_logging_state(s->far_t30); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - -#if 0 - span_log_set_level(&fax.modems.v27ter_rx.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(&fax.modems.v27ter_rx.logging, "A"); - span_log_set_level(&fax.modems.v29_rx.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(&fax.modems.v29_rx.logging, "A"); - span_log_set_level(&fax.modems.v17_rx.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(&fax.modems.v17_rx.logging, "A"); -#endif - while (faxtester_next_step(s) == 0) - ; - /*endwhile*/ - for (;;) - { - len = fax_tx(s->far_fax, amp, SAMPLES_PER_CHUNK); - faxtester_rx(s, amp, len); - if (log_audio) - { - for (i = 0; i < len; i++) - out_amp[2*i + 0] = amp[i]; - /*endfor*/ - } - /*endif*/ - - total_audio_time += SAMPLES_PER_CHUNK; - - logging = t30_get_logging_state(s->far_t30); - span_log_bump_samples(logging, len); -#if 0 - span_log_bump_samples(&fax.modems.v27ter_rx.logging, len); - span_log_bump_samples(&fax.modems.v29_rx.logging, len); - span_log_bump_samples(&fax.modems.v17_rx.logging, len); -#endif - logging = fax_get_logging_state(s->far_fax); - span_log_bump_samples(logging, len); - - logging = faxtester_get_logging_state(s); - span_log_bump_samples(logging, len); - - len = faxtester_tx(s, amp, SAMPLES_PER_CHUNK); - if (fax_rx(s->far_fax, amp, len)) - break; - /*endif*/ - if (log_audio) - { - for (i = 0; i < len; i++) - out_amp[2*i + 1] = amp[i]; - /*endfor*/ - if (sf_writef_short(out_handle, out_amp, SAMPLES_PER_CHUNK) != SAMPLES_PER_CHUNK) - break; - /*endif*/ - } - /*endif*/ - if (s->test_for_call_clear && !s->far_end_cleared_call) - { - s->call_clear_timer += len; - if (!t30_call_active(s->far_t30)) - { - span_log(faxtester_get_logging_state(s), SPAN_LOG_FLOW, "Far end cleared after %dms (limits %dms to %dms)\n", s->call_clear_timer/8, s->timein_x, s->timeout); - if (s->call_clear_timer/8 < s->timein_x || s->call_clear_timer/8 > s->timeout_x) - { - printf("Test failed\n"); - exit(2); - } - span_log(faxtester_get_logging_state(s), SPAN_LOG_FLOW, "Clear time OK\n"); - s->far_end_cleared_call = true; - s->test_for_call_clear = false; - while (faxtester_next_step(s) == 0) - ; - /*endwhile*/ - } - /*endif*/ - } - /*endif*/ - } - /*endfor*/ - if (log_audio) - { - if (sf_close_telephony(out_handle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME); - printf("Test failed\n"); - exit(2); - } - /*endif*/ - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - const char *xml_file_name; - const char *test_name; - logging_state_t *logging; - int opt; - -#if 0 - string_test(); -#endif - - xml_file_name = "../spandsp/tsb85.xml"; - test_name = "MRGN01"; - log_audio = false; - while ((opt = getopt(argc, argv, "lx:")) != -1) - { - switch (opt) - { - case 'l': - log_audio = true; - break; - case 'x': - xml_file_name = optarg; - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - if (argc > 0) - test_name = argv[0]; - - if ((state = faxtester_init(NULL, xml_file_name, test_name)) == NULL) - { - fprintf(stderr, "Cannot start FAX tester instance\n"); - printf("Test failed\n"); - exit(2); - } - logging = faxtester_get_logging_state(state); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); - /* We found the test we want, so run it. */ - exchange(state); - faxtester_free(state); - printf("Done\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/tsb85_tests.sh b/libs/spandsp/tests/tsb85_tests.sh deleted file mode 100755 index f20bbfaa97..0000000000 --- a/libs/spandsp/tests/tsb85_tests.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/sh -# -# spandsp fax tests -# -# 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 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. - -run_tsb85_test() -{ - rm -f tsb85_tests.tif - echo ./tsb85_tests ${TEST} - ./tsb85_tests ${TEST} 2>xyzzy2 - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo tsb85_tests ${TEST} failed! - exit $RETVAL - fi -} - -for TEST in MRGN01 MRGN02 MRGN03 MRGN04 MRGN05 MRGN06a MRGN06b MRGN07 MRGN08 -do - run_tsb85_test -done - -for TEST in MRGN09 MRGN10 MRGN11 MRGN12 MRGN13 MRGN14 MRGN15 MRGN16 MRGN17 -do - run_tsb85_test -done - -for TEST in ORGC01 ORGC02 ORGC03 -do - run_tsb85_test -done - -for TEST in OREN01 OREN02 OREN03 OREN04 OREN05 OREN06 OREN07 OREN08 OREN09 OREN10 -do - run_tsb85_test -done - -for TEST in MRGX01 MRGX02 MRGX03 MRGX04 MRGX05 MRGX06 MRGX07 MRGX08 -do - run_tsb85_test -done - -for TEST in MRGX09 MRGX10 MRGX11 MRGX12 MRGX13 MRGX14 MRGX15 -do - run_tsb85_test -done - -for TEST in MTGP01 MTGP02 OTGP03 -do - run_tsb85_test -done - -for TEST in MTGN01 MTGN02 MTGN03 MTGN04 MTGN05 MTGN06 MTGN07 MTGN08 MTGN09 MTGN10 -do - run_tsb85_test -done - -for TEST in MTGN11 MTGN12 MTGN13 MTGN14 MTGN15 MTGN16 MTGN17 MTGN18 MTGN19 MTGN20 -do - run_tsb85_test -done - -for TEST in MTGN21 MTGN22 MTGN23 MTGN24 MTGN25 MTGN26 MTGN27 MTGN28 -do - run_tsb85_test -done - -for TEST in OTGC01 OTGC02 OTGC03 OTGC04 OTGC05 OTGC06 OTGC07 OTGC08 -do - run_tsb85_test -done - -for TEST in OTGC09-01 OTGC09-02 OTGC09-03 OTGC09-04 OTGC09-05 OTGC09-06 OTGC09-07 OTGC09-08 OTGC09-09 OTGC09-10 OTGC09-11 OTGC09-12 -do - run_tsb85_test -done - -for TEST in OTGC10 OTGC11 -do - run_tsb85_test -done - -for TEST in OTEN01 OTEN02 OTEN03 OTEN04 OTEN05 OTEN06 -do - run_tsb85_test -done - -for TEST in MTGX01 MTGX02 MTGX03 MTGX04 MTGX05 MTGX06 MTGX07 MTGX08 -do - run_tsb85_test -done - -for TEST in MTGX09 MTGX10 MTGX11 MTGX12 MTGX13 MTGX14 MTGX15 MTGX16 -do - run_tsb85_test -done - -for TEST in MTGX17 MTGX18 MTGX19 MTGX20 MTGX21 MTGX22 MTGX23 -do - run_tsb85_test -done - -for TEST in MRGP01 MRGP02 MRGP03 MRGP04 MRGP05 MRGP06 MRGP07 MRGP08 -do - run_tsb85_test -done - -for TEST in ORGP09 ORGP10 -do - run_tsb85_test -done diff --git a/libs/spandsp/tests/udptl.c b/libs/spandsp/tests/udptl.c deleted file mode 100644 index e44fa023fa..0000000000 --- a/libs/spandsp/tests/udptl.c +++ /dev/null @@ -1,655 +0,0 @@ -//#define UDPTL_DEBUG -/* - * SpanDSP - a series of DSP components for telephony - * - * udptl.c - An implementation of the UDPTL protocol defined in T.38, - * less the packet exchange part - * - * Written by Steve Underwood - * - * Copyright (C) 2005, 2009, 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#if defined(HAVE_STDBOOL_H) -#include -#else -#include -#endif - -#include "udptl.h" - -static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue) -{ - if (*len >= limit) - return -1; - if ((buf[*len] & 0x80) == 0) - { - *pvalue = buf[(*len)++]; - return 0; - } - if ((buf[*len] & 0x40) == 0) - { - if (*len >= limit - 1) - return -1; - *pvalue = (buf[(*len)++] & 0x3F) << 8; - *pvalue |= buf[(*len)++]; - return 0; - } - *pvalue = (buf[(*len)++] & 0x3F) << 14; - /* Indicate that we have a fragment */ - return 1; -} -/*- End of function --------------------------------------------------------*/ - -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; - - *p_num_octets = 0; - for (octet_idx = 0; ; octet_idx += octet_cnt) - { - if ((stat = decode_length(buf, limit, len, &octet_cnt)) < 0) - return -1; - if (octet_cnt > 0) - { - *p_num_octets += octet_cnt; - - pbuf = &p_object[octet_idx]; - /* Make sure the buffer contains at least the number of bits requested */ - if ((*len + octet_cnt) > limit) - return -1; - - *pbuf = &buf[*len]; - *len += octet_cnt; - } - 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 --------------------------------------------------------*/ - -static int encode_length(uint8_t *buf, int *len, int value) -{ - int multiplier; - - if (value < 0x80) - { - /* 1 octet */ - buf[(*len)++] = value; - return value; - } - if (value < 0x4000) - { - /* 2 octets */ - /* Set the first bit of the first octet */ - buf[(*len)++] = ((0x8000 | value) >> 8) & 0xFF; - buf[(*len)++] = value & 0xFF; - return value; - } - /* Fragmentation */ - multiplier = (value < 0x10000) ? (value >> 14) : 4; - /* Set the first 2 bits of the octet */ - buf[(*len)++] = 0xC0 | multiplier; - return multiplier << 14; -} -/*- End of function --------------------------------------------------------*/ - -static int encode_open_type(uint8_t *buf, int *len, const uint8_t *data, int num_octets) -{ - int enclen; - int octet_idx; - uint8_t zero_byte; - - /* If open type is of zero length, add a single zero byte (10.1) */ - if (num_octets == 0) - { - zero_byte = 0; - data = &zero_byte; - num_octets = 1; - } - /* Encode the open type */ - for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) - { - if ((enclen = encode_length(buf, len, num_octets)) < 0) - return -1; - if (enclen > 0) - { - memcpy(&buf[*len], &data[octet_idx], enclen); - *len += enclen; - } - if (enclen >= num_octets) - break; - } - - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len) -{ - int stat; - int i; - int j; - int k; - int l; - int m; - int x; - int limit; - int which; - int ptr; - int count; - int total_count; - int seq_no; - const uint8_t *msg; - const uint8_t *data; - int msg_len; - int repaired[16]; - const uint8_t *bufs[16]; - int lengths[16]; - int span; - int entries; - - ptr = 0; - /* Decode seq_number */ - if (ptr + 2 > len) - return -1; - seq_no = (buf[0] << 8) | buf[1]; - ptr += 2; - /* Break out the primary packet */ - if ((stat = decode_open_type(buf, len, &ptr, &msg, &msg_len)) != 0) - return -1; - /* Decode error_recovery */ - if (ptr + 1 > len) - return -1; - /* Our buffers cannot tolerate overlength packets */ - if (msg_len > LOCAL_FAX_MAX_DATAGRAM) - return -1; - /* Update any missed slots in the buffer */ - for (i = s->rx_seq_no; seq_no > i; i++) - { - x = i & UDPTL_BUF_MASK; - s->rx[x].buf_len = -1; - s->rx[x].fec_len[0] = 0; - s->rx[x].fec_span = 0; - s->rx[x].fec_entries = 0; - } - /* Save the new packet. Pure redundancy mode won't use this, but some systems will switch - into FEC mode after sending some redundant packets. */ - x = seq_no & UDPTL_BUF_MASK; - if (msg_len > 0) - memcpy(s->rx[x].buf, msg, msg_len); - s->rx[x].buf_len = msg_len; - s->rx[x].fec_len[0] = 0; - s->rx[x].fec_span = 0; - s->rx[x].fec_entries = 0; - if ((buf[ptr++] & 0x80) == 0) - { - /* Secondary packet mode for error recovery */ - /* We might have the packet we want, but we need to check through - the redundant stuff, and verify the integrity of the UDPTL. - This greatly reduces our chances of accepting garbage. */ - total_count = 0; - do - { - if ((stat = decode_length(buf, len, &ptr, &count)) < 0) - return -1; - if ((total_count + count) >= 16) - { - /* There is too much stuff here to be real, and it would overflow the bufs array - if we continue */ - return -1; - } - for (i = 0; i < count; i++) - { - if (decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i]) != 0) - return -1; - } - total_count += count; - } - 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; - if (seq_no > s->rx_seq_no) - { - /* We received a later packet than we expected, so we need to check if we can fill in the gap from the - secondary packets. */ - /* Step through in reverse order, so we go oldest to newest */ - for (i = total_count; i > 0; i--) - { - if (seq_no - i >= s->rx_seq_no) - { - /* This one wasn't seen before */ - /* Process the secondary packet */ -#if defined(UDPTL_DEBUG) - fprintf(stderr, "Secondary %d, len %d\n", seq_no - i, lengths[i - 1]); -#endif - /* 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; - 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; - s->rx[x].fec_entries = 0; - if (s->rx_packet_handler(s->user_data, bufs[i - 1], lengths[i - 1], seq_no - i) < 0) - fprintf(stderr, "Bad IFP\n"); - } - } - } - } - else - { - /* FEC mode for error recovery */ - - /* Decode the FEC packets */ - /* The span is defined as an unconstrained integer, but will never be more - than a small value. */ - if (ptr + 2 > len) - return -1; - if (buf[ptr++] != 1) - return -1; - span = buf[ptr++]; - - x = seq_no & UDPTL_BUF_MASK; - - s->rx[x].fec_span = span; - - memset(repaired, 0, sizeof(repaired)); - repaired[x] = true; - - /* The number of entries is defined as a length, but will only ever be a small - value. Treat it as such. */ - if (ptr + 1 > len) - return -1; - entries = buf[ptr++]; - s->rx[x].fec_entries = entries; - - /* Decode the elements */ - for (i = 0; i < entries; i++) - { - if ((stat = decode_open_type(buf, len, &ptr, &data, &s->rx[x].fec_len[i])) != 0) - return -1; - if (s->rx[x].fec_len[i] > LOCAL_FAX_MAX_DATAGRAM) - return -1; - - /* Save the new FEC data */ - if (s->rx[x].fec_len[i]) - memcpy(s->rx[x].fec[i], data, s->rx[x].fec_len[i]); -#if 0 - fprintf(stderr, "FEC: "); - for (j = 0; j < s->rx[x].fec_len[i]; j++) - fprintf(stderr, "%02X ", data[j]); - fprintf(stderr, "\n"); -#endif - } - /* We should now be exactly at the end of the packet. If not, this is a fault. */ - if (ptr != len) - return -1; - /* See if we can reconstruct anything which is missing */ - /* TODO: this does not comprehensively hunt back and repair everything that is possible */ - for (l = x; l != ((x - (16 - span*entries)) & UDPTL_BUF_MASK); l = (l - 1) & UDPTL_BUF_MASK) - { - if (s->rx[l].fec_len[0] <= 0) - continue; - for (m = 0; m < s->rx[l].fec_entries; m++) - { - limit = (l + m) & UDPTL_BUF_MASK; - for (which = -1, k = (limit - s->rx[l].fec_span*s->rx[l].fec_entries) & UDPTL_BUF_MASK; - k != limit; - k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) - { - if (s->rx[k].buf_len <= 0) - which = (which == -1) ? k : -2; - } - if (which >= 0) - { - /* Repairable */ - for (j = 0; j < s->rx[l].fec_len[m]; j++) - { - s->rx[which].buf[j] = s->rx[l].fec[m][j]; - for (k = (limit - s->rx[l].fec_span*s->rx[l].fec_entries) & UDPTL_BUF_MASK; - k != limit; - k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) - { - s->rx[which].buf[j] ^= (s->rx[k].buf_len > j) ? s->rx[k].buf[j] : 0; - } - } - s->rx[which].buf_len = s->rx[l].fec_len[m]; - repaired[which] = true; - } - } - } - /* Now play any new packets forwards in time */ - for (l = (x + 1) & UDPTL_BUF_MASK, j = seq_no - UDPTL_BUF_MASK; l != x; l = (l + 1) & UDPTL_BUF_MASK, j++) - { - if (repaired[l]) - { -#if defined(UDPTL_DEBUG) - fprintf(stderr, "Fixed packet %d, len %d\n", j, l); -#endif - if (s->rx_packet_handler(s->user_data, s->rx[l].buf, s->rx[l].buf_len, j) < 0) - fprintf(stderr, "Bad IFP\n"); - } - } - } - /* If packets are received out of sequence, we may have already processed this packet - from the error recovery information in a packet already received. */ - if (seq_no >= s->rx_seq_no) - { - /* Decode the primary packet */ -#if defined(UDPTL_DEBUG) - fprintf(stderr, "Primary packet %d, len %d\n", seq_no, msg_len); -#endif - if (s->rx_packet_handler(s->user_data, msg, msg_len, seq_no) < 0) - fprintf(stderr, "Bad IFP\n"); - } - - s->rx_seq_no = (seq_no + 1) & 0xFFFF; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int msg_len) -{ - uint8_t fec[LOCAL_FAX_MAX_DATAGRAM]; - int i; - int j; - int seq; - int entry; - int entries; - int span; - int m; - int len; - int limit; - int high_tide; - int len_before_entries; - int previous_len; - - /* UDPTL cannot cope with zero length messages, and our buffering for redundancy limits their - maximum length. */ - if (msg_len < 1 || msg_len > LOCAL_FAX_MAX_DATAGRAM) - return -1; - seq = s->tx_seq_no & 0xFFFF; - - /* Map the sequence number to an entry in the circular buffer */ - entry = seq & UDPTL_BUF_MASK; - - /* We save the message in a circular buffer, for generating FEC or - redundancy sets later on. */ - s->tx[entry].buf_len = msg_len; - memcpy(s->tx[entry].buf, msg, msg_len); - - /* Build the UDPTL packet */ - - len = 0; - /* Encode the sequence number */ - buf[len++] = (seq >> 8) & 0xFF; - buf[len++] = seq & 0xFF; - - /* Encode the primary packet */ - if (encode_open_type(buf, &len, msg, msg_len) < 0) - return -1; - - /* Encode the appropriate type of error recovery information */ - switch (s->error_correction_scheme) - { - case UDPTL_ERROR_CORRECTION_NONE: - /* Encode the error recovery type */ - buf[len++] = 0x00; - /* The number of entries will always be zero, so it is pointless allowing - for the fragmented case here. */ - if (encode_length(buf, &len, 0) < 0) - return -1; - break; - case UDPTL_ERROR_CORRECTION_REDUNDANCY: - /* Encode the error recovery type */ - buf[len++] = 0x00; - if (s->tx_seq_no > s->error_correction_entries) - entries = s->error_correction_entries; - else - entries = s->tx_seq_no; - len_before_entries = len; - /* The number of entries will always be small, so it is pointless allowing - for the fragmented case here. */ - if (encode_length(buf, &len, entries) < 0) - return -1; - /* Encode the elements */ - for (m = 0; m < entries; m++) - { - previous_len = len; - j = (entry - m - 1) & UDPTL_BUF_MASK; - if (encode_open_type(buf, &len, s->tx[j].buf, s->tx[j].buf_len) < 0) - return -1; - - /* If we have exceeded the far end's max datagram size, don't include this last chunk, - and stop trying to add more. */ - if (len > s->far_max_datagram_size) - { - len = previous_len; - if (encode_length(buf, &len_before_entries, m) < 0) - return -1; - break; - } - } - break; - case UDPTL_ERROR_CORRECTION_FEC: - span = s->error_correction_span; - entries = s->error_correction_entries; - if (seq < s->error_correction_span*s->error_correction_entries) - { - /* In the initial stages, wind up the FEC smoothly */ - entries = seq/s->error_correction_span; - if (seq < s->error_correction_span) - span = 0; - } - /* Encode the error recovery type */ - buf[len++] = 0x80; - /* Span is defined as an inconstrained integer, which it dumb. It will only - ever be a small value. Treat it as such. */ - buf[len++] = 1; - buf[len++] = span; - /* The number of entries is defined as a length, but will only ever be a small - value. Treat it as such. */ - len_before_entries = len; - buf[len++] = entries; - for (m = 0; m < entries; m++) - { - previous_len = len; - /* Make an XOR'ed entry the maximum length */ - limit = (entry + m) & UDPTL_BUF_MASK; - high_tide = 0; - for (i = (limit - span*entries) & UDPTL_BUF_MASK; i != limit; i = (i + entries) & UDPTL_BUF_MASK) - { - if (high_tide < s->tx[i].buf_len) - { - for (j = 0; j < high_tide; j++) - fec[j] ^= s->tx[i].buf[j]; - for ( ; j < s->tx[i].buf_len; j++) - fec[j] = s->tx[i].buf[j]; - high_tide = s->tx[i].buf_len; - } - else - { - for (j = 0; j < s->tx[i].buf_len; j++) - fec[j] ^= s->tx[i].buf[j]; - } - } - if (encode_open_type(buf, &len, fec, high_tide) < 0) - return -1; - - /* If we have exceeded the far end's max datagram size, don't include this last chunk, - and stop trying to add more. */ - if (len > s->far_max_datagram_size) - { - len = previous_len; - buf[len_before_entries] = (uint8_t) m; - break; - } - } - break; - } - - if (s->verbose) - fprintf(stderr, "\n"); - s->tx_seq_no++; - return len; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_set_error_correction(udptl_state_t *s, - int ec_scheme, - int span, - int entries) -{ - switch (ec_scheme) - { - case UDPTL_ERROR_CORRECTION_FEC: - case UDPTL_ERROR_CORRECTION_REDUNDANCY: - case UDPTL_ERROR_CORRECTION_NONE: - s->error_correction_scheme = ec_scheme; - break; - case -1: - /* Just don't change the scheme */ - break; - default: - return -1; - } - if (span >= 0) - s->error_correction_span = span; - if (entries >= 0) - s->error_correction_entries = entries; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_get_error_correction(udptl_state_t *s, int *ec_scheme, int *span, int *entries) -{ - if (ec_scheme) - *ec_scheme = s->error_correction_scheme; - if (span) - *span = s->error_correction_span; - if (entries) - *entries = s->error_correction_entries; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_set_local_max_datagram(udptl_state_t *s, int max_datagram) -{ - s->local_max_datagram_size = max_datagram; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_get_local_max_datagram(udptl_state_t *s) -{ - return s->local_max_datagram_size; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_set_far_max_datagram(udptl_state_t *s, int max_datagram) -{ - s->far_max_datagram_size = max_datagram; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_get_far_max_datagram(udptl_state_t *s) -{ - return s->far_max_datagram_size; -} -/*- End of function --------------------------------------------------------*/ - -udptl_state_t *udptl_init(udptl_state_t *s, - int ec_scheme, - int span, - int entries, - udptl_rx_packet_handler_t rx_packet_handler, - void *user_data) -{ - int i; - - if (rx_packet_handler == NULL) - return NULL; - - if (s == NULL) - { - if ((s = (udptl_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - s->error_correction_scheme = ec_scheme; - s->error_correction_span = span; - s->error_correction_entries = entries; - - s->far_max_datagram_size = LOCAL_FAX_MAX_DATAGRAM; - s->local_max_datagram_size = LOCAL_FAX_MAX_DATAGRAM; - - memset(&s->rx, 0, sizeof(s->rx)); - memset(&s->tx, 0, sizeof(s->tx)); - for (i = 0; i <= UDPTL_BUF_MASK; i++) - { - s->rx[i].buf_len = -1; - s->tx[i].buf_len = -1; - } - - s->rx_packet_handler = rx_packet_handler; - s->user_data = user_data; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -int udptl_release(udptl_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/udptl.h b/libs/spandsp/tests/udptl.h deleted file mode 100644 index ae555cd500..0000000000 --- a/libs/spandsp/tests/udptl.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * udptl.c - * - * Written by Steve Underwood - * - * Copyright (C) 2009 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. - */ - -#if !defined(_SPANDSP_UDPTL_H_) -#define _SPANDSP_UDPTL_H_ - -#define LOCAL_FAX_MAX_DATAGRAM 400 -#define LOCAL_FAX_MAX_FEC_PACKETS 5 - -#define UDPTL_BUF_MASK 15 - -typedef int (*udptl_rx_packet_handler_t) (void *user_data, const uint8_t msg[], int len, int seq_no); - -typedef struct -{ - int buf_len; - uint8_t buf[LOCAL_FAX_MAX_DATAGRAM]; -} udptl_fec_tx_buffer_t; - -typedef struct -{ - int buf_len; - uint8_t buf[LOCAL_FAX_MAX_DATAGRAM]; - int fec_len[LOCAL_FAX_MAX_FEC_PACKETS]; - uint8_t fec[LOCAL_FAX_MAX_FEC_PACKETS][LOCAL_FAX_MAX_DATAGRAM]; - int fec_span; - int fec_entries; -} udptl_fec_rx_buffer_t; - -struct udptl_state_s -{ - udptl_rx_packet_handler_t rx_packet_handler; - void *user_data; - - /*! This option indicates the error correction scheme used in transmitted UDPTL - packets. */ - int error_correction_scheme; - - /*! This option indicates the number of error correction entries transmitted in - UDPTL packets. */ - int error_correction_entries; - - /*! This option indicates the span of the error correction entries in transmitted - UDPTL packets (FEC only). */ - int error_correction_span; - - /*! This option indicates the maximum size of a datagram that can be accepted by - the remote device. */ - int far_max_datagram_size; - - /*! This option indicates the maximum size of a datagram that we are prepared to - accept. */ - int local_max_datagram_size; - - int verbose; - - int tx_seq_no; - int rx_seq_no; - int rx_expected_seq_no; - - udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1]; - udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1]; -}; - -enum -{ - UDPTL_ERROR_CORRECTION_NONE, - UDPTL_ERROR_CORRECTION_FEC, - UDPTL_ERROR_CORRECTION_REDUNDANCY -}; - -typedef struct udptl_state_s udptl_state_t; - -#if defined(__cplusplus) -extern "C" { -#endif - -/*! \brief Process an arriving UDPTL packet. - \param s The UDPTL context. - \param buf The UDPTL packet buffer. - \param len The length of the packet. - \return 0 for OK. */ -int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len); - -/*! \brief Construct a UDPTL packet, ready for transmission. - \param s The UDPTL context. - \param buf The UDPTL packet buffer. - \param msg The primary packet. - \param len The length of the primary packet. - \return The length of the constructed UDPTL packet. */ -int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int msg_len); - -/*! \brief Change the error correction settings of a UDPTL context. - \param s The UDPTL context. - \param ec_scheme One of the optional error correction schemes. - \param span The packet span over which error correction should be applied. - \param entries The number of error correction entries to include in packets. - \return 0 for OK. */ -int udptl_set_error_correction(udptl_state_t *s, int ec_scheme, int span, int entries); - -/*! \brief Check the error correction settings of a UDPTL context. - \param s The UDPTL context. - \param ec_scheme One of the optional error correction schemes. - \param span The packet span over which error correction is being applied. - \param entries The number of error correction being included in packets. - \return 0 for OK. */ -int udptl_get_error_correction(udptl_state_t *s, int *ec_scheme, int *span, int *entries); - -int udptl_set_local_max_datagram(udptl_state_t *s, int max_datagram); - -int udptl_get_local_max_datagram(udptl_state_t *s); - -int udptl_set_far_max_datagram(udptl_state_t *s, int max_datagram); - -int udptl_get_far_max_datagram(udptl_state_t *s); - -/*! \brief Initialise a UDPTL context. - \param s The UDPTL context. - \param ec_scheme One of the optional error correction schemes. - \param span The packet span over which error correction should be applied. - \param entries The number of error correction entries to include in packets. - \param rx_packet_handler The callback function, used to report arriving IFP packets. - \param user_data An opaque pointer supplied to rx_packet_handler. - \return A pointer to the UDPTL context, or NULL if there was a problem. */ -udptl_state_t *udptl_init(udptl_state_t *s, int ec_scheme, int span, int entries, udptl_rx_packet_handler_t rx_packet_handler, void *user_data); - -/*! \brief Release a UDPTL context. - \param s The UDPTL context. - \return 0 for OK. */ -int udptl_release(udptl_state_t *s); - -#if defined(__cplusplus) -} -#endif -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v17_tests.c b/libs/spandsp/tests/v17_tests.c deleted file mode 100644 index 4ef9f7306f..0000000000 --- a/libs/spandsp/tests/v17_tests.c +++ /dev/null @@ -1,604 +0,0 @@ -//#define ADD_MAINS_INTERFERENCE -/* - * SpanDSP - a series of DSP components for telephony - * - * v17_tests.c - * - * 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 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. - */ - -/*! \page v17_tests_page V.17 modem tests -\section v17_tests_page_sec_1 What does it do? -These tests test one way paths, as V.17 is a half-duplex modem. They allow either: - - - A V.17 transmit modem to feed a V.17 receive modem through a telephone line - model. BER testing is then used to evaluate performance under various line - conditions. This is effective for testing the basic performance of the - receive modem. It is also the only test mode provided for evaluating the - transmit modem. - - - A V.17 receive modem is used to decode V.17 audio, stored in a audio file. - This is good way to evaluate performance with audio recorded from other - models of modem, and with real world problematic telephone lines. - -If the appropriate GUI environment exists, the tests are built such that a visual -display of modem status is maintained. - -\section v17_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_FENV_H) -#define __USE_GNU -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "modem_monitor.h" -#include "line_model_monitor.h" -#endif - -#define BLOCK_LEN 160 - -#define OUT_FILE_NAME "v17.wav" - -char *decode_test_file = NULL; -bool use_gui = false; - -int symbol_no = 0; - -int rx_bits = 0; -int tx_bits = 0; - -int test_bps; - -bert_state_t bert; -one_way_line_model_state_t *line_model; - -#if defined(ENABLE_GUI) -qam_monitor_t *qam_monitor; -#endif - -bert_results_t latest_results; - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - switch (reason) - { - case BERT_REPORT_REGULAR: - fprintf(stderr, "BERT report regular - %d bits, %d bad bits, %d resyncs\n", results->total_bits, results->bad_bits, results->resyncs); - memcpy(&latest_results, results, sizeof(latest_results)); - break; - default: - fprintf(stderr, "BERT report %s\n", bert_event_to_str(reason)); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v17_rx_status(void *user_data, int status) -{ - v17_rx_state_t *s; - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - - printf("V.17 rx status is %s (%d)\n", signal_status_to_str(status), status); - s = (v17_rx_state_t *) user_data; - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - printf("Training succeeded\n"); - if ((len = v17_rx_equalizer_state(s, &coeffs))) - { - printf("Equalizer:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V17_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V17_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v17putbit(void *user_data, int bit) -{ - if (bit < 0) - { - v17_rx_status(user_data, bit); - return; - } - - if (decode_test_file) - printf("Rx bit %d - %d\n", rx_bits++, bit); - else - bert_put_bit(&bert, bit); -} -/*- End of function --------------------------------------------------------*/ - -static void v17_tx_status(void *user_data, int status) -{ - printf("V.17 tx status is %s (%d)\n", signal_status_to_str(status), status); -} -/*- End of function --------------------------------------------------------*/ - -static int v17getbit(void *user_data) -{ - return bert_get_bit(&bert); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void qam_report(void *user_data, const complexi16_t *constel, const complexi16_t *target, int symbol) -#else -static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol) -#endif -{ - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - complexf_t constel_point; - complexf_t target_point; - float fpower; - v17_rx_state_t *rx; - static float smooth_power = 0.0f; - static int update_interval = 100; - - rx = (v17_rx_state_t *) user_data; - if (constel) - { - constel_point.re = constel->re/V17_CONSTELLATION_SCALING_FACTOR; - constel_point.im = constel->im/V17_CONSTELLATION_SCALING_FACTOR; - target_point.re = target->re/V17_CONSTELLATION_SCALING_FACTOR, - target_point.im = target->im/V17_CONSTELLATION_SCALING_FACTOR, - fpower = (constel_point.re - target_point.re)*(constel_point.re - target_point.re) - + (constel_point.im - target_point.im)*(constel_point.im - target_point.im); - smooth_power = 0.95f*smooth_power + 0.05f*fpower; -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor_update_constel(qam_monitor, &constel_point); - qam_monitor_update_carrier_tracking(qam_monitor, v17_rx_carrier_frequency(rx)); - qam_monitor_update_symbol_tracking(qam_monitor, v17_rx_symbol_timing_correction(rx)); - } -#endif - printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %9.4f %7.3f %7.4f\n", - symbol_no, - constel_point.re, - constel_point.im, - target_point.re, - target_point.im, - symbol, - fpower, - smooth_power, - v17_rx_carrier_frequency(rx), - v17_rx_signal_power(rx), - v17_rx_symbol_timing_correction(rx)); - symbol_no++; - if (--update_interval <= 0) - { - if ((len = v17_rx_equalizer_state(rx, &coeffs))) - { - printf("Equalizer A:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V17_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V17_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif -#if defined(ENABLE_GUI) - if (use_gui) - { -#if defined(SPANDSP_USE_FIXED_POINT) - qam_monitor_update_int_equalizer(qam_monitor, coeffs, len); -#else - qam_monitor_update_equalizer(qam_monitor, coeffs, len); -#endif - } -#endif - } - update_interval = 100; - } - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_FENV_H) -static void sigfpe_handler(int sig_num, siginfo_t *info, void *data) -{ - switch (sig_num) - { - case SIGFPE: - switch (info->si_code) - { - case FPE_INTDIV: - fprintf(stderr, "integer divide by zero at %p\n", info->si_addr); - break; - case FPE_INTOVF: - fprintf(stderr, "integer overflow at %p\n", info->si_addr); - break; - case FPE_FLTDIV: - fprintf(stderr, "FP divide by zero at %p\n", info->si_addr); - break; - case FPE_FLTOVF: - fprintf(stderr, "FP overflow at %p\n", info->si_addr); - break; - case FPE_FLTUND: - fprintf(stderr, "FP underflow at %p\n", info->si_addr); - break; - case FPE_FLTRES: - fprintf(stderr, "FP inexact result at %p\n", info->si_addr); - break; - case FPE_FLTINV: - fprintf(stderr, "FP invalid operation at %p\n", info->si_addr); - break; - case FPE_FLTSUB: - fprintf(stderr, "subscript out of range at %p\n", info->si_addr); - break; - } - break; - default: - fprintf(stderr, "Unexpected signal %d\n", sig_num); - break; - } - exit(2); -} -/*- End of function --------------------------------------------------------*/ - -static void fpe_trap_setup(void) -{ - struct sigaction trap; - - sigemptyset(&trap.sa_mask); - trap.sa_flags = SA_SIGINFO; - trap.sa_sigaction = sigfpe_handler; - - sigaction(SIGFPE, &trap, NULL); - //feenableexcept(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); - //feenableexcept(FE_ALL_EXCEPT); - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -} -/*- End of function --------------------------------------------------------*/ -#endif - -int main(int argc, char *argv[]) -{ - v17_rx_state_t *rx; - v17_tx_state_t *tx; - bert_results_t bert_results; - int16_t gen_amp[BLOCK_LEN]; - int16_t amp[BLOCK_LEN]; - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int samples; - int block_no; - int noise_level; - int signal_level; - int bits_per_test; - int line_model_no; - 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; - line_model_no = 0; - decode_test_file = NULL; - use_gui = false; - noise_level = -70; - signal_level = -13; - bits_per_test = 50000; - log_audio = false; - while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:r:s:t")) != -1) - { - switch (opt) - { - case 'b': - test_bps = atoi(optarg); - if (test_bps != 14400 - && - test_bps != 12000 - && - test_bps != 9600 - && - test_bps != 7200 - && - test_bps != 4800) - { - /* 4800 is an extension of V.17, to provide full coverage of the V.32bis modes */ - fprintf(stderr, "Invalid bit rate specified\n"); - exit(2); - } - break; - case 'B': - bits_per_test = atoi(optarg); - break; - case 'c': - channel_codec = atoi(optarg); - break; - case 'd': - decode_test_file = optarg; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'n': - noise_level = atoi(optarg); - break; - case 'r': - rbs_pattern = atoi(optarg); - break; - case 's': - signal_level = atoi(optarg); - break; - case 't': - tep = true; - break; - default: - //usage(); - exit(2); - break; - } - } - inhandle = NULL; - outhandle = NULL; - -#if defined(HAVE_FENV_H) - fpe_trap_setup(); -#endif - - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - - if (decode_test_file) - { - /* We will decode the audio from a file. */ - tx = NULL; - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - } - else - { - /* We will generate V.17 audio, and add some noise to it. */ - tx = v17_tx_init(NULL, test_bps, tep, v17getbit, NULL); - logging = v17_tx_get_logging_state(tx); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "V.17-tx"); - v17_tx_power(tx, signal_level); - v17_tx_set_modem_status_handler(tx, v17_tx_status, (void *) tx); -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - /* Move the carrier off a bit */ - tx->carrier_phase_rate = dds_phase_ratef(1792.0f); - tx->carrier_phase = 0x40000000; -#endif - - bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&bert, 10000, reporter, NULL); - - if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - one_way_line_model_set_dc(line_model, 0.0f); -#if defined(ADD_MAINS_INTERFERENCE) - one_way_line_model_set_mains_pickup(line_model, 50, -40.0f); -#endif - } - - rx = v17_rx_init(NULL, test_bps, v17putbit, NULL); - logging = v17_rx_get_logging_state(rx); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "V.17-rx"); - v17_rx_set_modem_status_handler(rx, v17_rx_status, (void *) rx); - v17_rx_set_qam_report_handler(rx, qam_report, (void *) rx); - -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor = qam_monitor_init(10.0f, V17_CONSTELLATION_SCALING_FACTOR, NULL); - if (!decode_test_file) - { - start_line_model_monitor(129); - line_model_monitor_line_model_update(line_model->near_filter, line_model->near_filter_len); - } - } -#endif - - memset(&latest_results, 0, sizeof(latest_results)); - for (block_no = 0; block_no < 100000000; block_no++) - { - if (decode_test_file) - { - samples = sf_readf_short(inhandle, amp, BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(qam_monitor, amp, samples); -#endif - if (samples == 0) - break; - } - else - { - samples = v17_tx(tx, gen_amp, BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(qam_monitor, gen_amp, samples); -#endif - if (samples == 0) - { - printf("Restarting on zero output\n"); - - /* Push a little silence through, to ensure all the data bits get out of the buffers */ - vec_zeroi16(amp, BLOCK_LEN); - v17_rx(rx, amp, BLOCK_LEN); - - /* Note that we might get a few bad bits as the carrier shuts down. */ - bert_result(&bert, &bert_results); - fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - /* See if bit errors are appearing yet. Also check we are getting enough bits out of the receiver. The last regular report - should be error free, though the final report will generally contain bits errors as the carrier was dying. The total - number of bits out of the receiver should be at least the number we sent. Also, since BERT sync should have occurred - rapidly at the start of transmission, the last report should have occurred at not much less than the total number of - bits we sent. */ - if (bert_results.total_bits < bits_per_test - || - latest_results.total_bits < bits_per_test - 100 - || - latest_results.bad_bits != 0) - { - break; - } - memset(&latest_results, 0, sizeof(latest_results)); -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - signal_level--; - /* 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_power(tx, signal_level); - 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); - one_way_line_model_free(line_model); - if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, 0)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - } - if (log_audio) - { - outframes = sf_writef_short(outhandle, gen_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - one_way_line_model(line_model, amp, gen_amp, samples); - } -#if defined(ENABLE_GUI) - if (use_gui && !decode_test_file) - line_model_monitor_line_spectrum_update(amp, samples); -#endif - v17_rx(rx, amp, samples); - } - if (!decode_test_file) - { - bert_result(&bert, &bert_results); - fprintf(stderr, "At completion:\n"); - fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - one_way_line_model_free(line_model); - - if (signal_level > -43) - { - printf("Tests failed.\n"); - exit(2); - } - - printf("Tests passed.\n"); - } - v17_rx_free(rx); - if (tx) - v17_tx_free(tx); -#if defined(ENABLE_GUI) - if (use_gui) - qam_wait_to_end(qam_monitor); -#endif - if (decode_test_file) - { - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v17_tests.sh b/libs/spandsp/tests/v17_tests.sh deleted file mode 100755 index 5657afd348..0000000000 --- a/libs/spandsp/tests/v17_tests.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -STDOUT_DEST=xyzzy -STDERR_DEST=xyzzy2 - -for OPTS in "-b 14400 -s -42 -n -66" "-b 12000 -s -42 -n -61" "-b 9600 -s -42 -n -59" "-b 7200 -s -42 -n -56" -do - ./v17_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo v17_tests ${OPTS} failed! - exit $RETVAL - fi -done -echo v17_tests completed OK diff --git a/libs/spandsp/tests/v18_tests.c b/libs/spandsp/tests/v18_tests.c deleted file mode 100644 index 866eac8027..0000000000 --- a/libs/spandsp/tests/v18_tests.c +++ /dev/null @@ -1,8995 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v18_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2004-2009 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. - */ - -/*! \page v18_tests_page V.18 tests -\section v18_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define OUTPUT_FILE_NAME "v18.wav" - -#define SAMPLES_PER_CHUNK 160 - -#define CHUNKS_PER_SECOND 50 - -#define TESTER 0 -#define TUT 1 - -int log_audio = false; -SNDFILE *outhandle = NULL; -char result[2][1024]; -int unexpected_echo = false; - -char *decode_test_file = NULL; - -int good_message_received; - -both_ways_line_model_state_t *model; -int rbs_pattern = 0; -int line_model_no = 0; -#if 0 -float echo_level_cpe1 = -15.0f; -float echo_level_co1 = -15.0f; -float echo_level_cpe2 = -15.0f; -float echo_level_co2 = -15.0f; -#else -float echo_level_cpe1 = -99.0f; -float echo_level_co1 = -99.0f; -float echo_level_cpe2 = -99.0f; -float echo_level_co2 = -99.0f; -#endif -float noise_level = -70.0f; -int channel_codec = MUNGE_CODEC_NONE; -v18_state_t *v18[2]; - -const char *qbf_tx = "The quick Brown Fox Jumps Over The Lazy dog 0123456789!@#$%^&*()'"; -const char *qbf_rx = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 0123456789!X$$/'+.()'"; -const char *full_baudot_rx = - "\b \n\n\n\r?\n\n\n !\"$$/+'().+,-./" - "0123456789:;(=)?" - "XABCDEFGHIJKLMNOPQRSTUVWXYZ(/)' " - "'ABCDEFGHIJKLMNOPQRSTUVWXYZ(!) "; - -static void put_text_msg(void *user_data, const uint8_t *msg, int len) -{ - if (strcmp((const char *) msg, qbf_rx)) - { - printf("Result:\n%s\n", msg); - printf("Reference result:\n%s\n", qbf_rx); - } - else - { - good_message_received = true; - } -} -/*- End of function --------------------------------------------------------*/ - -static void basic_tests(int mode) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - printf("Testing %s\n", v18_mode_to_str(mode)); - v18[TESTER] = v18_init(NULL, true, mode, V18_AUTOMODING_GLOBAL, put_text_msg, NULL); - logging = v18_get_logging_state(v18[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = v18_init(NULL, false, mode, V18_AUTOMODING_GLOBAL, put_text_msg, NULL); - logging = v18_get_logging_state(v18[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - /* Fake an OK condition for the first message test */ - good_message_received = true; - push = 0; - if (v18_put(v18[TESTER], qbf_tx, -1) != strlen(qbf_tx)) - { - printf("V.18 put failed\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - if (push == 0) - { - if ((samples = v18_tx(v18[TESTER], amp[0], SAMPLES_PER_CHUNK)) == 0) - push = 10; - } - else - { - samples = 0; - /* Push a little silence through, to flush things out */ - if (--push == 0) - { - if (!good_message_received) - { - printf("No message received\n"); - exit(2); - } - good_message_received = false; - if (v18_put(v18[TESTER], qbf_tx, -1) != strlen(qbf_tx)) - { - printf("V.18 put failed\n"); - exit(2); - } - } - } - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[0][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - if ((samples = v18_tx(v18[TUT], amp[1], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[1][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - v18_free(v18[TESTER]); - v18_free(v18[TUT]); -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.1 No disconnection test - Purpose: To verify that the DCE does not initiate a disconnection. - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.3 Retention of selected mode on loss of signal - Purpose: To ensure that the DCE stays in the selected transmission mode if it is not - configured to automatically re-assume the initial automoding state. - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.4 Detection of BUSY tone - Purpose: To ensure that the DCE provides the call progress indication "BUSY" in presence of - the national busy tone. - Preamble: N/A - Method: The TUT should be configured to dial out and then be presented with the - appropriate national busy tone. - Pass criteria: Detection of busy tone should be displayed by the TUT. - Comments: ITU-T V.18 specifies that the DCE should not hang up, but that is intended to apply - to the case where a connection is established and then lost. A terminal may - automatically hang up when busy tone is detected. PABX busy tones may differ in - frequency and cadence from national parameters. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.5 Detection of RINGING - Purpose: To ensure that the DCE provides the call progress indication "RINGING" in - presence of the national ringing tone. - Preamble: N/A - Method: The tester will make a call to the TUT using the nationally recommended cadence - and the minimum recommended ring voltage/current. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.6 "LOSS OF CARRIER" indication - Purpose: To ensure that the DCE provides the call progress indication "LOSS OF CARRIER" - upon a loss of carrier in full duplex modes, i.e. V.21, V.23, Bell 103. - Preamble: N/A - Method: Set up a call in each of the full duplex modes and force a carrier failure to the TUT. - Pass criteria: Loss of carrier should be indicated and disappear when the carrier is restored. - Comments: The V.18 modem should not automatically disconnect when used in a manual - conversation mode. However, a V.18 equipped terminal may disconnect based on - operational decisions, e.g. when it is a terminal in automatic answering machine - mode. There may be other cases, e.g. where the V.18 DCE is used in a gateway, - when automatic disconnection is required. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.7 Call progress indication - Purpose: To ensure that the DCE provides the call progress indication "CONNECT(x)" upon - a connection. - Preamble: N/A - Method: Correct CONNECT messages should be verified during the Automode tests that - follow. - Pass criteria: The relevant mode should be indicated by the DCE when automoding is complete. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.8 Circuit 135 Test - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.1.9 Connection procedures - Purpose: To ensure that the TUT implements the call connect procedure described in - clause 6. - Preamble: N/A - Method: TBD - Pass criteria: TBD - Comment: TBD - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.1 CI and XCI signal coding and cadence - Purpose: To verify that TUT correctly emits the CI and XCI signals with the ON/OFF - cadence defined in 5.1.1. - Preamble: N/A - Method: V.21 demodulator is used to decode the CI sequence and a timer to measure the - silence intervals between them. The XCI signal is also monitored and decoded to - 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 2s after the end of each CI. - 4) Each CI must have the correct bit pattern. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.2 ANS signal detection - Purpose: To verify that TUT correctly detects the ANS (2100Hz) signal during the - two-second interval (Toff) between transmission of CI sequences. - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.3 End of ANS signal detection - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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.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.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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.5 ANS tone followed by 1650Hz - 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.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.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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.6 ANS tone followed by 1300Hz - 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.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.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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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.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.2s of end of ANS. - 3) TUT should return to Monitor 1 state and then connect in DTMF mode within - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.8 Bell 103 (2225Hz signal) detection - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.9 V.21 (1650Hz signal) detection - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.10 V.23 (1300Hz signal) detection - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.11 V.23 (390Hz signal) detection - 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 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 3s after - the start of the 390Hz tone. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.12 5 bit mode (Baudot) detection tests - Purpose: To confirm detection of Baudot modulation at various bit rates that may be - encountered. - Preamble: N/A - Method: The tester transmits the 5-bit coded characters "0" to "9" followed by "abcdef" at - (a) 45.45, (b) 47.6, (c) 50 and (d) 100 bits per second. When TUT indicates a - connection, type at least 5 characters back to the tester so that correct selection - of bit rate can be confirmed. - Pass criteria: 1) TUT should select Baudot mode and the appropriate bit rate. - 2) The tester will analyse the bit rate of received characters, which should be at - either 45.45 or 50 bits per second as appropriate. - Comments: 45.45 and 50 bit/s are the commonly used Baudot bit rates. However, certain - textphones can operate at higher rates (e.g. 100 bit/s). Responding at either 45.45 or - 50 bit/s is acceptable to these devices which normally fall back to the selected rate. - 47.6 bit/s may possibly be encountered from another V.18 textphone in the - automode answer state. The TUT may then select either 45.45 or 50 bit/s for the - transmission. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.13 DTMF signal detection - 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 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. - Comments: 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 while - receiving for best possible performance. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.14 EDT rate detection - Purpose: To confirm detection of EDT modems by detecting the transmission rate of received - characters. - Preamble: N/A - Method: The tester transmits EDT characters "abcdef" to TUT at 110 bit/s. When TUT - indicates that the connection is established, type characters "abcdef" back to - the tester. The same characters will then be transmitted back to the TUT. - Pass criteria: Ensure correct reception of characters by tester and TUT. - Comments: The TUT should be able to determine the rate on the six characters given. If it takes - more than this then performance is probably inadequate as too many characters - would be lost. Some characters may be lost during the detection process. However, - the number lost should be minimal. The data bits and parity are specified in - Annex C. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.15 Rate detection test - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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.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.4s from the end of the 980Hz tone. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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.2s followed by 1650Hz for 5s - with no pause. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.20 Immunity to network tones - Purpose: To ensure that the TUT does not interpret network tones as valid signals. - Preamble: N/A - Method: The tester will first send a dial tone to the TUT, this will be followed by a ringing - tone and a network congestion tone. The frequencies and cadences of the tones will - vary according to the country setting. The tester must be configured for the same - country as the TUT. - Pass criteria: The countries supported by the TUT should be noted along with the response to - each tone. The tones should either be ignored or reported as the relevant network - tone to the user. - Comments: V.18 is required to recognize and report RINGING and BUSY tones. Other network - 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. The TUT may - disconnect on reception of tones indicating a failed call attempt. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.21 Immunity to non-textphone modems - Purpose: To ensure that the TUT does not interpret modem tones not supported by V.18 as - valid text telephone tones. - Preamble: N/A - Method: The tester will respond with an ANS tone (2100Hz) followed by simulated (a) - V.32 bis and (b) V.34 modem training sequences. - Pass criteria: The tones should either be ignored or reported back to the user. No textphone - modem should be selected. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.22 Immunity to fax tones - Purpose: To ensure that the TUT will not interpret a called fax machine as being a textphone. - Preamble: N/A - Method: The tester will respond as if it were a typical group 3 fax machine in automatic - answer mode. It should send a CED tone (2100Hz) plus Digital Identification - Signal (DIS) as defined in ITU-T T.30. - Pass criteria: The TUT should ignore the received tones. - Comments: Ideally the TUT should detect the presence of a fax machine and report it back to - the user. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.23 Immunity to voice - Purpose: To ensure that the TUT does not misinterpret speech as a valid textphone signal. - Preamble: N/A - Method: The tester will respond with sampled speech. A number of phrases recorded from - typical male and female speakers will be transmitted. This will include a typical - network announcement. - Pass criteria: The TUT should ignore the speech. - Comments: Ideally the TUT should report the presence of speech back to the user, e.g. via - circuit 135. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.24 ANSam signal detection - Purpose: To verify that TUT correctly detects the ANSam (2100Hz modulated) signal during - the two-second interval (Toff) between transmission of CI sequences. - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.2.25 V.8 calling procedure - Purpose: To verify that TUT correctly performs a V.8 call negotiation. - Preamble: Make a V.18 call from the TUT. Answer with ANSam from the Tester and with JM - for V.21 on the CM. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.1 Ta timer - 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 3s after answering the call. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.3 Early termination of ANSam tone - 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 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+-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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.4 Tt timer - Purpose: To ensure that after detection of ANSam the TUT will return to Monitor A after - 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 3s after ANSam disappears. - Comments: It is assumed that timer Ta is restarted on return to Monitor A. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.5 ANS tone followed by 980Hz - 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.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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.6 ANS tone followed by 1300Hz - 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.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)s of start of 1300Hz. - Comments: The TUT should indicate that V.23 mode has been selected. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.7 ANS tone followed by 1650Hz - 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.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+-100ms of start of 1650Hz. - Comments: The TUT should indicate that V.21 mode has been selected. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.8 980Hz followed by 1650Hz - Purpose: To ensure the correct selection of V.21 modem channel when certain types of - Swedish textphones are encountered. - Preamble: N/A - Method: The tester will simulate a call from a Diatext2 textphone that alternates between - 980Hz and 1650Hz until a connection is made. - 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.56s. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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) 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.10 V.21 detection by timer - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.11 EDT detection by rate - Purpose: To confirm detection of EDT modems by detecting the transmission rate of received - characters. - Preamble: N/A - Method: The tester transmits EDT characters "abcdef" to TUT at 110 bit/s. When TUT - indicates that the connection is established, type characters "abcdef" back to - the tester. The same characters will then be transmitted back to the TUT. - Pass criteria: Ensure correct reception of characters by tester and TUT. - Comments: The TUT should indicate that EDT mode has been selected. Some characters may - be lost during the detection process. However, the number lost should be minimal. - The data bits and parity are specified in Annex C. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.12 V.21 Detection by rate - Purpose: To confirm detection of V.21 modem low channel by detecting the transmission rate - of received characters and to ensure correct discrimination between V.18 and V.21 - modes. - Preamble: N/A - Method: The tester transmits characters "abcdef" to TUT using V.21 (1) at 300 bit/s. When - TUT indicates that the connection is established, type characters "abcdef" - back to the tester. The same characters will then be transmitted back to the TUT. - Pass criteria: Ensure correct reception of characters by tester and TUT. - Comments: This situation is unlikely to occur in practice unless the DCE is sending a V.21 - (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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.13 Tr timer - Purpose: To ensure that the TUT returns to the Monitor A state on expiry of timer Tr - (2s). Timer Tr is started when a modulated V.21 (1) signal is detected. - Preamble: N/A - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.14 Te timer - Purpose: To ensure that the TUT returns to the Monitor A on expiry of timer Te - (2.7s). Timer Te is started when a 980Hz signal is detected. - Preamble: N/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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.15 5 Bit mode (Baudot) detection tests - Purpose: To confirm detection of Baudot modulation at various bit rates that may be - encountered. - Preamble: N/A - Method: The tester transmits the 5-bit coded characters "0" to "9" followed by "abcdef" at - (a) 45.45, (b) 47.6, (c) 50 and (d) 100 bits per second. When TUT indicates a - connection, type at least 5 characters back to the tester so that correct selection of bit - rate can be confirmed. - Pass criteria: 1) The TUT should select Baudot mode and the appropriate bit rate. - 2) The tester will analyse the bit rate of received characters, which should be at an - appropriate rate, and confirm the carrier on/off times before and after the - characters. - Comments: 45.45 and 50 bit/s are the commonly used Baudot bit rates. However, some - textphones can transmit at higher rates, e.g. 100 bit/s. Responding at either 45.45 or - 50 bit/s is acceptable to these devices which then fall back to the selected rate. - A rate of 47.6 bit/s may be encountered from another V.18 textphone in the - automode answer state. The TUT may then select either 45.45 or 50 bit/s for the - transmission. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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) 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.22 1300Hz with XCI test - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.23 Stimulate mode country settings - Purpose: To ensure that the TUT steps through the probes in the specified order for the - country selected. - Preamble: The TUT should be configured for each of the possible probe orders specified in - Appendix I in turn. - 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 use the orders described in Appendix I. - Comments: The order of the probes is not mandatory. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.24 Stimulate carrierless mode probe message - Purpose: To ensure that the TUT sends the correct probe message for each of the carrierless - modes. - Preamble: N/A - 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)s. - Comments: The carrierless modes are those described in Annexes A, B and C. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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 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 20s after the end of the 1270Hz signal. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.26 Stimulate carrier mode probe time - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.27 V.23 mode (390Hz) detection - 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 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 - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - 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 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 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 4s after the end of the 1270Hz - burst. - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.29 Stimulate mode response during probe - Purpose: To ensure that the TUT is able to detect an incoming signal while transmitting a - carrier mode probe. - Preamble: N/A - Method: The tester will step through each possible response as defined in tests ANS-08 to - ANS-23 for each of the carrier mode probes and for each pause after a carrierless - mode probe message. - Pass criteria: The TUT should respond as described in the appropriate test above. - Comments: The TUT may not respond to any signals while a carrierless mode probe is being - sent since these modes are half duplex. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.30 Immunity to network tones - Purpose: To ensure that the TUT does not interpret network tones as valid signals. - Preamble: N/A - Method: The tester will first send a busy tone to the TUT this will be followed by a number - unobtainable tone. The frequencies and cadences of the tones will vary according to - the country setting. The tester must be configured for the same country as the TUT. - Pass criteria: The countries supported by the TUT should be noted along with the response to - each tone. The tones should either be ignored or reported as the relevant network - tone to the user. - Comments: V.18 is required to recognize and report RINGING and BUSY tones. Other network - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.31 Immunity to fax calling tones - 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.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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.32 Immunity to voice - Purpose: To ensure that the TUT does not misinterpret speech as a valid textphone signal. - Preamble: N/A - Method: The tester will respond with sampled speech. A number of phrases recorded from - typical male and female speakers will be transmitted. This will include a typical - network announcement. - Pass criteria: The TUT should ignore the speech. - Comments: Ideally the TUT should report the presence of speech back to the user. This is an - optional test. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.3.33 CM detection and V.8 answering - 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 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. - 2) The TUT should then transmit in V.21 (2) mode. - 3) The JM 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.4.1 Automode monitor Ta timer test - 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.4.2 Automode monitor 1300Hz calling tone discrimination - 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) 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.4.3 Automode monitor 980Hz calling tone discrimination - 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) 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- End of function --------------------------------------------------------*/ - -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[TUT], (const char *) msg); - else - v18_put(v18[TUT], "abcdefghij", 10); -} -/*- End of function --------------------------------------------------------*/ - -static int test_x_01(void) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - const char *ref; - - /* - III.5.4.5.1 Baudot carrier timing and receiver disabling - 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 150ms before the beginning of - the start bit. - 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 300ms after a character. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - v18_put(v18[TESTER], "zabcdefghijklmnopq", -1); - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - ref = "cdefghij"; - printf("Result:\n%s\n", result[TUT]); - printf("Reference result:\n%s\n", ref); - if (unexpected_echo || strcmp(result[TUT], 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.2 Baudot bit rate confirmation - Purpose: To verify that the TUT uses the correct bit rates in the Baudot mode. - Preamble: Establish a call between the tester and TUT in Baudot mode for each of the two - tests. - Method: The operator should select Baudot (a) 45 bit/s followed by (b) 50 bit/s modes and - transmit the string "abcdef" at each rate. - Pass criteria: The tester will measure the bit timings and confirm the rates. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.3 Baudot probe bit rate confirmation - Purpose: To verify that the TUT uses the correct bit rates in the Baudot mode probe during - automoding. - Preamble: Set the user defined carrierless mode probe message to the string "abcdef" if - possible. Set the TUT country setting to "United States". A call should be initiated - from the tester to the TUT. - Method: The tester will wait for the Baudot mode probe and measure the bit rate. - Pass criteria: The tester will measure the bit timings and confirm the rate of 47.6 bit/s. - Comments: The probe message must be long enough for the tester to establish the bit rate. "GA" - may not be sufficient. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 1; -} -/*- 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[TESTER], (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[TUT], (const char *) msg); - /* Echo each received character */ - //v18_put(v18[TUT], msg, len); - } -} -/*- End of function --------------------------------------------------------*/ - -static int test_x_04(void) -{ - char msg[1024]; - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int i; - int j; - - /* - III.5.4.5.4 5 Bit to T.50 character conversion - Purpose: To check that the character conversion tables in Annex A have been correctly - implemented. - Preamble: Establish a call between the tester and TUT in Baudot mode at 45 bit/s. - Method: The tester will send all possible characters preceded by the relevant case shift - command one at a time and wait for a response from the TUT operator. Each - character should be responded to at the TUT by typing the received character or - if the character is not available. - Pass criteria: 1) The tester will verify that each character is correctly echoed back by the TUT. - The operator should verify that each character is correctly displayed on the TUT. - 2) The TUT will send the LTRS symbol before its first character and the - appropriate mode character (either LTRS or FIGS) after every 72 subsequent - characters. - Comments: The tester should indicate which character has been sent in each case. Some of the - characters may not be available from the TUT keyboard and can be ignored. It is - assumed that the character conversion is the same for Baudot at 50 bit/s and any - other supported speed. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - unexpected_echo = false; - for (i = 0; i < 127; i++) - msg[i] = i + 1; - msg[127] = '\0'; - v18_put(v18[TESTER], msg, 127); - - for (i = 0; i < 2000; i++) - { - for (j = 0; j < 2; j++) - { - samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Result:\n%s\n", result[TESTER]); - printf("Result:\n%s\n", result[TUT]); - printf("Reference result:\n%s\n", full_baudot_rx); - if (unexpected_echo || strcmp(result[TUT], full_baudot_rx) != 0) - return -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void x_05_put_text_msg(void *user_data, const uint8_t *msg, int len) -{ - if (user_data == NULL) - { - /* Gather the received characters, which should be like the transmitted characters, - but with the first three characters missing. */ - strcat(result[TESTER], (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[TUT], "behknqtwz", 9); - } -} -/*- End of function --------------------------------------------------------*/ - -static int test_x_05(void) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - const char *ref; - - /* - III.5.4.5.5 DTMF receiver disabling - 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 300ms. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - /* Sending a character should block out the receiver for a while */ - v18_put(v18[TESTER], "z", 1); - - for (i = 0; i < 1000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - ref = "knqtwz"; - printf("Result:\n%s\n", result[TESTER]); - printf("Reference result:\n%s\n", ref); - if (strcmp(result[TESTER], ref) != 0) - return -1; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void x_06_put_text_msg(void *user_data, const uint8_t *msg, int len) -{ - if (user_data == NULL) - ; - else - strcat(result[TUT], (const char *) msg); -} -/*- End of function --------------------------------------------------------*/ - -static int test_x_06(void) -{ - char msg[128]; - const char *ref; - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.6 DTMF character conversion - Purpose: To check that the character conversion tables in Annex B have been correctly - implemented. - Preamble: Establish a call between the tester and TUT in DTMF mode. - Method: The tester will send each character from the set in Annex B, waiting for a response - 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 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[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 127; i++) - msg[i] = i + 1; - msg[127] = '\0'; - v18_put(v18[TESTER], msg, 127); - - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - ref = "\b \n\n\n?\n\n\n !%+().+,-.0123456789:;(=)?" - "XABCDEFGHIJKLMNOPQRSTUVWXYZ\xC6\xD8\xC5" - " abcdefghijklmnopqrstuvwxyz\xE6\xF8\xE5 \b"; - - printf("Result:\n%s\n", result[TESTER]); - printf("Reference result:\n%s\n", ref); - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - if (strcmp(result[TUT], 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.7 EDT carrier timing and receiver disabling - 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 300ms before the beginning of - the start bit. - 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 300ms after a character. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 0; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.8 EDT bit rate and character structure - Purpose: To verify that the TUT uses the correct bit rate and character structure in the EDT - mode. - Preamble: Establish a call between the tester and TUT in EDT mode. - Method: The operator should transmit the string "abcdef" from the TUT. - Pass criteria: 1) The tester should measure the bit timings and confirm that the rate is 110 bit/s. - 2) The tester should confirm that 1 start bit, 7 data bits, 1 even parity bit and 2 stop - bits are used. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 0; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.9 V.23 calling mode character format - Purpose: To verify that the TUT uses the correct character format in the V.23 calling mode. - Preamble: Establish a call from the TUT to the tester in V.23 mode. - Method: The operator should transmit the string "abcdef" from the TUT. The tester will echo - characters back to the TUT as they are received. The tester will then transmit the - string "abcdef" with ODD parity to the TUT. - Pass criteria: 1) Confirm that 1 start bit, 7 data bits, 1 even parity bit and 2 stop bits are - transmitted. - 2) The operator should confirm that there is no local echo at the TUT by checking - that there are no duplicate characters on the TUT display. - 3) The received string should be correctly displayed despite the incorrect parity. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 0; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.10 V.23 answer mode character format - Purpose: To verify that the TUT uses the correct character format in the V.23 answer mode. - Preamble: Establish a call from the tester to the TUT in V.23 mode. - Method: The tester will transmit the string "abcdef" with ODD parity. The TUT should echo - characters back to the tester as they are received. The operator should then transmit - the string "abcdef" from the TUT. - Pass criteria: 1) The received string should be correctly displayed at the TUT despite the - incorrect parity. - 2) Confirm that 1 start bit, 7 data bits, 1 even parity bit and 2 stop bits are - transmitted by the TUT. - 3) The tester should confirm that there is remote echo from TUT. - 4) The operator should confirm that there is local echo on the TUT. - Comments: This test is only applicable to Minitel Dialogue terminals. Prestel and Minitel - Normal terminals cannot operate in this mode. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 0; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.11 V.21 character structure - Purpose: To verify that the TUT uses the character structure in the V.21 mode. - Preamble: Establish a call from the TUT to the tester in V.21 mode. - Method: The operator should transmit a string from the TUT that is long enough to cause the - display to word wrap followed by "abcdef", new line (CR+LF). The tester will then - transmit the string "123456", BACKSPACE (0/8) with ODD parity to the TUT. - Pass criteria: 1) The tester should confirm that 1 start bit, 7 data bits, 1 even parity bit and 1 stop - bits are transmitted. - 2) The word wrap should not result in CR+LF. - 3) The forced new line should be indicated by CR+LF. - 4) The last five characters on the TUT display should be "12345" (no "6") - correctly displayed despite the incorrect parity. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 0; -} -/*- 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) -{ - logging_state_t *logging; - int16_t amp[2][SAMPLES_PER_CHUNK]; - int16_t model_amp[2][SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - int outframes; - int samples; - int push; - int i; - int j; - - /* - III.5.4.5.12 V.18 mode - Purpose: To verify that the TUT uses the protocol defined in ITU-T T.140. - Preamble: Establish a call from the TUT to the tester in V.18 mode. - Method: The operator should transmit a string from the TUT that is long enough to cause the - display to word wrap followed by "abcdef", new line (CR+LF), new line - (UNICODE preferred). The tester will then transmit the string "123456", - BACKSPACE. - Pass criteria: The tester should confirm UTF8 encoded UNICODE characters are used with the - controls specified in ITU-T T.140. - */ - v18[TESTER] = 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[TESTER]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "Tester"); - v18[TUT] = 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[TUT]); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "TUT"); - - if ((model = both_ways_line_model_init(line_model_no, - noise_level, - echo_level_cpe1, - echo_level_co1, - line_model_no, - noise_level, - echo_level_cpe2, - echo_level_co2, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - - result[TESTER][0] = - result[TUT][0] = '\0'; - for (i = 0; i < 10000; i++) - { - for (j = 0; j < 2; j++) - { - if ((samples = v18_tx(v18[j], amp[j], SAMPLES_PER_CHUNK)) == 0) - push = 10; - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(&[j][samples], SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - } - if (log_audio) - { - for (j = 0; j < samples; j++) - { - out_amp[2*j + 0] = amp[0][j]; - out_amp[2*j + 1] = amp[1][j]; - } - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - v18_rx(v18[TESTER], model_amp[1], samples); - v18_rx(v18[TUT], model_amp[0], samples); - } - - v18_free(v18[TESTER]); - v18_free(v18[TUT]); - printf("Test not yet implemented\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void put_v18_msg(void *user_data, const uint8_t *msg, int len) -{ - char buf[1024]; - - memcpy(buf, msg, len); - buf[len] = '\0'; - printf("Received (%d bytes) '%s'\n", len, buf); -} -/*- End of function --------------------------------------------------------*/ - -static int decode_test_data_file(int mode, const char *filename) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - SNDFILE *inhandle; - int len; - v18_state_t *v18_state; - logging_state_t *logging; - - printf("Decoding as '%s'\n", v18_mode_to_str(mode)); - /* We will decode the audio from a file. */ - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - 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, ""); - for (;;) - { - if ((len = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK)) <= 0) - break; - v18_rx(v18_state, amp, len); - } - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - v18_free(v18_state); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -const struct -{ - const char *title; - int (*func)(void); -} test_list[] = -{ - {"III.3.2.1 Operational requirements tests", NULL}, - {"MISC-01 4 (1) No disconnection test", test_misc_01}, - {"MISC-02 4 (2) Automatic resumption of automoding", test_misc_02}, - {"MISC-03 4 (2) Retention of selected mode on loss of signal", test_misc_03}, - {"MISC-04 4 (4) Detection of BUSY tone", test_misc_04}, - {"MISC-05 4 (4) Detection of RINGING", test_misc_05}, - {"MISC-06 4 (4) LOSS OF CARRIER indication", test_misc_06}, - {"MISC-07 4 (4) Call progress indication", test_misc_07}, - {"MISC-08 4 (5) Circuit 135 test", test_misc_08}, - {"MISC-09 4 (6) Connection procedures", test_misc_09}, - - {"III.3.2.2 Automode originate tests", NULL}, - {"ORG-01 5.1.1 CI & XCI signal coding and cadence", test_org_01}, - {"ORG-02 5.1.3 ANS signal detection", test_org_02}, - {"ORG-03 5.2.3.1 End of ANS signal detection", test_org_03}, - {"ORG-04 5.1.3.2 ANS tone followed by TXP", test_org_04}, - {"ORG-05 5.1.3.3 ANS tone followed by 1650Hz", test_org_05}, - {"ORG-06 5.1.3.4 ANS tone followed by 1300Hz", test_org_06}, - {"ORG-07 5.1.3 ANS tone followed by no tone", test_org_07}, - {"ORG-08 5.1.4 Bell 103 (2225Hz signal) detection", test_org_08}, - {"ORG-09 5.1.5 V.21 (1650Hz signal) detection", test_org_09}, - {"ORG-10 5.1.6 V.23 (1300Hz signal) detection", test_org_10}, - {"ORG-11 5.1.7 V.23 (390Hz signal) detection", test_org_11}, - {"ORG-12a to d 5.1.8 5 Bit Mode (baudot) detection Tests", test_org_12}, - {"ORG-13 5.1.9 DTMF signal detection", test_org_13}, - {"ORG-14 5.1.10 EDT rate detection", test_org_14}, - {"ORG-15 5.1.10.1 Rate detection test", test_org_15}, - {"ORG-16 5.1.10.2 980Hz detection", test_org_16}, - {"ORG-17 5.1.10.3 Loss of signal after 980Hz", test_org_17}, - {"ORG-18 5.1.10.3 Tr Timer", test_org_18}, - {"ORG-19 5.1.11 Bell 103 (1270Hz signal) detection", test_org_19}, - {"ORG-20 Immunity to network tones", test_org_20}, - {"ORG-21a to b Immunity to other non-textphone modems", test_org_21}, - {"ORG-22 Immunity to Fax tones", test_org_22}, - {"ORG-23 Immunity to voice", test_org_23}, - {"ORG-24 5.1.2 ANSam detection", test_org_24}, - {"ORG-25 6.1 V.8 originate call", test_org_25}, - - {"III.3.2.3 Automode answer tests", NULL}, - {"ANS-01 5.2.1 Ta timer", test_ans_01}, - {"ANS-02 5.2.2 CI signal detection", test_ans_02}, - {"ANS-03 5.2.2.1 Early termination of ANS tone", test_ans_03}, - {"ANS-04 5.2.2.2 Tt Timer", test_ans_04}, - {"ANS-05 5.2.3.2 ANS tone followed by 980Hz", test_ans_05}, - {"ANS-06 5.2.3.2 ANS tone followed by 1300Hz", test_ans_06}, - {"ANS-07 5.2.3.3 ANS tone followed by 1650Hz", test_ans_07}, - {"ANS-08 5.2.4.1 980Hz followed by 1650Hz", test_ans_08}, - {"ANS-09a to d 5.2.4.2 980Hz calling tone detection", test_ans_09}, - {"ANS-10 5.2.4.3 V.21 detection by timer", test_ans_10}, - {"ANS-11 5.2.4.4.1 EDT detection by rate", test_ans_11}, - {"ANS-12 5.2.4.4.2 V.21 detection by rate", test_ans_12}, - {"ANS-13 5.2.4.4.3 Tr Timer", test_ans_13}, - {"ANS-14 5.2.4.5 Te Timer", test_ans_14}, - {"ANS-15a to d 5.2.5 5 bit mode (Baudot) detection tests", test_ans_15}, - {"ANS-16 5.2.6 DTMF signal detection", test_ans_16}, - {"ANS-17 5.2.7 Bell 103 (1270Hz signal) detection", test_ans_17}, - {"ANS-18 5.2.8 Bell 103 (2225Hz signal) detection", test_ans_18}, - {"ANS-19 5.2.9 V.21 reverse mode (1650Hz) detection", test_ans_19}, - {"ANS-20a to d 5.2.10 1300Hz calling tone discrimination", test_ans_20}, - {"ANS-21 5.2.11 V.23 reverse mode (1300Hz) detection", test_ans_21}, - {"ANS-22 1300Hz with XCI Test", test_ans_22}, - {"ANS-23 5.2.12 Stimulate mode country settings", test_ans_23}, - {"ANS-24 5.2.12.1 Stimulate carrierless mode probe message", test_ans_24}, - {"ANS-25 5.2.12.1.1 Interrupted carrierless mode probe", test_ans_25}, - {"ANS-26 5.2.12.2 Stimulate carrier mode probe time", test_ans_26}, - {"ANS-27 5.2.12.2.1 V.23 mode (390Hz) detection", test_ans_27}, - {"ANS-28 5.2.12.2.2 Interrupted carrier mode probe", test_ans_28}, - {"ANS-29 5.2.12.2.2 Stimulate mode response during probe", test_ans_29}, - {"ANS-30 Immunity to network tones", test_ans_30}, - {"ANS-31 Immunity to Fax calling tones", test_ans_31}, - {"ANS-32 Immunity to voice", test_ans_32}, - {"ANS-33 5.2.2.1 V.8 CM detection and V.8 answering", test_ans_33}, - - {"III.3.2.4 Automode monitor tests", NULL}, - {"MON-01 to -20 5.3 Repeat all answer mode tests excluding tests ANS-01, ANS-20 and ANS-23 to ANS-29", test_mon_01}, - {"MON-21 5.3 Automode monitor Ta timer", test_mon_21}, - {"MON-22a to d 5.3 Automode monitor 1300Hz calling tone discrimination", test_mon_22}, - {"MON-23a to d 5.3 Automode monitor 980Hz calling tone discrimination", test_mon_23}, - - {"III.3.2.5 ITU-T V.18 annexes tests", NULL}, - {"X-01 A.1 Baudot carrier timing and receiver disabling", test_x_01}, - {"X-02 A.2 Baudot bit rate confirmation", test_x_02}, - {"X-03 A.3 Baudot probe bit rate confirmation", test_x_03}, - {"X-04 A.4 5 Bit to T.50 character conversion", test_x_04}, - {"X-05 B.1 DTMF receiver disabling", test_x_05}, - {"X-06 B.2 DTMF character conversion", test_x_06}, - {"X-07 C.1 EDT carrier timing and receiver disabling", test_x_07}, - {"X-08 C.2-3 EDT bit rate and character structure", test_x_08}, - {"X-09 E V.23 calling mode character format", test_x_09}, - {"X-10 E V.23 answer mode character format", test_x_10}, - {"X-11 F.4-5 V.21 character structure", test_x_11}, - {"X-12 G.1-3 V.18 mode", test_x_12}, - - {"", NULL} -}; - -int main(int argc, char *argv[]) -{ - int i; - int res; - bool hit; - const char *match; - int test_standard; - int opt; - - match = NULL; - test_standard = -1; - while ((opt = getopt(argc, argv, "d:ls:")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - case 'l': - log_audio = true; - break; - case 's': - test_standard = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - if (decode_test_file) - { - decode_test_data_file(test_standard, decode_test_file); - exit(0); - } - if (argc > 0) - match = argv[0]; - - outhandle = NULL; - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - } - - hit = false; - for (i = 0; test_list[i].title[0]; i++) - { - if (test_list[i].func - && - (match == NULL - || - (strncmp(match, test_list[i].title, strlen(match)) == 0 - && - test_list[i].title[strlen(match)] == ' '))) - { - hit = true; - printf("%s\n", test_list[i].title); - res = test_list[i].func(); - if (res < 0) - { - printf(" Test failed\n"); - exit(2); - } - if (res == 0) - { - printf(" Test passed\n"); - } - } - else - { - if (match == NULL) - printf("%s\n", test_list[i].title); - } - } - if (!hit) - { - printf("Test not found\n"); - exit(2); - } - 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)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - } - printf("Tests passed\n"); - return 0; - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v22bis_tests.c b/libs/spandsp/tests/v22bis_tests.c deleted file mode 100644 index f3c0532e92..0000000000 --- a/libs/spandsp/tests/v22bis_tests.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v22bis_tests.c - * - * 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 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. - */ - -/*! \page v22bis_tests_page V.22bis modem tests -\section v22bis_tests_page_sec_1 What does it do? -These tests connect two V.22bis modems back to back, through a telephone line -model. BER testing is then used to evaluate performance under various line -conditions. - -If the appropriate GUI environment exists, the tests are built such that a visual -display of modem status is maintained. - -\section v22bis_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "modem_monitor.h" -#endif - -#define BLOCK_LEN 160 - -#define OUT_FILE_NAME "v22bis.wav" - -char *decode_test_file = NULL; -bool use_gui = false; - -int rx_bits = 0; - -both_ways_line_model_state_t *model; - -typedef struct -{ - v22bis_state_t *v22bis; - bert_state_t bert_tx; - bert_state_t bert_rx; - bert_results_t latest_results; -#if defined(ENABLE_GUI) - qam_monitor_t *qam_monitor; -#endif - float smooth_power; - int symbol_no; -} endpoint_t; - -endpoint_t endpoint[2]; - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - endpoint_t *s; - - s = (endpoint_t *) user_data; - switch (reason) - { - case BERT_REPORT_REGULAR: - fprintf(stderr, "V.22bis rx %p BERT report regular - %d bits, %d bad bits, %d resyncs\n", - user_data, - results->total_bits, - results->bad_bits, - results->resyncs); - memcpy(&s->latest_results, results, sizeof(s->latest_results)); - break; - default: - fprintf(stderr, - "V.22bis rx %p BERT report %s\n", - user_data, - bert_event_to_str(reason)); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v22bis_rx_status(void *user_data, int status) -{ - endpoint_t *s; - int bit_rate; - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - - /* Special conditions */ - s = (endpoint_t *) user_data; - printf("V.22bis rx %p status is %s (%d)\n", user_data, signal_status_to_str(status), status); - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - bit_rate = v22bis_get_current_bit_rate(s->v22bis); - printf("Negotiated bit rate: %d\n", bit_rate); - if ((len = v22bis_rx_equalizer_state(s->v22bis, &coeffs))) - { - printf("Equalizer:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V22BIS_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V22BIS_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v22bis_putbit(void *user_data, int bit) -{ - endpoint_t *s; - - if (bit < 0) - { - v22bis_rx_status(user_data, bit); - return; - } - - s = (endpoint_t *) user_data; - if (decode_test_file) - printf("Rx bit %p-%d - %d\n", user_data, rx_bits++, bit); - else - bert_put_bit(&s->bert_rx, bit); -} -/*- End of function --------------------------------------------------------*/ - -static int v22bis_getbit(void *user_data) -{ - endpoint_t *s; - int bit; - - s = (endpoint_t *) user_data; - bit = bert_get_bit(&s->bert_tx); - return bit; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void qam_report(void *user_data, const complexi16_t *constel, const complexi16_t *target, int symbol) -#else -static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol) -#endif -{ - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - complexf_t constel_point; - complexf_t target_point; - float fpower; - endpoint_t *s; - - s = (endpoint_t *) user_data; - if (constel) - { - constel_point.re = constel->re/V22BIS_CONSTELLATION_SCALING_FACTOR; - constel_point.im = constel->im/V22BIS_CONSTELLATION_SCALING_FACTOR; - target_point.re = target->re/V22BIS_CONSTELLATION_SCALING_FACTOR; - target_point.im = target->im/V22BIS_CONSTELLATION_SCALING_FACTOR; -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor_update_constel(s->qam_monitor, &constel_point); - qam_monitor_update_carrier_tracking(s->qam_monitor, v22bis_rx_carrier_frequency(s->v22bis)); - qam_monitor_update_symbol_tracking(s->qam_monitor, v22bis_rx_symbol_timing_correction(s->v22bis)); - } -#endif - fpower = (constel->re - target->re)*(constel->re - target->re) - + (constel->im - target->im)*(constel->im - target->im); - s->smooth_power = 0.95f*s->smooth_power + 0.05f*fpower; - - printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %8.4f\n", - s->symbol_no, - constel_point.re, - constel_point.im, - target_point.re, - target_point.im, - symbol, - fpower, - s->smooth_power, - v22bis_rx_signal_power(s->v22bis)); - s->symbol_no++; - } - else - { - printf("Gardner step %d\n", symbol); - if ((len = v22bis_rx_equalizer_state(s->v22bis, &coeffs))) - { - printf("Equalizer A:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V22BIS_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V22BIS_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif -#if defined(ENABLE_GUI) - if (use_gui) - { -#if defined(SPANDSP_USE_FIXED_POINT) - qam_monitor_update_int_equalizer(s->qam_monitor, coeffs, len); -#else - qam_monitor_update_equalizer(s->qam_monitor, coeffs, len); -#endif - } -#endif - } - } -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int16_t amp[2][BLOCK_LEN]; - int16_t model_amp[2][BLOCK_LEN]; - int16_t out_amp[2*BLOCK_LEN]; - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int samples; - int samples2; - int i; - int j; - int test_bps; - int line_model_no; - int channel_codec; - int rbs_pattern; - int bits_per_test; - int noise_level; - int signal_level; - int guard_tone_option; - int opt; - bool log_audio; - - channel_codec = MUNGE_CODEC_NONE; - rbs_pattern = 0; - test_bps = 2400; - line_model_no = 0; - decode_test_file = NULL; - noise_level = -70; - signal_level = -13; - bits_per_test = 50000; - guard_tone_option = V22BIS_GUARD_TONE_1800HZ; - log_audio = false; - while ((opt = getopt(argc, argv, "b:B:c:d:gG:lm:n:r:s:")) != -1) - { - switch (opt) - { - case 'b': - test_bps = atoi(optarg); - if (test_bps != 2400 && test_bps != 1200) - { - fprintf(stderr, "Invalid bit rate specified\n"); - exit(2); - } - break; - case 'B': - bits_per_test = atoi(optarg); - break; - case 'c': - channel_codec = atoi(optarg); - break; - case 'd': - decode_test_file = optarg; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'G': - guard_tone_option = atoi(optarg); - break; - case 'l': - log_audio = true; - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'n': - noise_level = atoi(optarg); - break; - case 'r': - rbs_pattern = atoi(optarg); - break; - case 's': - signal_level = atoi(optarg); - break; - default: - //usage(); - exit(2); - break; - } - } - inhandle = NULL; - if (decode_test_file) - { - /* We will decode the audio from a file. */ - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - } - - outhandle = NULL; - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - memset(endpoint, 0, sizeof(endpoint)); - - for (i = 0; i < 2; i++) - { - endpoint[i].v22bis = v22bis_init(NULL, test_bps, guard_tone_option, (i == 0), v22bis_getbit, &endpoint[i], v22bis_putbit, &endpoint[i]); - v22bis_tx_power(endpoint[i].v22bis, signal_level); - /* Move the carrier off a bit */ - endpoint[i].v22bis->tx.carrier_phase_rate = dds_phase_ratef((i == 0) ? 1207.0f : 2407.0f); - v22bis_rx_set_qam_report_handler(endpoint[i].v22bis, qam_report, (void *) &endpoint[i]); - span_log_set_level(&endpoint[i].v22bis->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(&endpoint[i].v22bis->logging, (i == 0) ? "caller" : "answerer"); - endpoint[i].smooth_power = 0.0f; - endpoint[i].symbol_no = 0; - bert_init(&endpoint[i].bert_tx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_init(&endpoint[i].bert_rx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&endpoint[i].bert_rx, 10000, reporter, &endpoint[i]); - } - -#if defined(ENABLE_GUI) - if (use_gui) - { - endpoint[0].qam_monitor = qam_monitor_init(6.0f, V22BIS_CONSTELLATION_SCALING_FACTOR, "Calling modem"); - endpoint[1].qam_monitor = qam_monitor_init(6.0f, V22BIS_CONSTELLATION_SCALING_FACTOR, "Answering modem"); - } -#endif - if ((model = both_ways_line_model_init(line_model_no, - (float) noise_level, - -15.0f, - -15.0f, - line_model_no, - (float) noise_level, - -15.0f, - -15.0f, - channel_codec, - rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - samples = 0; - for (;;) - { - for (i = 0; i < 2; i++) - { - samples = v22bis_tx(endpoint[i].v22bis, amp[i], BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(endpoint[i].qam_monitor, amp[i], samples); -#endif - if (samples == 0) - { - /* Note that we might get a few bad bits as the carrier shuts down. */ - bert_result(&endpoint[i].bert_rx, &endpoint[i].latest_results); - - bert_init(&endpoint[i].bert_tx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_init(&endpoint[i].bert_rx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&endpoint[i].bert_rx, 10000, reporter, &endpoint[i]); - - printf("Restarting on zero output\n"); - v22bis_restart(endpoint[i].v22bis, test_bps); - } - } - -#if 1 - both_ways_line_model(model, - model_amp[0], - amp[0], - model_amp[1], - amp[1], - samples); -#else - vec_copyi16(model_amp[0], amp[0], samples); - vec_copyi16(model_amp[1], amp[1], samples); -#endif - if (decode_test_file) - { - samples2 = sf_readf_short(inhandle, model_amp[0], samples); - if (samples2 != samples) - break; - } - for (i = 0; i < 2; i++) - { - span_log_bump_samples(&endpoint[i].v22bis->logging, samples); - v22bis_rx(endpoint[i ^ 1].v22bis, model_amp[i], samples); - for (j = 0; j < samples; j++) - out_amp[2*j + i] = model_amp[i][j]; - for ( ; j < BLOCK_LEN; j++) - out_amp[2*j + i] = 0; - } - - if (log_audio) - { - outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN); - if (outframes != BLOCK_LEN) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - } - both_ways_line_model_free(model); -#if defined(ENABLE_GUI) - if (use_gui) - qam_wait_to_end(endpoint[0].qam_monitor); -#endif - if (decode_test_file) - { - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v27ter_tests.c b/libs/spandsp/tests/v27ter_tests.c deleted file mode 100644 index edac945aa3..0000000000 --- a/libs/spandsp/tests/v27ter_tests.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v27ter_tests.c - * - * 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 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. - */ - -/*! \page v27ter_tests_page V.27ter modem tests -\section v27ter_tests_page_sec_1 What does it do? -These tests test one way paths, as V.27ter is a half-duplex modem. They allow either: - - - A V.27ter transmit modem to feed a V.27ter receive modem through a telephone line - model. BER testing is then used to evaluate performance under various line - conditions. This is effective for testing the basic performance of the - receive modem. It is also the only test mode provided for evaluating the - transmit modem. - - - A V.27ter receive modem is used to decode V.27ter audio, stored in an audio file. - This is good way to evaluate performance with audio recorded from other - models of modem, and with real world problematic telephone lines. - -If the appropriate GUI environment exists, the tests are built such that a visual -display of modem status is maintained. - -\section v27ter_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_FENV_H) -#define __USE_GNU -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "modem_monitor.h" -#include "line_model_monitor.h" -#endif - -#define BLOCK_LEN 160 - -#define OUT_FILE_NAME "v27ter.wav" - -char *decode_test_file = NULL; -bool use_gui = false; - -int symbol_no = 0; - -int rx_bits = 0; - -bert_state_t bert; -one_way_line_model_state_t *line_model; - -#if defined(ENABLE_GUI) -qam_monitor_t *qam_monitor; -#endif - -bert_results_t latest_results; - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - switch (reason) - { - case BERT_REPORT_REGULAR: - fprintf(stderr, "BERT report regular - %d bits, %d bad bits, %d resyncs\n", results->total_bits, results->bad_bits, results->resyncs); - memcpy(&latest_results, results, sizeof(latest_results)); - break; - default: - fprintf(stderr, "BERT report %s\n", bert_event_to_str(reason)); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v27ter_rx_status(void *user_data, int status) -{ - v27ter_rx_state_t *s; - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - - printf("V.27ter rx status is %s (%d)\n", signal_status_to_str(status), status); - s = (v27ter_rx_state_t *) user_data; - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - if ((len = v27ter_rx_equalizer_state(s, &coeffs))) - { - printf("Equalizer:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V27TER_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V27TER_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v27terputbit(void *user_data, int bit) -{ - if (bit < 0) - { - v27ter_rx_status(user_data, bit); - return; - } - - if (decode_test_file) - printf("Rx bit %d - %d\n", rx_bits++, bit); - else - bert_put_bit(&bert, bit); -} -/*- End of function --------------------------------------------------------*/ - -static void v27ter_tx_status(void *user_data, int status) -{ - printf("V.27ter tx status is %s (%d)\n", signal_status_to_str(status), status); -} -/*- End of function --------------------------------------------------------*/ - -static int v27tergetbit(void *user_data) -{ - return bert_get_bit(&bert); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void qam_report(void *user_data, const complexi16_t *constel, const complexi16_t *target, int symbol) -#else -static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol) -#endif -{ - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - complexf_t constel_point; - complexf_t target_point; - float fpower; - float error; - v27ter_rx_state_t *rx; - static float smooth_power = 0.0f; - static int update_interval = 100; - - rx = (v27ter_rx_state_t *) user_data; - if (constel) - { - constel_point.re = constel->re/V27TER_CONSTELLATION_SCALING_FACTOR; - constel_point.im = constel->im/V27TER_CONSTELLATION_SCALING_FACTOR; - target_point.re = target->re/V27TER_CONSTELLATION_SCALING_FACTOR; - target_point.im = target->im/V27TER_CONSTELLATION_SCALING_FACTOR; - fpower = (constel_point.re - target_point.re)*(constel_point.re - target_point.re) - + (constel_point.im - target_point.im)*(constel_point.im - target_point.im); - smooth_power = 0.95f*smooth_power + 0.05f*fpower; -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor_update_constel(qam_monitor, &constel_point); - qam_monitor_update_carrier_tracking(qam_monitor, v27ter_rx_carrier_frequency(rx)); - qam_monitor_update_symbol_tracking(qam_monitor, v27ter_rx_symbol_timing_correction(rx)); - } -#endif - error = constel->im*target->re - constel->re*target->im; - printf("Tracking error %f %f %f %f %f %f\n", error, v27ter_rx_carrier_frequency(rx), constel_point.re, constel_point.im, target_point.re, target_point.im); - printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %9.4f %7.3f %7.4f\n", - symbol_no, - constel_point.re, - constel_point.im, - target_point.re, - target_point.im, - symbol, - fpower, - smooth_power, - v27ter_rx_carrier_frequency(rx), - v27ter_rx_signal_power(rx), - v27ter_rx_symbol_timing_correction(rx)); - symbol_no++; - if (--update_interval <= 0) - { - if ((len = v27ter_rx_equalizer_state(rx, &coeffs))) - { - printf("Equalizer B:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V27TER_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V27TER_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif -#if defined(ENABLE_GUI) - if (use_gui) - { -#if defined(SPANDSP_USE_FIXED_POINT) - qam_monitor_update_int_equalizer(qam_monitor, coeffs, len); -#else - qam_monitor_update_equalizer(qam_monitor, coeffs, len); -#endif - } -#endif - } - update_interval = 100; - } - } - else - { - printf("Gardner step %d\n", symbol); - if ((len = v27ter_rx_equalizer_state(rx, &coeffs))) - { - printf("Equalizer A:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V27TER_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V27TER_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif -#if defined(ENABLE_GUI) - if (use_gui) - { -#if defined(SPANDSP_USE_FIXED_POINT) - qam_monitor_update_int_equalizer(qam_monitor, coeffs, len); -#else - qam_monitor_update_equalizer(qam_monitor, coeffs, len); -#endif - } -#endif - } - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_FENV_H) -static void sigfpe_handler(int sig_num, siginfo_t *info, void *data) -{ - switch (sig_num) - { - case SIGFPE: - switch (info->si_code) - { - case FPE_INTDIV: - fprintf(stderr, "integer divide by zero at %p\n", info->si_addr); - break; - case FPE_INTOVF: - fprintf(stderr, "integer overflow at %p\n", info->si_addr); - break; - case FPE_FLTDIV: - fprintf(stderr, "FP divide by zero at %p\n", info->si_addr); - break; - case FPE_FLTOVF: - fprintf(stderr, "FP overflow at %p\n", info->si_addr); - break; - case FPE_FLTUND: - fprintf(stderr, "FP underflow at %p\n", info->si_addr); - break; - case FPE_FLTRES: - fprintf(stderr, "FP inexact result at %p\n", info->si_addr); - break; - case FPE_FLTINV: - fprintf(stderr, "FP invalid operation at %p\n", info->si_addr); - break; - case FPE_FLTSUB: - fprintf(stderr, "subscript out of range at %p\n", info->si_addr); - break; - } - break; - default: - fprintf(stderr, "Unexpected signal %d\n", sig_num); - break; - } - exit(2); -} -/*- End of function --------------------------------------------------------*/ - -static void fpe_trap_setup(void) -{ - struct sigaction trap; - - sigemptyset(&trap.sa_mask); - trap.sa_flags = SA_SIGINFO; - trap.sa_sigaction = sigfpe_handler; - - sigaction(SIGFPE, &trap, NULL); - //feenableexcept(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); - //feenableexcept(FE_ALL_EXCEPT); - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -} -/*- End of function --------------------------------------------------------*/ -#endif - -int main(int argc, char *argv[]) -{ - v27ter_rx_state_t *rx; - v27ter_tx_state_t *tx; - bert_results_t bert_results; - int16_t gen_amp[BLOCK_LEN]; - int16_t amp[BLOCK_LEN]; - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int samples; - int test_bps; - int noise_level; - int signal_level; - int bits_per_test; - int line_model_no; - int block_no; - 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; - line_model_no = 0; - decode_test_file = NULL; - use_gui = false; - noise_level = -70; - signal_level = -13; - bits_per_test = 50000; - log_audio = false; - while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:r:s:t")) != -1) - { - switch (opt) - { - case 'b': - test_bps = atoi(optarg); - if (test_bps != 4800 && test_bps != 2400) - { - fprintf(stderr, "Invalid bit rate specified\n"); - exit(2); - } - break; - case 'B': - bits_per_test = atoi(optarg); - break; - case 'c': - channel_codec = atoi(optarg); - break; - case 'd': - decode_test_file = optarg; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'n': - noise_level = atoi(optarg); - break; - case 'r': - rbs_pattern = atoi(optarg); - break; - case 's': - signal_level = atoi(optarg); - break; - case 't': - tep = true; - break; - default: - //usage(); - exit(2); - break; - } - } - inhandle = NULL; - outhandle = NULL; - -#if defined(HAVE_FENV_H) - fpe_trap_setup(); -#endif - - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - - if (decode_test_file) - { - /* We will decode the audio from a file. */ - tx = NULL; - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - } - else - { - /* We will generate V.27ter audio, and add some noise to it. */ - tx = v27ter_tx_init(NULL, test_bps, tep, v27tergetbit, NULL); - logging = v27ter_tx_get_logging_state(tx); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "V.27ter-tx"); - v27ter_tx_power(tx, signal_level); - v27ter_tx_set_modem_status_handler(tx, v27ter_tx_status, (void *) tx); - /* Move the carrier off a bit */ -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - tx->carrier_phase_rate = dds_phase_ratef(1810.0f); -#endif - bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&bert, 10000, reporter, NULL); - - if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - } - - rx = v27ter_rx_init(NULL, test_bps, v27terputbit, NULL); - logging = v27ter_rx_get_logging_state(rx); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "V.27ter-rx"); - v27ter_rx_set_modem_status_handler(rx, v27ter_rx_status, (void *) rx); - v27ter_rx_set_qam_report_handler(rx, qam_report, (void *) rx); - -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor = qam_monitor_init(2.0f, V27TER_CONSTELLATION_SCALING_FACTOR, NULL); - if (!decode_test_file) - { - start_line_model_monitor(129); - line_model_monitor_line_model_update(line_model->near_filter, line_model->near_filter_len); - } - } -#endif - - memset(&latest_results, 0, sizeof(latest_results)); - for (block_no = 0; ; block_no++) - { - if (decode_test_file) - { - samples = sf_readf_short(inhandle, amp, BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(qam_monitor, amp, samples); -#endif - if (samples == 0) - break; - } - else - { - samples = v27ter_tx(tx, gen_amp, BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(qam_monitor, gen_amp, samples); -#endif - if (samples == 0) - { - printf("Restarting on zero output\n"); - - /* Push a little silence through, to ensure all the data bits get out of the buffers */ - vec_zeroi16(amp, BLOCK_LEN); - v27ter_rx(rx, amp, BLOCK_LEN); - v27ter_rx(rx, amp, BLOCK_LEN); - v27ter_rx(rx, amp, BLOCK_LEN); - - /* Note that we might get a few bad bits as the carrier shuts down. */ - bert_result(&bert, &bert_results); - fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - /* See if bit errors are appearing yet. Also check we are getting enough bits out of the receiver. The last regular report - should be error free, though the final report will generally contain bits errors as the carrier was dying. The total - number of bits out of the receiver should be at least the number we sent. Also, since BERT sync should have occurred - rapidly at the start of transmission, the last report should have occurred at not much less than the total number of - bits we sent. */ - if (bert_results.total_bits < bits_per_test - || - latest_results.total_bits < bits_per_test - 100 - || - latest_results.bad_bits != 0) - { - break; - } - memset(&latest_results, 0, sizeof(latest_results)); - signal_level--; - v27ter_tx_restart(tx, test_bps, tep); - v27ter_tx_power(tx, signal_level); - 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_free(line_model); - if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, 0)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - } - - if (log_audio) - { - outframes = sf_writef_short(outhandle, gen_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - one_way_line_model(line_model, amp, gen_amp, samples); - } -#if defined(ENABLE_GUI) - if (use_gui && !decode_test_file) - line_model_monitor_line_spectrum_update(amp, samples); -#endif - v27ter_rx(rx, amp, samples); - } - if (!decode_test_file) - { - bert_result(&bert, &bert_results); - fprintf(stderr, "At completion:\n"); - fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - one_way_line_model_free(line_model); - - if (signal_level > -43) - { - printf("Tests failed.\n"); - exit(2); - } - - printf("Tests passed.\n"); - } - v27ter_rx_free(rx); - if (tx) - v27ter_tx_free(tx); - bert_release(&bert); -#if defined(ENABLE_GUI) - if (use_gui) - qam_wait_to_end(qam_monitor); -#endif - if (decode_test_file) - { - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v27ter_tests.sh b/libs/spandsp/tests/v27ter_tests.sh deleted file mode 100755 index 9e5d99d9b3..0000000000 --- a/libs/spandsp/tests/v27ter_tests.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -STDOUT_DEST=xyzzy -STDERR_DEST=xyzzy2 - -for OPTS in "-g -b 4800 -s -42 -n -57" "-g -b 2400 -s -42 -n -51" -do - ./v27ter_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo v27ter_tests ${OPTS} failed! - exit $RETVAL - fi -done -echo v27ter_tests completed OK diff --git a/libs/spandsp/tests/v29_tests.c b/libs/spandsp/tests/v29_tests.c deleted file mode 100644 index 946170cb5d..0000000000 --- a/libs/spandsp/tests/v29_tests.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v29_tests.c - * - * 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 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. - */ - -/*! \page v29_tests_page V.29 modem tests -\section v29_tests_page_sec_1 What does it do? -These tests test one way paths, as V.29 is a half-duplex modem. They allow either: - - - A V.29 transmit modem to feed a V.29 receive modem through a telephone line - model. BER testing is then used to evaluate performance under various line - conditions. This is effective for testing the basic performance of the - receive modem. It is also the only test mode provided for evaluating the - transmit modem. - - - A V.29 receive modem is used to decode V.29 audio, stored in an audio file. - This is good way to evaluate performance with audio recorded from other - models of modem, and with real world problematic telephone lines. - -If the appropriate GUI environment exists, the tests are built such that a visual -display of modem status is maintained. - -\section v29_tests_page_sec_2 How is it used? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) -#define ENABLE_GUI -#endif - -#include -#include -#include -#include -#include -#include -#include -#if defined(HAVE_FENV_H) -#define __USE_GNU -#include -#endif - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" -#include "spandsp-sim.h" - -#if defined(ENABLE_GUI) -#include "modem_monitor.h" -#include "line_model_monitor.h" -#endif - -#define BLOCK_LEN 160 - -#define OUT_FILE_NAME "v29.wav" - -char *decode_test_file = NULL; -bool use_gui = false; - -int symbol_no = 0; -int rx_bits = 0; - -bert_state_t bert; -one_way_line_model_state_t *line_model; - -#if defined(ENABLE_GUI) -qam_monitor_t *qam_monitor; -#endif - -bert_results_t latest_results; - -static void reporter(void *user_data, int reason, bert_results_t *results) -{ - switch (reason) - { - case BERT_REPORT_REGULAR: - fprintf(stderr, "BERT report regular - %d bits, %d bad bits, %d resyncs\n", results->total_bits, results->bad_bits, results->resyncs); - memcpy(&latest_results, results, sizeof(latest_results)); - break; - default: - fprintf(stderr, "BERT report %s\n", bert_event_to_str(reason)); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v29_rx_status(void *user_data, int status) -{ - v29_rx_state_t *s; - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - - printf("V.29 rx status is %s (%d)\n", signal_status_to_str(status), status); - s = (v29_rx_state_t *) user_data; - switch (status) - { - case SIG_STATUS_TRAINING_SUCCEEDED: - printf("Training succeeded\n"); - if ((len = v29_rx_equalizer_state(s, &coeffs))) - { - printf("Equalizer:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V29_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V29_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif - } - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void v29putbit(void *user_data, int bit) -{ - if (bit < 0) - { - v29_rx_status(user_data, bit); - return; - } - - if (decode_test_file) - printf("Rx bit %d - %d\n", rx_bits++, bit); - else - bert_put_bit(&bert, bit); -} -/*- End of function --------------------------------------------------------*/ - -static void v29_tx_status(void *user_data, int status) -{ - printf("V.29 tx status is %s (%d)\n", signal_status_to_str(status), status); -} -/*- End of function --------------------------------------------------------*/ - -static int v29getbit(void *user_data) -{ - return bert_get_bit(&bert); -} -/*- End of function --------------------------------------------------------*/ - -#if defined(SPANDSP_USE_FIXED_POINT) -static void qam_report(void *user_data, const complexi16_t *constel, const complexi16_t *target, int symbol) -#else -static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol) -#endif -{ - int i; - int len; -#if defined(SPANDSP_USE_FIXED_POINT) - complexi16_t *coeffs; -#else - complexf_t *coeffs; -#endif - complexf_t constel_point; - complexf_t target_point; - float fpower; - v29_rx_state_t *rx; - static float smooth_power = 0.0f; - static int update_interval = 100; - - rx = (v29_rx_state_t *) user_data; - if (constel) - { - constel_point.re = constel->re/V29_CONSTELLATION_SCALING_FACTOR; - constel_point.im = constel->im/V29_CONSTELLATION_SCALING_FACTOR; - target_point.re = target->re/V29_CONSTELLATION_SCALING_FACTOR, - target_point.im = target->im/V29_CONSTELLATION_SCALING_FACTOR, - fpower = (constel_point.re - target_point.re)*(constel_point.re - target_point.re) - + (constel_point.im - target_point.im)*(constel_point.im - target_point.im); - smooth_power = 0.95f*smooth_power + 0.05f*fpower; -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor_update_constel(qam_monitor, &constel_point); - qam_monitor_update_carrier_tracking(qam_monitor, v29_rx_carrier_frequency(rx)); - //qam_monitor_update_carrier_tracking(qam_monitor, (fpower) ? fpower : 0.001f); - qam_monitor_update_symbol_tracking(qam_monitor, v29_rx_symbol_timing_correction(rx)); - } -#endif - printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %9.4f %7.3f %7.4f\n", - symbol_no, - constel_point.re, - constel_point.im, - target_point.re, - target_point.im, - symbol, - fpower, - smooth_power, - v29_rx_carrier_frequency(rx), - v29_rx_signal_power(rx), - v29_rx_symbol_timing_correction(rx)); - symbol_no++; - if (--update_interval <= 0) - { - if ((len = v29_rx_equalizer_state(rx, &coeffs))) - { - printf("Equalizer A:\n"); - for (i = 0; i < len; i++) -#if defined(SPANDSP_USE_FIXED_POINT) - printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V29_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V29_CONSTELLATION_SCALING_FACTOR); -#else - printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); -#endif -#if defined(ENABLE_GUI) - if (use_gui) - { -#if defined(SPANDSP_USE_FIXED_POINT) - qam_monitor_update_int_equalizer(qam_monitor, coeffs, len); -#else - qam_monitor_update_equalizer(qam_monitor, coeffs, len); -#endif - } -#endif - } - update_interval = 100; - } - } -} -/*- End of function --------------------------------------------------------*/ - -#if defined(HAVE_FENV_H) -static void sigfpe_handler(int sig_num, siginfo_t *info, void *data) -{ - switch (sig_num) - { - case SIGFPE: - switch (info->si_code) - { - case FPE_INTDIV: - fprintf(stderr, "integer divide by zero at %p\n", info->si_addr); - break; - case FPE_INTOVF: - fprintf(stderr, "integer overflow at %p\n", info->si_addr); - break; - case FPE_FLTDIV: - fprintf(stderr, "FP divide by zero at %p\n", info->si_addr); - break; - case FPE_FLTOVF: - fprintf(stderr, "FP overflow at %p\n", info->si_addr); - break; - case FPE_FLTUND: - fprintf(stderr, "FP underflow at %p\n", info->si_addr); - break; - case FPE_FLTRES: - fprintf(stderr, "FP inexact result at %p\n", info->si_addr); - break; - case FPE_FLTINV: - fprintf(stderr, "FP invalid operation at %p\n", info->si_addr); - break; - case FPE_FLTSUB: - fprintf(stderr, "subscript out of range at %p\n", info->si_addr); - break; - } - break; - default: - fprintf(stderr, "Unexpected signal %d\n", sig_num); - break; - } - exit(2); -} -/*- End of function --------------------------------------------------------*/ - -static void fpe_trap_setup(void) -{ - struct sigaction trap; - - sigemptyset(&trap.sa_mask); - trap.sa_flags = SA_SIGINFO; - trap.sa_sigaction = sigfpe_handler; - - sigaction(SIGFPE, &trap, NULL); - //feenableexcept(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW); - //feenableexcept(FE_ALL_EXCEPT); - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -} -/*- End of function --------------------------------------------------------*/ -#endif - -int main(int argc, char *argv[]) -{ - v29_rx_state_t *rx; - v29_tx_state_t *tx; - bert_results_t bert_results; - int16_t gen_amp[BLOCK_LEN]; - int16_t amp[BLOCK_LEN]; - SNDFILE *inhandle; - SNDFILE *outhandle; - int outframes; - int samples; - int test_bps; - int noise_level; - int signal_level; - int bits_per_test; - int line_model_no; - int block_no; - 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; - line_model_no = 0; - decode_test_file = NULL; - use_gui = false; - noise_level = -70; - signal_level = -13; - bits_per_test = 50000; - log_audio = false; - while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:r:s:t")) != -1) - { - switch (opt) - { - case 'b': - test_bps = atoi(optarg); - if (test_bps != 9600 && test_bps != 7200 && test_bps != 4800) - { - fprintf(stderr, "Invalid bit rate specified\n"); - exit(2); - } - break; - case 'B': - bits_per_test = atoi(optarg); - break; - case 'c': - channel_codec = atoi(optarg); - break; - case 'd': - decode_test_file = optarg; - break; - case 'g': -#if defined(ENABLE_GUI) - use_gui = true; -#else - fprintf(stderr, "Graphical monitoring not available\n"); - exit(2); -#endif - break; - case 'l': - log_audio = true; - break; - case 'm': - line_model_no = atoi(optarg); - break; - case 'n': - noise_level = atoi(optarg); - break; - case 'r': - rbs_pattern = atoi(optarg); - break; - case 's': - signal_level = atoi(optarg); - break; - case 't': - tep = true; - break; - default: - //usage(); - exit(2); - break; - } - } - inhandle = NULL; - outhandle = NULL; - -#if defined(HAVE_FENV_H) - fpe_trap_setup(); -#endif - - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - - if (decode_test_file) - { - /* We will decode the audio from a file. */ - tx = NULL; - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); - exit(2); - } - } - else - { - /* We will generate V.29 audio, and add some noise to it. */ - tx = v29_tx_init(NULL, test_bps, tep, v29getbit, NULL); - logging = v29_tx_get_logging_state(tx); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "V.29-tx"); - v29_tx_power(tx, signal_level); - v29_tx_set_modem_status_handler(tx, v29_tx_status, (void *) tx); -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - /* Move the carrier off a bit */ - tx->carrier_phase_rate = dds_phase_ratef(1710.0f); - tx->carrier_phase = 0; -#endif - - bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); - bert_set_report(&bert, 10000, reporter, NULL); - - if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, rbs_pattern)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - } - - rx = v29_rx_init(NULL, test_bps, v29putbit, NULL); - logging = v29_rx_get_logging_state(rx); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "V.29-rx"); - v29_rx_signal_cutoff(rx, -45.5f); - v29_rx_set_modem_status_handler(rx, v29_rx_status, (void *) rx); - v29_rx_set_qam_report_handler(rx, qam_report, (void *) rx); -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - /* Rotate the starting phase */ - rx->carrier_phase = 0x80000000; -#endif - -#if defined(ENABLE_GUI) - if (use_gui) - { - qam_monitor = qam_monitor_init(6.0f, V29_CONSTELLATION_SCALING_FACTOR, NULL); - if (!decode_test_file) - { - start_line_model_monitor(129); - line_model_monitor_line_model_update(line_model->near_filter, line_model->near_filter_len); - } - } -#endif - - memset(&latest_results, 0, sizeof(latest_results)); - for (block_no = 0; ; block_no++) - { - if (decode_test_file) - { - samples = sf_readf_short(inhandle, amp, BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(qam_monitor, amp, samples); -#endif - if (samples == 0) - break; - } - else - { - samples = v29_tx(tx, gen_amp, BLOCK_LEN); -#if defined(ENABLE_GUI) - if (use_gui) - qam_monitor_update_audio_level(qam_monitor, gen_amp, samples); -#endif - if (samples == 0) - { - /* Push a little silence through, to ensure all the data bits get out of the buffers */ - vec_zeroi16(amp, BLOCK_LEN); - v29_rx(rx, amp, BLOCK_LEN); - - /* Note that we might get a few bad bits as the carrier shuts down. */ - bert_result(&bert, &bert_results); - fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - /* See if bit errors are appearing yet. Also check we are getting enough bits out of the receiver. The last regular report - should be error free, though the final report will generally contain bits errors as the carrier was dying. The total - number of bits out of the receiver should be at least the number we sent. Also, since BERT sync should have occurred - rapidly at the start of transmission, the last report should have occurred at not much less than the total number of - bits we sent. */ - if (bert_results.total_bits < bits_per_test - || - latest_results.total_bits < bits_per_test - 100 - || - latest_results.bad_bits != 0) - { - break; - } - memset(&latest_results, 0, sizeof(latest_results)); - signal_level--; - v29_tx_restart(tx, test_bps, tep); - v29_tx_power(tx, signal_level); - v29_rx_restart(rx, test_bps, false); -#if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) - rx->eq_put_step = rand()%(48*10/3); -#endif - 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_free(line_model); - if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, 0)) == NULL) - { - fprintf(stderr, " Failed to create line model\n"); - exit(2); - } - } - if (log_audio) - { - outframes = sf_writef_short(outhandle, gen_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - } - one_way_line_model(line_model, amp, gen_amp, samples); - } -#if defined(ENABLE_GUI) - if (use_gui && !decode_test_file) - line_model_monitor_line_spectrum_update(amp, samples); -#endif - v29_rx(rx, amp, samples); - } - if (!decode_test_file) - { - bert_result(&bert, &bert_results); - fprintf(stderr, "At completion:\n"); - fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); - fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - one_way_line_model_free(line_model); - - if (signal_level > -43) - { - printf("Tests failed.\n"); - exit(2); - } - - printf("Tests passed.\n"); - } - v29_rx_free(rx); - if (tx) - v29_tx_free(tx); - bert_release(&bert); -#if defined(ENABLE_GUI) - if (use_gui) - qam_wait_to_end(qam_monitor); -#endif - if (decode_test_file) - { - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); - exit(2); - } - } - if (log_audio) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v29_tests.sh b/libs/spandsp/tests/v29_tests.sh deleted file mode 100755 index 5c98d00619..0000000000 --- a/libs/spandsp/tests/v29_tests.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -STDOUT_DEST=xyzzy -STDERR_DEST=xyzzy2 - -for OPTS in "-g -b 9600 -s -42 -n -62" "-g -b 7200 -s -42 -n -59" "-g -b 4800 -s -42 -n -54" -do - ./v29_tests ${OPTS} >$STDOUT_DEST 2>$STDERR_DEST - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo v29_tests ${OPTS} failed! - exit $RETVAL - fi -done -echo v29_tests completed OK diff --git a/libs/spandsp/tests/v42_tests.c b/libs/spandsp/tests/v42_tests.c deleted file mode 100644 index 727b5a8b58..0000000000 --- a/libs/spandsp/tests/v42_tests.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2004, 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 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. - */ - -/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */ - -/*! \page v42_tests_page V.42 tests -\section v42_tests_page_sec_1 What does it do? -These tests connect two instances of V.42 back to back. V.42 frames are -then exchanged between them. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES - -#include "spandsp.h" - -v42_state_t callerx; -v42_state_t answererx; -v42_state_t *caller; -v42_state_t *answerer; -int variable_length; - -int rx_next[3] = {0}; -int tx_next[3] = {0}; - -static void v42_status(void *user_data, int status) -{ - v42_state_t *s; - - s = (v42_state_t *) user_data; - if (status < 0) - printf("%p: Status is '%s' (%d)\n", s, signal_status_to_str(status), status); - else - printf("%p: Status is '%s' (%d)\n", s, lapm_status_to_str(status), status); -} -/*- End of function --------------------------------------------------------*/ - -static int v42_get_frames(void *user_data, uint8_t msg[], int len) -{ - int i; - int j; - int k; - int x; - v42_state_t *s; - - if (len < 0) - { - v42_status(user_data, len); - return 0; - } - s = (v42_state_t *) user_data; - x = (s == caller) ? 1 : 2; - if (variable_length) - { - j = make_mask32(len); - do - k = j & rand(); - while (k > len); - } - else - { - k = len; - } - for (i = 0; i < k; i++) - msg[i] = tx_next[x]++; - return k; -} -/*- End of function --------------------------------------------------------*/ - -static void v42_put_frames(void *user_data, const uint8_t msg[], int len) -{ - int i; - v42_state_t *s; - int x; - static int count = 0; - static int xxx = 0; - - if (len < 0) - { - v42_status(user_data, len); - return; - } - s = (v42_state_t *) user_data; - x = (s == caller) ? 1 : 2; - for (i = 0; i < len; i++) - { - if (msg[i] != (rx_next[x] & 0xFF)) - { - printf("%p: Mismatch 0x%02X 0x%02X\n", user_data, msg[i], rx_next[x] & 0xFF); - exit(2); - } - rx_next[x]++; - } - printf("%p: Got frame len %d\n", user_data, len); - printf("%p: %d Far end busy status %d\n", user_data, count, v42_get_far_busy_status(s)); - if (s == caller) - { - if (++count == 5) - { - v42_set_local_busy_status(s, true); - xxx = 1; - } - } - else - { - if (xxx && ++count == 45) - v42_set_local_busy_status(caller, false); - } -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int i; - int bit; - 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; - while ((opt = getopt(argc, argv, "bv")) != -1) - { - switch (opt) - { - case 'b': - insert_caller_bit_errors = 11000; - insert_answerer_bit_errors = 10000; - break; - case 'v': - variable_length = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - 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); - v42_restart(answerer); - - span_log_set_level(v42_get_logging_state(caller), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_DEBUG); - span_log_set_tag(v42_get_logging_state(caller), "caller"); - span_log_set_level(v42_get_logging_state(answerer), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_DEBUG); - span_log_set_tag(v42_get_logging_state(answerer), "answerer"); - - for (i = 0; i < 1000000; i++) - { - bit = v42_tx_bit(caller); - if (insert_caller_bit_errors && i%insert_caller_bit_errors == 0) - bit ^= 1; - v42_rx_bit(answerer, bit); - bit = v42_tx_bit(answerer); - if (insert_answerer_bit_errors && i%insert_answerer_bit_errors == 0) - bit ^= 1; - v42_rx_bit(caller, bit); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v42bis_tests.c b/libs/spandsp/tests/v42bis_tests.c deleted file mode 100644 index 2ce718feba..0000000000 --- a/libs/spandsp/tests/v42bis_tests.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42bis_tests.c - * - * 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 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. - */ - -/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */ - -/*! \page v42bis_tests_page V.42bis tests -\section v42bis_tests_page_sec_1 What does it do? -These tests compress the contents of a file specified on the command line, writing -the compressed data to v42bis_tests.v42bis. They then read back the contents of the -compressed file, decompress, and write the results to v42bis_tests.out. The contents -of this file should exactly match the original file. -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" - -#define COMPRESSED_FILE_NAME "v42bis_tests.v42bis" -#define DECOMPRESSED_FILE_NAME "v42bis_tests.out" - -int in_octets_to_date = 0; -int out_octets_to_date = 0; - -static void frame_handler(void *user_data, const uint8_t *buf, int len) -{ - int ret; - - if ((ret = write((intptr_t) user_data, buf, len)) != len) - fprintf(stderr, "Write error %d/%d\n", ret, errno); - out_octets_to_date += len; -} - -static void data_handler(void *user_data, const uint8_t *buf, int len) -{ - int ret; - - if ((ret = write((intptr_t) user_data, buf, len)) != len) - fprintf(stderr, "Write error %d/%d\n", ret, errno); - out_octets_to_date += len; -} - -int main(int argc, char *argv[]) -{ - int len; - v42bis_state_t *state_a; - v42bis_state_t *state_b; - uint8_t buf[1024]; - int in_fd; - int v42bis_fd; - int out_fd; - int do_compression; - bool do_decompression; - bool stutter_compression; - int stutter_time; - int seg; - int opt; - time_t now; - const char *argv0; - const char *original_file; - const char *compressed_file; - const char *decompressed_file; - - argv0 = argv[0]; - do_compression = false; - do_decompression = false; - stutter_compression = false; - while ((opt = getopt(argc, argv, "cds")) != -1) - { - switch (opt) - { - case 'c': - do_compression = true; - break; - case 'd': - do_decompression = true; - break; - case 's': - stutter_compression = true; - break; - default: - //usage(); - exit(2); - break; - } - } - argc -= optind; - argv += optind; - if (argc < 1) - { - fprintf(stderr, "Usage: %s [-c] [-d] [-s] []\n", argv0); - exit(2); - } - if (do_compression) - { - original_file = argv[0]; - compressed_file = COMPRESSED_FILE_NAME; - } - else - { - original_file = NULL; - compressed_file = argv[0]; - } - decompressed_file = (argc > 1) ? argv[1] : DECOMPRESSED_FILE_NAME; - if (do_compression) - { - stutter_time = rand() & 0x3FF; - if ((in_fd = open(argv[0], O_RDONLY)) < 0) - { - fprintf(stderr, "Error opening file '%s'.\n", original_file); - exit(2); - } - if ((v42bis_fd = open(compressed_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) - { - fprintf(stderr, "Error opening file '%s'.\n", compressed_file); - exit(2); - } - - time(&now); - state_a = v42bis_init(NULL, 3, 512, 6, frame_handler, (void *) (intptr_t) v42bis_fd, 512, data_handler, NULL, 512); - span_log_set_level(v42bis_get_logging_state(state_a), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(v42bis_get_logging_state(state_a), "V.42bis"); - //v42bis_compression_control(state_a, V42BIS_COMPRESSION_MODE_ALWAYS); - in_octets_to_date = 0; - out_octets_to_date = 0; - while ((len = read(in_fd, buf, 1024)) > 0) - { - seg = 0; - if (stutter_compression) - { - while ((len - seg) >= stutter_time) - { - if (v42bis_compress(state_a, buf + seg, stutter_time)) - { - fprintf(stderr, "Bad return code from compression\n"); - exit(2); - } - v42bis_compress_flush(state_a); - seg += stutter_time; - stutter_time = rand() & 0x3FF; - } - } - if (v42bis_compress(state_a, buf + seg, len - seg)) - { - fprintf(stderr, "Bad return code from compression\n"); - exit(2); - } - in_octets_to_date += len; - } - v42bis_compress_flush(state_a); - printf("%d bytes compressed to %d bytes in %lds\n", in_octets_to_date, out_octets_to_date, time(NULL) - now); - close(in_fd); - close(v42bis_fd); - } - - if (do_decompression) - { - /* Now open the files for the decompression. */ - if ((v42bis_fd = open(compressed_file, O_RDONLY)) < 0) - { - fprintf(stderr, "Error opening file '%s'.\n", compressed_file); - exit(2); - } - if ((out_fd = open(decompressed_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) - { - fprintf(stderr, "Error opening file '%s'.\n", decompressed_file); - exit(2); - } - - time(&now); - state_b = v42bis_init(NULL, 3, 512, 6, frame_handler, (void *) (intptr_t) v42bis_fd, 512, data_handler, (void *) (intptr_t) out_fd, 512); - span_log_set_level(v42bis_get_logging_state(state_b), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(v42bis_get_logging_state(state_b), "V.42bis"); - in_octets_to_date = 0; - out_octets_to_date = 0; - while ((len = read(v42bis_fd, buf, 1024)) > 0) - { - if (v42bis_decompress(state_b, buf, len)) - { - fprintf(stderr, "Bad return code from decompression\n"); - exit(2); - } - in_octets_to_date += len; - } - v42bis_decompress_flush(state_b); - printf("%d bytes decompressed to %d bytes in %lds\n", in_octets_to_date, out_octets_to_date, time(NULL) - now); - close(v42bis_fd); - close(out_fd); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/v42bis_tests.sh b/libs/spandsp/tests/v42bis_tests.sh deleted file mode 100755 index fa86645785..0000000000 --- a/libs/spandsp/tests/v42bis_tests.sh +++ /dev/null @@ -1,152 +0,0 @@ -#!/bin/sh -# -# V.42bis compression/decompression tests, as specified in V.56ter -# -# 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 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. - -BASE=../test-data/itu/v56ter - -./v42bis_tests -c -d ${BASE}/1.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/1.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/1X04.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/1X04.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/1X30.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/1X30.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/2.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/2.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/2X10.TST -RETVAL=$? - -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/2X10.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/3.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/3.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/3X06.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/3X06.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/4.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/4.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/4X04.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/4X04.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/5.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/5.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -./v42bis_tests -c -d ${BASE}/5X16.TST -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi -diff ${BASE}/5X16.TST v42bis_tests.out -RETVAL=$? -if [ $RETVAL != 0 ] -then - exit $RETVAL -fi diff --git a/libs/spandsp/tests/v8_tests.c b/libs/spandsp/tests/v8_tests.c deleted file mode 100644 index 43338583ef..0000000000 --- a/libs/spandsp/tests/v8_tests.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v8_tests.c - * - * 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 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. - */ - -/*! \page v8_tests_page V.8 tests -\section v8_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "spandsp.h" -#include "spandsp-sim.h" - -#define SAMPLES_PER_CHUNK 160 - -#define OUTPUT_FILE_NAME "v8.wav" - -int negotiations_ok = 0; - -#if 0 -static int select_modulation(int mask) -{ - /* Select the fastest data modem available */ - if (mask & V8_MOD_V90) - return V8_MOD_V90; - /*endif*/ - if (mask & V8_MOD_V34) - return V8_MOD_V34; - /*endif*/ - if (mask & V8_MOD_V32) - return V8_MOD_V32; - /*endif*/ - if (mask & V8_MOD_V23) - return V8_MOD_V23; - /*endif*/ - if (mask & V8_MOD_V21) - return V8_MOD_V21; - /*endif*/ - return -1; -} -/*- End of function --------------------------------------------------------*/ -#endif - -static void handler(void *user_data, v8_parms_t *result) -{ - const char *s; - - s = (const char *) user_data; - - printf("%s ", s); - switch (result->status) - { - case V8_STATUS_IN_PROGRESS: - printf("V.8 negotiation in progress\n"); - return; - case V8_STATUS_V8_OFFERED: - printf("V.8 offered by the other party\n"); - break; - case V8_STATUS_V8_CALL: - printf("V.8 call negotiation successful\n"); - break; - case V8_STATUS_NON_V8_CALL: - printf("Non-V.8 call negotiation successful\n"); - break; - case V8_STATUS_FAILED: - printf("V.8 call negotiation failed\n"); - return; - default: - printf("Unexpected V.8 status %d\n", result->status); - break; - } - /*endswitch*/ - - printf(" Modem connect tone '%s' (%d)\n", modem_connect_tone_to_str(result->modem_connect_tone), result->modem_connect_tone); - printf(" Call function '%s' (%d)\n", v8_call_function_to_str(result->call_function), result->call_function); - printf(" Far end modulations 0x%X\n", result->modulations); - printf(" Protocol '%s' (%d)\n", v8_protocol_to_str(result->protocol), result->protocol); - printf(" PSTN access '%s' (%d)\n", v8_pstn_access_to_str(result->pstn_access), result->pstn_access); - printf(" PCM modem availability '%s' (%d)\n", v8_pcm_modem_availability_to_str(result->pcm_modem_availability), result->pcm_modem_availability); - if (result->t66 >= 0) - printf(" T.66 '%s' (%d)\n", v8_t66_to_str(result->t66), result->t66); - /*endif*/ - if (result->nsf >= 0) - printf(" NSF %d\n", result->nsf); - /*endif*/ - - switch (result->status) - { - case V8_STATUS_V8_OFFERED: - /* Edit the result information appropriately */ - //result->call_function = V8_CALL_T30_TX; - result->modulations &= (V8_MOD_V17 - | V8_MOD_V21 - //| V8_MOD_V22 - //| V8_MOD_V23HDX - //| V8_MOD_V23 - //| V8_MOD_V26BIS - //| V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - //| V8_MOD_V32 - | V8_MOD_V34HDX - //| V8_MOD_V34 - //| V8_MOD_V90 - | V8_MOD_V92); - break; - case V8_STATUS_V8_CALL: - if (result->call_function == V8_CALL_V_SERIES - && - result->protocol == V8_PROTOCOL_LAPM_V42) - { - negotiations_ok++; - } - /*endif*/ - break; - case V8_STATUS_NON_V8_CALL: - negotiations_ok = 42; - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static int v8_calls_v8_tests(SNDFILE *outhandle) -{ - v8_state_t *v8_caller; - v8_state_t *v8_answerer; - logging_state_t *caller_logging; - logging_state_t *answerer_logging; - int caller_available_modulations; - int answerer_available_modulations; - int i; - int samples; - int remnant; - int outframes; - int16_t amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - v8_parms_t v8_call_parms; - v8_parms_t v8_answer_parms; - - caller_available_modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V26BIS - | V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - | V8_MOD_V32 - | V8_MOD_V34HDX - | V8_MOD_V34 - | V8_MOD_V90 - | V8_MOD_V92; - answerer_available_modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V26BIS - | V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - | V8_MOD_V32 - | V8_MOD_V34HDX - | V8_MOD_V34 - | V8_MOD_V90 - | V8_MOD_V92; - negotiations_ok = 0; - - v8_call_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - 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; - v8_call_parms.protocol = V8_PROTOCOL_LAPM_V42; - v8_call_parms.pcm_modem_availability = 0; - v8_call_parms.pstn_access = 0; - v8_call_parms.nsf = -1; - v8_call_parms.t66 = -1; - v8_caller = v8_init(NULL, 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.v92 = -1; - v8_answer_parms.call_function = V8_CALL_V_SERIES; - v8_answer_parms.modulations = answerer_available_modulations; - v8_answer_parms.protocol = V8_PROTOCOL_LAPM_V42; - v8_answer_parms.pcm_modem_availability = 0; - v8_answer_parms.pstn_access = 0; - v8_answer_parms.nsf = -1; - v8_answer_parms.t66 = -1; - v8_answerer = v8_init(NULL, false, &v8_answer_parms, handler, (void *) "answerer"); - - caller_logging = v8_get_logging_state(v8_caller); - span_log_set_level(caller_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(caller_logging, "caller"); - answerer_logging = v8_get_logging_state(v8_answerer); - span_log_set_level(answerer_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(answerer_logging, "answerer"); - for (i = 0; i < 1000; i++) - { - samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { -printf("Caller silence %d\n", SAMPLES_PER_CHUNK - samples); - vec_zeroi16(amp + samples, SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - /*endif*/ - span_log_bump_samples(caller_logging, samples); - remnant = v8_rx(v8_answerer, amp, samples); - for (i = 0; i < samples; i++) - out_amp[2*i] = amp[i]; - /*endfor*/ - - samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { -printf("Answerer silence %d\n", SAMPLES_PER_CHUNK - samples); - vec_zeroi16(amp + samples, SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - /*endif*/ - span_log_bump_samples(answerer_logging, samples); - if (v8_rx(v8_caller, amp, samples) && remnant) - break; - /*endif*/ - for (i = 0; i < samples; i++) - out_amp[2*i + 1] = amp[i]; - /*endfor*/ - - if (outhandle) - { - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endif*/ - } - /*endfor*/ - v8_free(v8_caller); - v8_free(v8_answerer); - - if (negotiations_ok != 2) - { - printf("Tests failed.\n"); - exit(2); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int non_v8_calls_v8_tests(SNDFILE *outhandle) -{ - silence_gen_state_t *non_v8_caller_tx; - modem_connect_tones_rx_state_t *non_v8_caller_rx; - v8_state_t *v8_answerer; - logging_state_t *answerer_logging; - int answerer_available_modulations; - int i; - int samples; - int remnant; - int outframes; - int tone; - int16_t amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - v8_parms_t v8_answer_parms; - - answerer_available_modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V26BIS - | V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - | V8_MOD_V32 - | V8_MOD_V34HDX - | V8_MOD_V34 - | V8_MOD_V90 - | V8_MOD_V92; - negotiations_ok = 0; - - non_v8_caller_tx = silence_gen_init(NULL, 10*SAMPLE_RATE); - 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.v92 = -1; - v8_answer_parms.call_function = V8_CALL_V_SERIES; - v8_answer_parms.modulations = answerer_available_modulations; - v8_answer_parms.protocol = V8_PROTOCOL_LAPM_V42; - v8_answer_parms.pcm_modem_availability = 0; - v8_answer_parms.pstn_access = 0; - v8_answer_parms.nsf = -1; - v8_answer_parms.t66 = -1; - v8_answerer = v8_init(NULL, - false, - &v8_answer_parms, - handler, - (void *) "answerer"); - answerer_logging = v8_get_logging_state(v8_answerer); - span_log_set_level(answerer_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(answerer_logging, "answerer"); - for (i = 0; i < 1000; i++) - { - samples = silence_gen(non_v8_caller_tx, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(amp + samples, SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - /*endif*/ - remnant = v8_rx(v8_answerer, amp, samples); - if (remnant) - break; - /*endif*/ - for (i = 0; i < samples; i++) - out_amp[2*i] = amp[i]; - /*endfor*/ - - samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(amp + samples, SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - /*endif*/ - span_log_bump_samples(answerer_logging, samples); - modem_connect_tones_rx(non_v8_caller_rx, amp, samples); - if ((tone = modem_connect_tones_rx_get(non_v8_caller_rx)) != MODEM_CONNECT_TONES_NONE) - { - printf("Detected %s (%d)\n", modem_connect_tone_to_str(tone), tone); - if (tone == MODEM_CONNECT_TONES_ANSAM_PR) - negotiations_ok++; - /*endif*/ - } - /*endif*/ - for (i = 0; i < samples; i++) - out_amp[2*i + 1] = amp[i]; - /*endfor*/ - - if (outhandle) - { - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endif*/ - } - /*endfor*/ - silence_gen_free(non_v8_caller_tx); - modem_connect_tones_rx_free(non_v8_caller_rx); - v8_free(v8_answerer); - - if (negotiations_ok != 1) - { - printf("Tests failed.\n"); - exit(2); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int v8_calls_non_v8_tests(SNDFILE *outhandle) -{ - v8_state_t *v8_caller; - modem_connect_tones_tx_state_t *non_v8_answerer_tx; - logging_state_t *caller_logging; - int caller_available_modulations; - int i; - int samples; - int outframes; - int16_t amp[SAMPLES_PER_CHUNK]; - int16_t out_amp[2*SAMPLES_PER_CHUNK]; - v8_parms_t v8_call_parms; - - caller_available_modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V26BIS - | V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - | V8_MOD_V32 - | V8_MOD_V34HDX - | V8_MOD_V34 - | V8_MOD_V90 - | V8_MOD_V92; - negotiations_ok = 0; - - v8_call_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - 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; - v8_call_parms.protocol = V8_PROTOCOL_LAPM_V42; - v8_call_parms.pcm_modem_availability = 0; - v8_call_parms.pstn_access = 0; - v8_call_parms.nsf = -1; - v8_call_parms.t66 = -1; - v8_caller = v8_init(NULL, - true, - &v8_call_parms, - handler, - (void *) "caller"); - non_v8_answerer_tx = modem_connect_tones_tx_init(NULL, MODEM_CONNECT_TONES_ANS_PR); - caller_logging = v8_get_logging_state(v8_caller); - span_log_set_level(caller_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); - span_log_set_tag(caller_logging, "caller"); - for (i = 0; i < 1000; i++) - { - samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(amp + samples, SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - /*endif*/ - span_log_bump_samples(caller_logging, samples); - for (i = 0; i < samples; i++) - out_amp[2*i] = amp[i]; - /*endfor*/ - - samples = modem_connect_tones_tx(non_v8_answerer_tx, amp, SAMPLES_PER_CHUNK); - if (samples < SAMPLES_PER_CHUNK) - { - vec_zeroi16(amp + samples, SAMPLES_PER_CHUNK - samples); - samples = SAMPLES_PER_CHUNK; - } - /*endif*/ - if (v8_rx(v8_caller, amp, samples)) - break; - /*endif*/ - for (i = 0; i < samples; i++) - out_amp[2*i + 1] = amp[i]; - /*endfor*/ - - if (outhandle) - { - outframes = sf_writef_short(outhandle, out_amp, samples); - if (outframes != samples) - { - fprintf(stderr, " Error writing audio file\n"); - exit(2); - } - /*endif*/ - } - /*endif*/ - } - /*endfor*/ - v8_free(v8_caller); - modem_connect_tones_tx_free(non_v8_answerer_tx); - - if (negotiations_ok != 42) - { - printf("Tests failed.\n"); - exit(2); - } - /*endif*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - int16_t amp[SAMPLES_PER_CHUNK]; - int samples; - int caller_available_modulations; - int answerer_available_modulations; - SNDFILE *inhandle; - SNDFILE *outhandle; - int opt; - bool log_audio; - char *decode_test_file; - v8_state_t *v8_caller; - v8_state_t *v8_answerer; - v8_parms_t v8_call_parms; - v8_parms_t v8_answer_parms; - logging_state_t *logging; - - decode_test_file = NULL; - log_audio = false; - while ((opt = getopt(argc, argv, "d:l")) != -1) - { - switch (opt) - { - case 'd': - decode_test_file = optarg; - break; - case 'l': - log_audio = true; - break; - default: - //usage(); - exit(2); - break; - } - } - - if (decode_test_file) - { - caller_available_modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V26BIS - | V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - | V8_MOD_V32 - | V8_MOD_V34HDX - | V8_MOD_V34 - | V8_MOD_V90 - | V8_MOD_V92; - answerer_available_modulations = V8_MOD_V17 - | V8_MOD_V21 - | V8_MOD_V22 - | V8_MOD_V23HDX - | V8_MOD_V23 - | V8_MOD_V26BIS - | V8_MOD_V26TER - | V8_MOD_V27TER - | V8_MOD_V29 - | V8_MOD_V32 - | V8_MOD_V34HDX - | V8_MOD_V34 - | V8_MOD_V90 - | V8_MOD_V92; - - 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.v92 = -1; - v8_call_parms.call_function = V8_CALL_V_SERIES; - v8_call_parms.modulations = caller_available_modulations; - v8_call_parms.protocol = V8_PROTOCOL_LAPM_V42; - v8_call_parms.pcm_modem_availability = 0; - v8_call_parms.pstn_access = 0; - v8_call_parms.nsf = -1; - v8_call_parms.t66 = -1; - v8_caller = v8_init(NULL, - true, - &v8_call_parms, - handler, - (void *) "caller"); - logging = v8_get_logging_state(v8_caller); - span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG); - 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.v92 = -1; - v8_answer_parms.call_function = V8_CALL_V_SERIES; - v8_answer_parms.modulations = answerer_available_modulations; - v8_answer_parms.protocol = V8_PROTOCOL_LAPM_V42; - v8_answer_parms.pcm_modem_availability = 0; - v8_answer_parms.pstn_access = 0; - v8_answer_parms.nsf = -1; - v8_answer_parms.t66 = -1; - v8_answerer = v8_init(NULL, - false, - &v8_answer_parms, - handler, - (void *) "answerer"); - logging = v8_get_logging_state(v8_answerer); - span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG); - span_log_set_tag(logging, "answerer"); - - if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) - { - fprintf(stderr, " Cannot open speech file '%s'\n", decode_test_file); - exit (2); - } - /*endif*/ - - while ((samples = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK))) - { - v8_rx(v8_caller, amp, samples); - v8_rx(v8_answerer, amp, samples); - v8_tx(v8_caller, amp, samples); - v8_tx(v8_answerer, amp, samples); - } - /*endwhile*/ - - v8_free(v8_caller); - v8_free(v8_answerer); - if (sf_close_telephony(inhandle)) - { - fprintf(stderr, " Cannot close speech file '%s'\n", decode_test_file); - exit(2); - } - /*endif*/ - } - else - { - outhandle = NULL; - if (log_audio) - { - if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL) - { - fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - /*endif*/ - } - /*endif*/ - - printf("Test 1: V.8 terminal calls V.8 terminal\n"); - v8_calls_v8_tests(outhandle); - - printf("Test 2: non-V.8 terminal calls V.8 terminal\n"); - non_v8_calls_v8_tests(outhandle); - - printf("Test 3: V.8 terminal calls non-V.8 terminal\n"); - v8_calls_non_v8_tests(outhandle); - - if (outhandle) - { - if (sf_close_telephony(outhandle)) - { - fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); - exit(2); - } - /*endif*/ - } - /*endif*/ - - printf("Tests passed.\n"); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/vector_float_tests.c b/libs/spandsp/tests/vector_float_tests.c deleted file mode 100644 index d6d1b95112..0000000000 --- a/libs/spandsp/tests/vector_float_tests.c +++ /dev/null @@ -1,651 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * vector_float_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" - -static void vec_copyf_dumb(float z[], const float x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_copyf(void) -{ - int i; - float x[100]; - float za[100]; - float zb[100]; - - printf("Testing vec_copyf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = i; - za[i] = -0.5f; - zb[i] = -0.5f; - } - vec_copyf_dumb(za + 3, x + 1, 0); - vec_copyf(zb + 3, x + 1, 0); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_copyf() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_copyf_dumb(za + 3, x + 1, 1); - vec_copyf(zb + 3, x + 1, 1); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_copyf() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_copyf_dumb(za + 3, x + 1, 29); - vec_copyf(zb + 3, x + 1, 29); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_copyf() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_negatef_dumb(float z[], const float x[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = -x[i]; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_negatef(void) -{ - int i; - float x[100]; - float za[100]; - float zb[100]; - - printf("Testing vec_negatef()\n"); - for (i = 0; i < 99; i++) - { - x[i] = i; - za[i] = -0.5f; - zb[i] = -0.5f; - } - vec_negatef_dumb(za + 3, x + 1, 0); - vec_negatef(zb + 3, x + 1, 0); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_negatef() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_negatef_dumb(za + 3, x + 1, 1); - vec_negatef(zb + 3, x + 1, 1); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_megatef() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_negatef_dumb(za + 3, x + 1, 29); - 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]); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_zerof_dumb(float z[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = 0.0f; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_zerof(void) -{ - int i; - float za[100]; - float zb[100]; - - printf("Testing vec_zerof()\n"); - for (i = 0; i < 99; i++) - { - za[i] = -1.0f; - zb[i] = -1.0f; - } - vec_zerof_dumb(za + 3, 0); - vec_zerof(zb + 3, 0); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_zerof() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_zerof_dumb(za + 3, 1); - vec_zerof(zb + 3, 1); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_zerof() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_zerof_dumb(za + 3, 29); - vec_zerof(zb + 3, 29); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_zerof() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_setf_dumb(float z[], float x, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_setf(void) -{ - int i; - float za[100]; - float zb[100]; - - printf("Testing vec_setf()\n"); - for (i = 0; i < 99; i++) - { - za[i] = -1.0f; - zb[i] = -1.0f; - } - vec_setf_dumb(za + 3, 42.0f, 0); - vec_setf(zb + 3, 42.0f, 0); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_setf() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_setf_dumb(za + 3, 42.0f, 1); - vec_setf(zb + 3, 42.0f, 1); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_setf() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - vec_setf_dumb(za + 3, 42.0f, 29); - vec_setf(zb + 3, 42.0f, 29); - for (i = 0; i < 99; i++) - { - if (za[i] != zb[i]) - { - printf("vec_setf() - %d %f %f\n", i, za[i], zb[i]); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static double vec_dot_prod_dumb(const double x[], const double y[], int n) -{ - int i; - double z; - - z = 0.0; - for (i = 0; i < n; i++) - z += x[i]*y[i]; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_dot_prod(void) -{ - int i; - double x[100]; - double y[100]; - double zsa; - double zsb; - double ratio; - - printf("Testing vec_dot_prod()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 99; i++) - { - zsa = vec_dot_prod(x, y, i); - zsb = vec_dot_prod_dumb(x, y, i); - ratio = zsa/zsb; - if (ratio < 0.9999 || ratio > 1.0001) - { - printf("vec_dot_prod() - %f %f\n", zsa, zsb); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static float vec_dot_prodf_dumb(const float x[], const float y[], int n) -{ - int i; - float z; - - z = 0.0; - for (i = 0; i < n; i++) - z += x[i]*y[i]; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_dot_prodf(void) -{ - int i; - float x[100]; - float y[100]; - float zsa; - float zsb; - float ratio; - - printf("Testing vec_dot_prodf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 99; i++) - { - zsa = vec_dot_prodf(x, y, i); - zsb = vec_dot_prodf_dumb(x, y, i); - ratio = zsa/zsb; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_dot_prodf() - %e %e\n", zsa, zsb); - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_addf_dumb(float z[], const float x[], const float y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_addf(void) -{ - int i; - int j; - float x[100]; - float y[100]; - float zsa[100]; - float zsb[100]; - float ratio; - - printf("Testing vec_addf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 90; i++) - { - /* Force address misalignment, to check this works OK */ - vec_addf(zsa + 1, x + 1, y + 1, i); - vec_addf_dumb(zsb + 1, x + 1, y + 1, i); - for (j = 1; j <= i; j++) - { - ratio = zsa[j]/zsb[j]; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_mulf() - %d %e %e\n", j, zsa[j], zsb[j]); - printf("Tests failed\n"); - exit(2); - } - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_subf_dumb(float z[], const float x[], const float y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] - y[i]; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_subf(void) -{ - int i; - int j; - float x[100]; - float y[100]; - float zsa[100]; - float zsb[100]; - float ratio; - - printf("Testing vec_subf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 90; i++) - { - /* Force address misalignment, to check this works OK */ - vec_subf(zsa + 1, x + 1, y + 1, i); - vec_subf_dumb(zsb + 1, x + 1, y + 1, i); - for (j = 1; j <= i; j++) - { - ratio = zsa[j]/zsb[j]; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_mulf() - %d %e %e\n", j, zsa[j], zsb[j]); - printf("Tests failed\n"); - exit(2); - } - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_mulf_dumb(float z[], const float x[], const float y[], int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*y[i]; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_mulf(void) -{ - int i; - int j; - float x[100]; - float y[100]; - float zsa[100]; - float zsb[100]; - float ratio; - - printf("Testing vec_mulf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 90; i++) - { - /* Force address misalignment, to check this works OK */ - vec_mulf(zsa + 1, x + 1, y + 1, i); - vec_mulf_dumb(zsb + 1, x + 1, y + 1, i); - for (j = 1; j <= i; j++) - { - ratio = zsa[j]/zsb[j]; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_mulf() - %d %e %e\n", j, zsa[j], zsb[j]); - printf("Tests failed\n"); - exit(2); - } - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -#define LMS_LEAK_RATE 0.9999f - -static void vec_lmsf_dumb(const float x[], float y[], int n, float error) -{ - int i; - - for (i = 0; i < n; i++) - { - /* Leak a little to tame uncontrolled wandering */ - y[i] = y[i]*LMS_LEAK_RATE + x[i]*error; - } -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_lmsf(void) -{ - int i; - int j; - float x[100]; - float ya[100]; - float yb[100]; - float ratio; - - printf("Testing vec_lmsf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - ya[i] = - yb[i] = rand(); - } - for (i = 1; i < 99; i++) - { - vec_lmsf(x, ya, i, 0.1f); - vec_lmsf_dumb(x, yb, i, 0.1f); - for (j = 0; j < i; j++) - { - ratio = ya[j]/yb[j]; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_lmsf() - %d %e %e\n", j, ya[j], yb[j]); - printf("Tests failed\n"); - exit(2); - } - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_scaledxy_addf_dumb(float z[], const float x[], float x_scale, const float y[], float y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i]*x_scale + y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_scaledxy_addf(void) -{ - int i; - int j; - float x[100]; - float y[100]; - float za[100]; - float zb[100]; - float ratio; - - printf("Testing vec_scaledxy_addf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 99; i++) - { - vec_scaledxy_addf(za, x, 2.5f, y, 1.5f, i); - vec_scaledxy_addf_dumb(zb, x, 2.5f, y, 1.5f, i); - for (j = 0; j < i; j++) - { - ratio = za[j]/zb[j]; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_scaledxy_addf() - %d %e %e\n", j, za[j], zb[j]); - printf("Tests failed\n"); - exit(2); - } - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void vec_scaledy_addf_dumb(float z[], const float x[], const float y[], float y_scale, int n) -{ - int i; - - for (i = 0; i < n; i++) - z[i] = x[i] + y[i]*y_scale; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_scaledy_addf(void) -{ - int i; - int j; - float x[100]; - float y[100]; - float za[100]; - float zb[100]; - float ratio; - - printf("Testing vec_scaledy_addf()\n"); - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - for (i = 1; i < 99; i++) - { - vec_scaledy_addf(za, x, y, 1.5f, i); - vec_scaledy_addf_dumb(zb, x, y, 1.5f, i); - for (j = 0; j < i; j++) - { - ratio = za[j]/zb[j]; - if (ratio < 0.9999f || ratio > 1.0001f) - { - printf("vec_scaledy_addf() - %d %e %e\n", j, za[j], zb[j]); - printf("Tests failed\n"); - exit(2); - } - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - test_vec_copyf(); - test_vec_negatef(); - test_vec_zerof(); - test_vec_setf(); - test_vec_addf(); - test_vec_subf(); - test_vec_mulf(); - test_vec_scaledxy_addf(); - test_vec_scaledy_addf(); - test_vec_dot_prod(); - test_vec_dot_prodf(); - test_vec_lmsf(); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/vector_int_tests.c b/libs/spandsp/tests/vector_int_tests.c deleted file mode 100644 index 0ac0c6424c..0000000000 --- a/libs/spandsp/tests/vector_int_tests.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * complex_vector_int_tests.c - * - * Written by Steve Underwood - * - * Copyright (C) 2006 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. - */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "spandsp.h" - -static int32_t vec_dot_prodi16_dumb(const int16_t x[], const int16_t y[], int n) -{ - int32_t z; - int i; - - z = 0; - for (i = 0; i < n; i++) - z += (int32_t) x[i]*(int32_t) y[i]; - return z; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_dot_prodi16(void) -{ - int i; - int32_t za; - int32_t zb; - int16_t x[99]; - int16_t y[99]; - - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - - for (i = 1; i < 99; i++) - { - za = vec_dot_prodi16(x, y, i); - zb = vec_dot_prodi16_dumb(x, y, i); - if (za != zb) - { - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int32_t vec_min_maxi16_dumb(const int16_t x[], int n, int16_t out[]) -{ - int i; - int16_t min; - int16_t max; - int16_t temp; - int32_t z; - - max = INT16_MIN; - min = INT16_MAX; - for (i = 0; i < n; i++) - { - temp = x[i]; - if (temp > max) - max = temp; - /*endif*/ - if (temp < min) - min = temp; - /*endif*/ - } - /*endfor*/ - out[0] = max; - out[1] = min; - z = abs(min); - if (z > max) - return z; - return max; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_min_maxi16(void) -{ - int i; - int32_t za; - int32_t zb; - int16_t x[99]; - int16_t outa[2]; - int16_t outb[2]; - - for (i = 0; i < 99; i++) - x[i] = rand(); - - x[42] = -32768; - za = vec_min_maxi16_dumb(x, 99, outa); - zb = vec_min_maxi16(x, 99, outb); - if (za != zb - || - outa[0] != outb[0] - || - outa[1] != outb[1]) - { - printf("Tests failed\n"); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int test_vec_circular_dot_prodi16(void) -{ - int i; - int j; - int pos; - int len; - int32_t za; - int32_t zb; - int16_t x[99]; - int16_t y[99]; - - /* Verify that we can do circular sample buffer "dot" linear coefficient buffer - operations properly, by doing two sub-dot products. */ - for (i = 0; i < 99; i++) - { - x[i] = rand(); - y[i] = rand(); - } - - len = 95; - for (pos = 0; pos < len; pos++) - { - za = vec_circular_dot_prodi16(x, y, len, pos); - zb = 0; - for (i = 0; i < len; i++) - { - j = (pos + i) % len; - zb += (int32_t) x[j]*(int32_t) y[i]; - } - - if (za != zb) - { - printf("Tests failed\n"); - exit(2); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -int main(int argc, char *argv[]) -{ - test_vec_dot_prodi16(); - test_vec_min_maxi16(); - test_vec_circular_dot_prodi16(); - - printf("Tests passed.\n"); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/unpack_g722_data.sh b/libs/spandsp/unpack_g722_data.sh deleted file mode 100755 index a73c345a3b..0000000000 --- a/libs/spandsp/unpack_g722_data.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# -# SpanDSP - a series of DSP components for telephony -# -# unpack_g722_data.sh -# -# 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 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. - -ITUDATA="../../../T-REC-G.722-198703-I!AppII!ZPF-E.zip" - -cd test-data/itu -if [ -d g722 ] -then - cd g722 -else - mkdir g722 - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot create test-data/itu/g722! - exit $RETVAL - fi - cd g722 -fi - -rm -rf T* -rm -rf software -unzip ${ITUDATA} >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ITU test vectors for G.722! - exit $RETVAL -fi -#rm ${ITUDATA} -unzip ./software/G722ap2/G722E/Software.zip >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ITU test vectors for G.722! - exit $RETVAL -fi -mv ./software/G722ap2/G722E/T* . -rm -rf software -echo The ITU test vectors for G.722 should now be in the g722 directory diff --git a/libs/spandsp/unpack_g726_data.sh b/libs/spandsp/unpack_g726_data.sh deleted file mode 100755 index 8e3bbf3d6b..0000000000 --- a/libs/spandsp/unpack_g726_data.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# -# SpanDSP - a series of DSP components for telephony -# -# unpack_g726_data.sh -# -# 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 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. - -ITUDATA="../../../T-REC-G.726-199103-I!AppII!SOFT-ZST-E.zip" - -cd test-data/itu -if [ -d g726 ] -then - cd g726 -else - mkdir g726 - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot create test-data/itu/g726! - exit $RETVAL - fi - cd g726 -fi - -rm -rf DISK1 -rm -rf DISK2 -rm -rf G726piiE.WW7.doc -rm -rf Software.zip -unzip ${ITUDATA} >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ITU test vectors for G.726! - exit $RETVAL -fi -#rm $(ITUDATA} -rm G726piiE.WW7.doc -unzip Software.zip >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ITU test vectors for G.726! - exit $RETVAL -fi -rm Software.zip -mv ./software/G726ap2/G726ap2e/DISK1 . -mv ./software/G726ap2/G726ap2e/DISK2 . -rm -rf ./software -echo The ITU test vectors for G.726 should now be in the g726 directory diff --git a/libs/spandsp/unpack_gsm0610_data.sh b/libs/spandsp/unpack_gsm0610_data.sh deleted file mode 100755 index 1141e6a3e1..0000000000 --- a/libs/spandsp/unpack_gsm0610_data.sh +++ /dev/null @@ -1,353 +0,0 @@ -#!/bin/sh -# -# SpanDSP - a series of DSP components for telephony -# -# unpack_gsm0610_data.sh -# -# 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 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. - -# The ETSI distribution file extracts to 5 ZIP files, called DISK1.ZIP to DISK5.ZIP -# These were originally the contents of 5 floppy disks. Disks 1 to 3 contain data -# files. However, disks 4 and 5 contain .EXE files, which unpack.... but only in an -# MS environment. These files need to be executed in a Windows or DOS environment, -# or a good emulation like FreeDOS or Wine. - -ETSIDATA="../../../en_300961v080101p0.zip" - -cd test-data -if [ -d etsi ] -then - cd etsi -else - mkdir etsi - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot create test-data/etsi! - exit $RETVAL - fi - cd etsi -fi -if [ -d gsm0610 ] -then - cd gsm0610 -else - mkdir gsm0610 - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot create test-data/etsi/gsm0610! - exit $RETVAL - fi - cd gsm0610 -fi - -if [ $1x = --no-exe-runx ] -then - # Run the .exe files, which should be here - ./FR_A.EXE - ./FR_HOM_A.EXE - ./FR_SYN_A.EXE - ./FR_U.EXE - ./FR_HOM_U.EXE - ./FR_SYN_U.EXE - exit 0 -fi - -# Clear out any leftovers from the past -rm -rf ASN.1.txt -rm -rf DISK1.ZIP -rm -rf DISK2.ZIP -rm -rf DISK3.ZIP -rm -rf DISK4.ZIP -rm -rf DISK5.ZIP -rm -rf *.EXE -rm -rf READ_FRA.TXT -rm -rf ACTION -rm -rf unpacked - -if [ $1x = --no-exex ] -then - # We need to prepare the .exe files to be run separately - rm -rf *.INP - rm -rf *.COD - rm -rf *.OUT - - unzip ${ETSIDATA} >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL - fi - unzip ./DISK4.ZIP >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL - fi - unzip ./DISK5.ZIP >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL - fi - rm -rf ASN.1.txt - rm -rf DISK1.ZIP - rm -rf DISK2.ZIP - rm -rf DISK3.ZIP - rm -rf DISK4.ZIP - rm -rf DISK5.ZIP - rm -rf READ_FRA.TXT - - # An environment which is emulating an MS one will probably need - # to make the .EXE files actually executable. - chmod 755 *.EXE - - echo "Now copy the files from the test-data/etsi/gsm0610 directory to a Windows," - echo "DOS or other machine which can run .exe files. Run each of the .exe" - echo "files (there are 6 of them), and copy the whole directory back here." - echo "You can then complete the creation of the working data directories" - echo "with the command:" - echo $0 "--no-exe-continue" - exit 0 -fi - -unzip ${ETSIDATA} >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL -fi -#rm ${ETSIDATA} - -rm -rf ASN.1.txt - -if [ $1x != --no-exe-continuex ] -then - # We need to extract and run the .exe files right now. For this to succeed - # we must be running in an environment which can run .exe files. This has been - # tested with Cygwin on a Windows XP machine. - rm -rf *.INP - rm -rf *.COD - rm -rf *.OUT - - unzip ./DISK4.ZIP >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL - fi - unzip ./DISK5.ZIP >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL - fi - # An environment which is emulating an MS one will probably need - # to make the .EXE files actually executable. - chmod 755 *.EXE - ./FR_HOM_A.EXE >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot run ./FR_HOM_A.EXE - exit $RETVAL - fi - ./FR_SYN_A.EXE >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot run ./FR_HOM_A.EXE - exit $RETVAL - fi - ./FR_A.EXE >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot run ./FR_HOM_A.EXE - exit $RETVAL - fi - ./FR_HOM_U.EXE >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot run ./FR_HOM_A.EXE - exit $RETVAL - fi - ./FR_SYN_U.EXE >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot run ./FR_HOM_A.EXE - exit $RETVAL - fi - ./FR_U.EXE >/dev/null - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot run ./FR_HOM_A.EXE - exit $RETVAL - fi - - rm -rf READ_FRA.TXT -fi - -rm -rf DISK4.ZIP -rm -rf DISK5.ZIP -rm -rf *.EXE - -chmod 644 *.INP -chmod 644 *.OUT -chmod 644 *.COD - -# Create the directories where we want to put the test data files. -mkdir unpacked -mkdir unpacked/fr_A -mkdir unpacked/fr_L -mkdir unpacked/fr_U -mkdir unpacked/fr_homing_A -mkdir unpacked/fr_homing_L -mkdir unpacked/fr_homing_U -mkdir unpacked/fr_sync_A -mkdir unpacked/fr_sync_L -mkdir unpacked/fr_sync_U - -# Disks 1, 2 and 3 simply unzip, and the files have sensible file names. We -# just need to rearrange the directories in which they are located. -unzip ./DISK1.ZIP >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL -fi -unzip ./DISK2.ZIP >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL -fi -unzip ./DISK3.ZIP >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ETSI test vectors for GSM 06.10! - exit $RETVAL -fi -rm -rf DISK1.ZIP -rm -rf DISK2.ZIP -rm -rf DISK3.ZIP - -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK1/"* ./unpacked/fr_L -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK3/"Sync*.cod ./unpacked/fr_sync_L -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK2/"Seq*h.* ./unpacked/fr_homing_L -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK3/"Seq*h.* ./unpacked/fr_homing_L -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK3/Bitsync.inp" ./unpacked/fr_sync_L -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK3/Seqsync.inp" ./unpacked/fr_sync_L - -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK3/Homing01.cod" ./unpacked/fr_homing_L -mv "./ACTION/SMG#23/HOLD/0610_5~1/TESTSE~1/DISK3/Homing01.out" ./unpacked/fr_homing_L - -rm -rf ACTION - -# The files extracted by the .EXE files have messy naming, and are not in -# a sane directory layout. We rename and move them, to make the final result of -# the files extracted from all five of the original .ZIP files reasonably -# consistent, and easy to follow. -rm -rf READ_FRA.TXT - -for I in SYN*_A.COD ; -do - mv $I `echo $I | sed -e "s|SYN|./unpacked/fr_sync_A/Sync|" | sed -e "s/COD/cod/"` -done - -for I in SYN*_U.COD ; -do - mv $I `echo $I | sed -e "s|SYN|./unpacked/fr_sync_U/Sync|" | sed -e "s/COD/cod/"` -done - -for I in SEQ*H_A.COD ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_homing_A/Seq|" | sed -e "s/COD/cod/"` -done - -for I in SEQ*H_U.COD ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_homing_U/Seq|" | sed -e "s/COD/cod/"` -done - -for I in SEQ*H_A.INP ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_homing_A/Seq|" | sed -e "s/INP/inp/"` -done - -for I in SEQ*H_U.INP ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_homing_U/Seq|" | sed -e "s/INP/inp/"` -done - -for I in SEQ*H_A.OUT ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_homing_A/Seq|" | sed -e "s/OUT/out/"` -done - -for I in SEQ*H_U.OUT ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_homing_U/Seq|" | sed -e "s/OUT/out/"` -done - -for I in SEQ*-A.COD ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_A/Seq|" | sed -e "s/COD/cod/"` -done - -for I in SEQ*-U.COD ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_U/Seq|" | sed -e "s/COD/cod/"` -done - -for I in SEQ*-A.INP ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_A/Seq|" | sed -e "s/INP/inp/"` -done - -for I in SEQ*-U.INP ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_U/Seq|" | sed -e "s/INP/inp/"` -done - -for I in SEQ*-A.OUT ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_A/Seq|" | sed -e "s/OUT/out/"` -done - -for I in SEQ*-U.OUT ; -do - mv $I `echo $I | sed -e "s|SEQ|./unpacked/fr_U/Seq|" | sed -e "s/OUT/out/"` -done - -mv HOM01_A.OUT ./unpacked/fr_homing_A/Homing01_A.out -mv HOM01_U.OUT ./unpacked/fr_homing_U/Homing01_U.out -mv SEQSYN_A.INP ./unpacked/fr_sync_A/Seqsync_A.inp -mv SEQSYN_U.INP ./unpacked/fr_sync_U/Seqsync_U.inp - -echo "The ETSI test vectors for GSM 06.10 should now be correctly laid out in the" -echo "gsm0610 directory" diff --git a/libs/spandsp/unpack_v56ter_data.sh b/libs/spandsp/unpack_v56ter_data.sh deleted file mode 100755 index 28b8276679..0000000000 --- a/libs/spandsp/unpack_v56ter_data.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -# -# SpanDSP - a series of DSP components for telephony -# -# unpack_v56ter_data.sh -# -# 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 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. - -ITUDATA="../../../T-REC-V.56ter-199608-I!!ZPF-E.zip" - -cd test-data/itu -if [ -d v56ter ] -then - cd v56ter -else - mkdir v56ter - RETVAL=$? - if [ $RETVAL != 0 ] - then - echo Cannot create test-data/itu/v56ter! - exit $RETVAL - fi - cd v56ter -fi - -rm -rf software -rm -rf *.TST -unzip ${ITUDATA} >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ITU test vectors for V.56ter! - exit $RETVAL -fi -#rm ${ITUDATA} -unzip software/V56ter/V56tere/Software.zip >/dev/null -RETVAL=$? -if [ $RETVAL != 0 ] -then - echo Cannot unpack the ITU test vectors for V.56ter! - exit $RETVAL -fi -mv ./software/V56ter/V56tere/*.TST . -chmod 644 *.TST -rm -rf software -echo The ITU test vectors for V.56ter should now be in the v56ter directory diff --git a/libs/spandsp/wrapper.xsl b/libs/spandsp/wrapper.xsl deleted file mode 100644 index 2f432262b3..0000000000 --- a/libs/spandsp/wrapper.xsl +++ /dev/null @@ -1,5 +0,0 @@ - - - css.css - diff --git a/libs/spandsp/yum-prepare.sh b/libs/spandsp/yum-prepare.sh deleted file mode 100644 index bcdb01e8cb..0000000000 --- a/libs/spandsp/yum-prepare.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# 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 \ - autoconf \ - automake \ - m4 \ - netpbm \ - netpbm-progs diff --git a/libs/spandsp/src/libtiff.2017.vcxproj b/libs/win32/libtiff/libtiff.2017.vcxproj similarity index 100% rename from libs/spandsp/src/libtiff.2017.vcxproj rename to libs/win32/libtiff/libtiff.2017.vcxproj diff --git a/libs/win32/spandsp/libspandsp.2017.vcxproj b/libs/win32/spandsp/libspandsp.2017.vcxproj new file mode 100644 index 0000000000..6a3d8012d0 --- /dev/null +++ b/libs/win32/spandsp/libspandsp.2017.vcxproj @@ -0,0 +1,471 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + libspandsp + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} + libspandsp + Win32Proj + + + + DynamicLibrary + Unicode + true + $(DefaultPlatformToolset) + + + DynamicLibrary + Unicode + $(DefaultPlatformToolset) + + + DynamicLibrary + Unicode + true + $(DefaultPlatformToolset) + + + DynamicLibrary + Unicode + $(DefaultPlatformToolset) + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + true + false + true + false + + + + $(IntDir)BuildLog $(ProjectName).htm + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + CompileAsC + 4127;4324;4267;4306;%(DisableSpecificWarnings) + + + true + Windows + false + MachineX86 + + + + + $(IntDir)BuildLog $(ProjectName).htm + + + .;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + 4127;4324;4267;4306;%(DisableSpecificWarnings) + + + true + Windows + true + true + false + MachineX86 + + + + + $(IntDir)BuildLog $(ProjectName).htm + + + Disabled + .;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level4 + CompileAsC + 4127;4324;4267;4306;%(DisableSpecificWarnings) + + + true + Windows + false + MachineX64 + + + + + $(IntDir)BuildLog $(ProjectName).htm + + + .;.\spandsp;.\msvc;..\..\jpeg-8d;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBSPANDSP_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + Level4 + 4127;4324;4267;4306;%(DisableSpecificWarnings) + + + true + Windows + true + true + false + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" + $(ProjectDir)%(Filename)%(Extension);%(Outputs) + Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" + $(ProjectDir)%(Filename)%(Extension);%(Outputs) + Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" + $(ProjectDir)%(Filename)%(Extension);%(Outputs) + Copying %(FullPath) to $(ProjectDir)%(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)%(Filename)%(Extension)" + $(ProjectDir)%(Filename)%(Extension);%(Outputs) + + + + + {019dbd2a-273d-4ba4-bf86-b5efe2ed76b1} + true + false + false + true + false + + + {401a40cd-5db4-4e34-ac68-fa99e9fac014} + false + + + {dee932ab-5911-4700-9eeb-8c7090a0a330} + false + + + {85f0cf8c-c7ab-48f6-ba19-cc94cf87f981} + + + {2386b892-35f5-46cf-a0f0-10394d2fbf9b} + + + {329a6fa0-0fcc-4435-a950-e670aefa9838} + false + + + {eddb8ab9-c53e-44c0-a620-0e86c2cbd5d5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/src/msvc/make_at_dictionary.2017.vcxproj b/libs/win32/spandsp/make_at_dictionary.2017.vcxproj similarity index 91% rename from libs/spandsp/src/msvc/make_at_dictionary.2017.vcxproj rename to libs/win32/spandsp/make_at_dictionary.2017.vcxproj index 4ec897bbf9..63c3e9fa56 100644 --- a/libs/spandsp/src/msvc/make_at_dictionary.2017.vcxproj +++ b/libs/win32/spandsp/make_at_dictionary.2017.vcxproj @@ -21,6 +21,7 @@ + @@ -40,7 +41,6 @@ Disabled - .;.\spandsp;.\msvc;.\generated;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -57,11 +57,11 @@ MachineX86 - "$(TargetPath)" >"$(ProjectDir)..\at_interpreter_dictionary.h" + "$(TargetPath)" >"..\..\spandsp\src\at_interpreter_dictionary.h" - + diff --git a/libs/spandsp/src/msvc/make_cielab_luts.2017.vcxproj b/libs/win32/spandsp/make_cielab_luts.2017.vcxproj similarity index 92% rename from libs/spandsp/src/msvc/make_cielab_luts.2017.vcxproj rename to libs/win32/spandsp/make_cielab_luts.2017.vcxproj index 146d2c65bd..737ff00f10 100644 --- a/libs/spandsp/src/msvc/make_cielab_luts.2017.vcxproj +++ b/libs/win32/spandsp/make_cielab_luts.2017.vcxproj @@ -21,6 +21,7 @@ + @@ -40,7 +41,6 @@ Disabled - .;.\spandsp;.\msvc;.\generated;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -57,11 +57,11 @@ MachineX86 - "$(TargetPath)" >"$(ProjectDir)..\cielab_luts.h" + "$(TargetPath)" >"..\..\spandsp\src\cielab_luts.h" - + diff --git a/libs/spandsp/src/msvc/make_math_fixed_tables.2017.vcxproj b/libs/win32/spandsp/make_math_fixed_tables.2017.vcxproj similarity index 91% rename from libs/spandsp/src/msvc/make_math_fixed_tables.2017.vcxproj rename to libs/win32/spandsp/make_math_fixed_tables.2017.vcxproj index 65672024e4..5e4da13f3e 100644 --- a/libs/spandsp/src/msvc/make_math_fixed_tables.2017.vcxproj +++ b/libs/win32/spandsp/make_math_fixed_tables.2017.vcxproj @@ -21,6 +21,7 @@ + @@ -40,7 +41,6 @@ Disabled - .;.\spandsp;.\msvc;.\generated;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -57,11 +57,11 @@ MachineX86 - "$(TargetPath)" >"$(ProjectDir)..\math_fixed_tables.h" + "$(TargetPath)" >"..\..\spandsp\src\math_fixed_tables.h" - + diff --git a/libs/spandsp/src/msvc/make_modem_filter.2017.vcxproj b/libs/win32/spandsp/make_modem_filter.2017.vcxproj similarity index 60% rename from libs/spandsp/src/msvc/make_modem_filter.2017.vcxproj rename to libs/win32/spandsp/make_modem_filter.2017.vcxproj index 0791ad3738..eae331a73a 100644 --- a/libs/spandsp/src/msvc/make_modem_filter.2017.vcxproj +++ b/libs/win32/spandsp/make_modem_filter.2017.vcxproj @@ -21,6 +21,7 @@ + @@ -40,7 +41,6 @@ Disabled - .;.\spandsp;.\msvc;.\generated;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -57,42 +57,42 @@ MachineX86 - "$(TargetPath)" -m V.17 -r >"$(ProjectDir)..\v17_v32bis_rx_rrc.h" -"$(TargetPath)" -m V.17 -r >"$(ProjectDir)..\v17_v32bis_rx_floating_rrc.h" + "$(TargetPath)" -m V.17 -r >"..\..\spandsp\src\v17_v32bis_rx_rrc.h" +"$(TargetPath)" -m V.17 -r >..\..\spandsp\src\v17_v32bis_rx_floating_rrc.h" -"$(TargetPath)" -m V.17 -t >"$(ProjectDir)..\v17_v32bis_tx_rrc.h" -"$(TargetPath)" -m V.17 -t >"$(ProjectDir)..\v17_v32bis_tx_floating_rrc.h" +"$(TargetPath)" -m V.17 -t >"..\..\spandsp\src\v17_v32bis_tx_rrc.h" +"$(TargetPath)" -m V.17 -t >"..\..\spandsp\src\v17_v32bis_tx_floating_rrc.h" -"$(TargetPath)" -m V.22bis1200 -r >"$(ProjectDir)..\v22bis_rx_1200_rrc.h" -"$(TargetPath)" -m V.22bis2400 -r >"$(ProjectDir)..\v22bis_rx_2400_rrc.h" -"$(TargetPath)" -m V.22bis1200 -r >"$(ProjectDir)..\v22bis_rx_1200_floating_rrc.h" -"$(TargetPath)" -m V.22bis2400 -r >"$(ProjectDir)..\v22bis_rx_2400_floating_rrc.h" -"$(TargetPath)" -m V.22bis -t >"$(ProjectDir)..\v22bis_tx_rrc.h" -"$(TargetPath)" -m V.22bis -t >"$(ProjectDir)..\v22bis_tx_floating_rrc.h" +"$(TargetPath)" -m V.22bis1200 -r >"..\..\spandsp\src\v22bis_rx_1200_rrc.h" +"$(TargetPath)" -m V.22bis2400 -r >"..\..\spandsp\src\v22bis_rx_2400_rrc.h" +"$(TargetPath)" -m V.22bis1200 -r >"..\..\spandsp\src\v22bis_rx_1200_floating_rrc.h" +"$(TargetPath)" -m V.22bis2400 -r >"..\..\spandsp\src\v22bis_rx_2400_floating_rrc.h" +"$(TargetPath)" -m V.22bis -t >"..\..\spandsp\src\v22bis_tx_rrc.h" +"$(TargetPath)" -m V.22bis -t >"..\..\spandsp\src\v22bis_tx_floating_rrc.h" -"$(TargetPath)" -m V.27ter2400 -r >"$(ProjectDir)..\v27ter_rx_2400_rrc.h" -"$(TargetPath)" -m V.27ter4800 -r >"$(ProjectDir)..\v27ter_rx_4800_rrc.h" -"$(TargetPath)" -m V.27ter2400 -r >"$(ProjectDir)..\v27ter_rx_2400_floating_rrc.h" -"$(TargetPath)" -m V.27ter4800 -r >"$(ProjectDir)..\v27ter_rx_4800_floating_rrc.h" -"$(TargetPath)" -m V.27ter2400 -t >"$(ProjectDir)..\v27ter_tx_2400_rrc.h" -"$(TargetPath)" -m V.27ter4800 -t >"$(ProjectDir)..\v27ter_tx_4800_rrc.h" -"$(TargetPath)" -m V.27ter2400 -t >"$(ProjectDir)..\v27ter_tx_2400_floating_rrc.h" -"$(TargetPath)" -m V.27ter4800 -t >"$(ProjectDir)..\v27ter_tx_4800_floating_rrc.h" +"$(TargetPath)" -m V.27ter2400 -r >"..\..\spandsp\src\v27ter_rx_2400_rrc.h" +"$(TargetPath)" -m V.27ter4800 -r >"..\..\spandsp\src\v27ter_rx_4800_rrc.h" +"$(TargetPath)" -m V.27ter2400 -r >"..\..\spandsp\src\v27ter_rx_2400_floating_rrc.h" +"$(TargetPath)" -m V.27ter4800 -r >"..\..\spandsp\src\v27ter_rx_4800_floating_rrc.h" +"$(TargetPath)" -m V.27ter2400 -t >"..\..\spandsp\src\v27ter_tx_2400_rrc.h" +"$(TargetPath)" -m V.27ter4800 -t >"..\..\spandsp\src\v27ter_tx_4800_rrc.h" +"$(TargetPath)" -m V.27ter2400 -t >"..\..\spandsp\src\v27ter_tx_2400_floating_rrc.h" +"$(TargetPath)" -m V.27ter4800 -t >"..\..\spandsp\src\v27ter_tx_4800_floating_rrc.h" -"$(TargetPath)" -m V.29 -r >"$(ProjectDir)..\v29rx_rrc.h" -"$(TargetPath)" -m V.29 -r >"$(ProjectDir)..\v29rx_floating_rrc.h" -"$(TargetPath)" -m V.29 -t >"$(ProjectDir)..\v29tx_rrc.h" -"$(TargetPath)" -m V.29 -t >"$(ProjectDir)..\v29tx_floating_rrc.h" +"$(TargetPath)" -m V.29 -r >"..\..\spandsp\src\v29rx_rrc.h" +"$(TargetPath)" -m V.29 -r >"..\..\spandsp\src\v29rx_floating_rrc.h" +"$(TargetPath)" -m V.29 -t >"..\..\spandsp\src\v29tx_rrc.h" +"$(TargetPath)" -m V.29 -t >"..\..\spandsp\src\v29tx_floating_rrc.h" - - - + + + - + diff --git a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2017.vcxproj b/libs/win32/spandsp/make_t43_gray_code_tables.2017.vcxproj similarity index 91% rename from libs/spandsp/src/msvc/make_t43_gray_code_tables.2017.vcxproj rename to libs/win32/spandsp/make_t43_gray_code_tables.2017.vcxproj index 515991c7df..867f3d85df 100644 --- a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2017.vcxproj +++ b/libs/win32/spandsp/make_t43_gray_code_tables.2017.vcxproj @@ -21,6 +21,7 @@ + @@ -40,7 +41,6 @@ Disabled - .;.\spandsp;.\msvc;.\generated;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) true EnableFastChecks @@ -57,11 +57,11 @@ MachineX86 - "$(TargetPath)" >"$(ProjectDir)..\t43_gray_code_tables.h" + "$(TargetPath)" >"..\..\spandsp\src\t43_gray_code_tables.h" - + diff --git a/src/mod/applications/mod_spandsp/Makefile.am b/src/mod/applications/mod_spandsp/Makefile.am index 6ac1054370..61ae45a416 100644 --- a/src/mod/applications/mod_spandsp/Makefile.am +++ b/src/mod/applications/mod_spandsp/Makefile.am @@ -1,17 +1,9 @@ include $(top_srcdir)/build/modmake.rulesam MODNAME=mod_spandsp -SPANDSP_DIR=$(switch_srcdir)/libs/spandsp -SPANDSP_BUILDDIR=$(switch_builddir)/libs/spandsp -SPANDSP_LA=$(SPANDSP_BUILDDIR)/src/libspandsp.la - mod_LTLIBRARIES = mod_spandsp.la mod_spandsp_la_SOURCES = mod_spandsp.c udptl.c mod_spandsp_fax.c mod_spandsp_dsp.c mod_spandsp_codecs.c mod_spandsp_modem.c mod_spandsp_la_CFLAGS = $(AM_CFLAGS) -mod_spandsp_la_CPPFLAGS = -I$(SPANDSP_DIR)/src -I$(SPANDSP_BUILDDIR)/src -I. -mod_spandsp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(SPANDSP_LA_JBIG) $(SPANDSP_LA_LZMA) -ljpeg -lz -ltiff +mod_spandsp_la_CPPFLAGS = $(SPANDSL_CFLAGS) -I. +mod_spandsp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LIBS) -ljpeg -lz -ltiff mod_spandsp_la_LDFLAGS = -avoid-version -module -no-undefined -shared - -$(SPANDSP_LA): $(SPANDSP_DIR) $(SPANDSP_DIR)/.update - cd $(SPANDSP_BUILDDIR) && $(MAKE) CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" - $(TOUCH_TARGET) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.2017.vcxproj b/src/mod/applications/mod_spandsp/mod_spandsp.2017.vcxproj index 3702da837f..0802291b90 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.2017.vcxproj +++ b/src/mod/applications/mod_spandsp/mod_spandsp.2017.vcxproj @@ -1,183 +1,184 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mod_spandsp - {1E21AFE0-6FDB-41D2-942D-863607C24B91} - mod_spandsp - Win32Proj - - - - DynamicLibrary - NotSet - $(DefaultPlatformToolset) - - - DynamicLibrary - NotSet - $(DefaultPlatformToolset) - - - DynamicLibrary - NotSet - $(DefaultPlatformToolset) - - - DynamicLibrary - NotSet - $(DefaultPlatformToolset) - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - NativeMinimumRules.ruleset - false - - - NativeMinimumRules.ruleset - false - - - NativeMinimumRules.ruleset - false - - - NativeMinimumRules.ruleset - false - - - - %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) - - - 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) - false - - - ws2_32.lib;%(AdditionalDependencies) - false - - - - - - - X64 - - - %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) - - - 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) - false - - - ws2_32.lib;%(AdditionalDependencies) - false - - - MachineX64 - - - - - %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) - - - 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) - false - - - ws2_32.lib;%(AdditionalDependencies) - false - - - - - - - X64 - - - %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) - - - 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) - false - - - ws2_32.lib;%(AdditionalDependencies) - false - - - MachineX64 - - - - - - - - - - - - - - - - - {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} - false - - - {202d7a4e-760d-4d0e-afa1-d7459ced30ff} - false - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_spandsp + {1E21AFE0-6FDB-41D2-942D-863607C24B91} + mod_spandsp + Win32Proj + + + + DynamicLibrary + NotSet + $(DefaultPlatformToolset) + + + DynamicLibrary + NotSet + $(DefaultPlatformToolset) + + + DynamicLibrary + NotSet + $(DefaultPlatformToolset) + + + DynamicLibrary + NotSet + $(DefaultPlatformToolset) + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + NativeMinimumRules.ruleset + false + + + NativeMinimumRules.ruleset + false + + + NativeMinimumRules.ruleset + false + + + NativeMinimumRules.ruleset + false + + + + %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) + + + 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) + false + + + ws2_32.lib;%(AdditionalDependencies) + false + + + + + + + X64 + + + %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) + + + 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) + false + + + ws2_32.lib;%(AdditionalDependencies) + false + + + MachineX64 + + + + + %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) + + + 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) + false + + + ws2_32.lib;%(AdditionalDependencies) + false + + + + + + + X64 + + + %(RootDir)%(Directory)..\..\..\..\libs\spandsp\src\msvc;%(RootDir)%(Directory)..\..\..\..\libs\spandsp\src;%(RootDir)%(Directory)..\..\..\..\libs\jpeg-8d;%(AdditionalIncludeDirectories) + + + 4189;6031;4456;4024;4047;4324;6340;6246;6011;6387;%(DisableSpecificWarnings) + false + + + ws2_32.lib;%(AdditionalDependencies) + false + + + MachineX64 + + + + + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + \ No newline at end of file diff --git a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2017.vcxproj b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2017.vcxproj index 522785905c..17220bfcdf 100644 --- a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2017.vcxproj +++ b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2017.vcxproj @@ -66,6 +66,7 @@ + diff --git a/src/mod/endpoints/mod_skypopen/mod_skypopen.2015.vcxproj b/src/mod/endpoints/mod_skypopen/mod_skypopen.2015.vcxproj index 5298f1bf86..bb8fd5eda9 100644 --- a/src/mod/endpoints/mod_skypopen/mod_skypopen.2015.vcxproj +++ b/src/mod/endpoints/mod_skypopen/mod_skypopen.2015.vcxproj @@ -66,6 +66,7 @@ + diff --git a/w32/Console/FreeSwitchConsole.2017.vcxproj b/w32/Console/FreeSwitchConsole.2017.vcxproj index 3555b3bcc2..5e29a6f52d 100644 --- a/w32/Console/FreeSwitchConsole.2017.vcxproj +++ b/w32/Console/FreeSwitchConsole.2017.vcxproj @@ -66,6 +66,7 @@ + @@ -87,7 +88,7 @@ Disabled - %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks @@ -117,7 +118,7 @@ Disabled - %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks @@ -143,7 +144,7 @@ - %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL @@ -171,7 +172,7 @@ X64 - %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL diff --git a/w32/Library/FreeSwitchCore.2017.vcxproj b/w32/Library/FreeSwitchCore.2017.vcxproj index 2e7b2f7ce8..a21da723cc 100644 --- a/w32/Library/FreeSwitchCore.2017.vcxproj +++ b/w32/Library/FreeSwitchCore.2017.vcxproj @@ -1,119 +1,119 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - FreeSwitchCoreLib - {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} - FreeSwitchCoreLib - Win32Proj - 8.1 - - - - DynamicLibrary - MultiByte - $(DefaultPlatformToolset) - - - DynamicLibrary - MultiByte - $(DefaultPlatformToolset) - - - DynamicLibrary - MultiByte - $(DefaultPlatformToolset) - - - DynamicLibrary - MultiByte - $(DefaultPlatformToolset) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - true - $(SolutionDir)$(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - true - $(SolutionDir)$(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - false - $(SolutionDir)$(PlatformName)\$(Configuration)\ - $(PlatformName)\$(Configuration)\ - false - $(SolutionDir)$(PlatformName)\$(Configuration)\ - FreeSwitch - FreeSwitch - FreeSwitch - FreeSwitch - $(PlatformName)\$(Configuration)\ - - - AllRules.ruleset - false - - - AllRules.ruleset - false - - - AllRules.ruleset - false - - - AllRules.ruleset - false - - - - ..\..\libs\apr\include\arch\win32;%(AdditionalIncludeDirectories) - HAVE_WINSOCK2_H;%(PreprocessorDefinitions) - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + FreeSwitchCoreLib + {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} + FreeSwitchCoreLib + Win32Proj + 8.1 + + + + DynamicLibrary + MultiByte + $(DefaultPlatformToolset) + + + DynamicLibrary + MultiByte + $(DefaultPlatformToolset) + + + DynamicLibrary + MultiByte + $(DefaultPlatformToolset) + + + DynamicLibrary + MultiByte + $(DefaultPlatformToolset) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + true + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + true + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + false + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + false + $(SolutionDir)$(PlatformName)\$(Configuration)\ + FreeSwitch + FreeSwitch + FreeSwitch + FreeSwitch + $(PlatformName)\$(Configuration)\ + + + AllRules.ruleset + false + + + AllRules.ruleset + false + + + AllRules.ruleset + false + + + AllRules.ruleset + false + + + + ..\..\libs\apr\include\arch\win32;%(AdditionalIncludeDirectories) + HAVE_WINSOCK2_H;%(PreprocessorDefinitions) + + if not exist "$(OutDir)conf" xcopy "$(SolutionDir)conf\vanilla\*.*" "$(OutDir)conf\" /C /D /Y /S if not exist "$(OutDir)db" md "$(OutDir)db" if not exist "$(OutDir)log" md "$(OutDir)log" @@ -121,711 +121,711 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs if not exist "$(OutDir)images" xcopy "$(SolutionDir)images\*.*" "$(OutDir)images\" /C /D /Y /S if not exist "$(OutDir)fonts" xcopy "$(SolutionDir)fonts\*.*" "$(OutDir)fonts\" /C /D /Y /S - - - - - - - Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) - CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Create - switch.h - - - Level4 - true - ProgramDatabase - %(ForcedIncludeFiles) - false - Default - false - 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) - - - true - - - rpcrt4.lib;%(AdditionalDependencies) - $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) - %(AddModuleNamesToAssembly) - true - Windows - - - - - false - - - $(OutDir)FreeSwitchCore.lib - MachineX86 - - - - - $(SolutionDir)src\include - - - - - - X64 - - - Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) - CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Create - switch.h - - - Level4 - true - ProgramDatabase - %(ForcedIncludeFiles) - false - false - 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) - - - true - - - rpcrt4.lib;%(AdditionalDependencies) - $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) - %(AddModuleNamesToAssembly) - true - Windows - - - - - false - - - $(OutDir)FreeSwitchCore.lib - MachineX64 - - - - - - MaxSpeed - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) - CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) - MultiThreadedDLL - Create - switch.h - - - Level4 - true - ProgramDatabase - false - false - 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) - - - true - - - rpcrt4.lib;%(AdditionalDependencies) - $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) - false - Windows - true - true - false - - - $(OutDir)FreeSwitchCore.lib - MachineX86 - - - - - - X64 - - - MaxSpeed - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) - CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) - MultiThreadedDLL - Create - switch.h - - - Level4 - true - ProgramDatabase - false - false - 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) - - - true - - - rpcrt4.lib;%(AdditionalDependencies) - $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) - false - Windows - true - true - false - - - $(OutDir)FreeSwitchCore.lib - MachineX64 - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - 6385;%(DisableSpecificWarnings) - 6385;%(DisableSpecificWarnings) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 28183;6387;%(DisableSpecificWarnings) - 28183;6387;%(DisableSpecificWarnings) - 28183;6387;%(DisableSpecificWarnings) - 28183;6387;%(DisableSpecificWarnings) - - - - - NotUsing - - - NotUsing - - - - - - - - - 4389;4127;%(DisableSpecificWarnings) - 4389;4127;%(DisableSpecificWarnings) - 4389;4127;%(DisableSpecificWarnings) - 4389;4127;%(DisableSpecificWarnings) - - - - - - - - - - - - - - - - - - - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;4389;4706;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;4389;4706;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;4389;4706;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;4389;4706;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - - - - - 4100;4127;%(DisableSpecificWarnings) - _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) - - - 4100;4127;%(DisableSpecificWarnings) - - - - - - - - - 4100;%(DisableSpecificWarnings) - - - 4100;%(DisableSpecificWarnings) - - - - - - - 4100;%(DisableSpecificWarnings) - - - 4100;%(DisableSpecificWarnings) - - - - - - - - - 4100;%(DisableSpecificWarnings) - - - 4100;%(DisableSpecificWarnings) - - - - - - - 4100;%(DisableSpecificWarnings) - - - 4100;%(DisableSpecificWarnings) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Document - true - true - true - true - - - - - {89385c74-5860-4174-9caf-a39e7c48909c} - false - - - {c13cc324-0032-4492-9a30-310a6bd64ff5} - - - {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} - - - {78b079bd-9fc7-4b9e-b4a6-96da0f00248b} - - - {d6973076-9317-4ef2-a0b8-b7a18ac0713e} - - - {dce19daf-69ac-46db-b14a-39f0faa5db74} - - - {b6e22500-3db6-4e6e-8cd5-591b781d7d99} - + + + + + + + Disabled + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) + CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Create + switch.h + + + Level4 + true + ProgramDatabase + %(ForcedIncludeFiles) + false + Default + false + 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + true + + + rpcrt4.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) + %(AddModuleNamesToAssembly) + true + Windows + + + + + false + + + $(OutDir)FreeSwitchCore.lib + MachineX86 + + + + + $(SolutionDir)src\include + + + + + + X64 + + + Disabled + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) + CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Create + switch.h + + + Level4 + true + ProgramDatabase + %(ForcedIncludeFiles) + false + false + 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + true + + + rpcrt4.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) + %(AddModuleNamesToAssembly) + true + Windows + + + + + false + + + $(OutDir)FreeSwitchCore.lib + MachineX64 + + + + + + MaxSpeed + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) + CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) + MultiThreadedDLL + Create + switch.h + + + Level4 + true + ProgramDatabase + false + false + 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + true + + + rpcrt4.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) + false + Windows + true + true + false + + + $(OutDir)FreeSwitchCore.lib + MachineX86 + + + + + + X64 + + + MaxSpeed + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\sqlite-amalgamation-3080401;..\..\libs\speex-1.2rc1\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\libzrtp\include;..\..\libs\libzrtp\third_party\bgaes;..\..\libs\libzrtp\third_party\bnlib;..\..\libs\libtpl-1.5\src;..\..\libs\libtpl-1.5\src\win;..\..\libs\sofia-sip\libsofia-sip-ua\sdp;..\..\libs\sofia-sip\libsofia-sip-ua\su;..\..\libs\sofia-sip\win32;..\..\libs\libyuv\include;..\..\libs\freetype\include;..\..\libs\libpng;..\..\libs\libvpx;%(AdditionalIncludeDirectories) + CJSON_EXPORT_SYMBOLS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;ENABLE_ZRTP;TPL_NOLIB;LIBSOFIA_SIP_UA_STATIC;SWITCH_HAVE_YUV;SWITCH_HAVE_VPX;SWITCH_HAVE_PNG;SWITCH_HAVE_FREETYPE;%(PreprocessorDefinitions) + MultiThreadedDLL + Create + switch.h + + + Level4 + true + ProgramDatabase + false + false + 4706;4456;4457;4458;4459;4456;4703;4305;4306;4701;4996;4018;4389;4996;4267;4244;4127;4100;4232;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + true + + + rpcrt4.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\libs\apr\$(OutDir);$(ProjectDir)..\..\libs\sqlite\$(OutDir) DLL;$(ProjectDir)..\..\libs\apr-util\$(OutDir);$(ProjectDir)..\..\libs\apr-iconv\$(OutDir);$(ProjectDir)..\..\libs\libresample\win;$(ProjectDir)..\..\libs\srtp\$(OutDir);%(AdditionalLibraryDirectories) + false + Windows + true + true + false + + + $(OutDir)FreeSwitchCore.lib + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + 6385;%(DisableSpecificWarnings) + 6385;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 28183;6387;%(DisableSpecificWarnings) + 28183;6387;%(DisableSpecificWarnings) + 28183;6387;%(DisableSpecificWarnings) + 28183;6387;%(DisableSpecificWarnings) + + + + + NotUsing + + + NotUsing + + + + + + + + + 4389;4127;%(DisableSpecificWarnings) + 4389;4127;%(DisableSpecificWarnings) + 4389;4127;%(DisableSpecificWarnings) + 4389;4127;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + + + + + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;4389;4706;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;4389;4706;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;4389;4706;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;4389;4706;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + + + + + 4100;4127;%(DisableSpecificWarnings) + _CRT_SECURE_NO_DEPRECATE;STATICLIB;%(PreprocessorDefinitions) + + + 4100;4127;%(DisableSpecificWarnings) + + + + + + + + + 4100;%(DisableSpecificWarnings) + + + 4100;%(DisableSpecificWarnings) + + + + + + + 4100;%(DisableSpecificWarnings) + + + 4100;%(DisableSpecificWarnings) + + + + + + + + + 4100;%(DisableSpecificWarnings) + + + 4100;%(DisableSpecificWarnings) + + + + + + + 4100;%(DisableSpecificWarnings) + + + 4100;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + true + true + true + true + + + + + {89385c74-5860-4174-9caf-a39e7c48909c} + false + + + {c13cc324-0032-4492-9a30-310a6bd64ff5} + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + + + {78b079bd-9fc7-4b9e-b4a6-96da0f00248b} + + + {d6973076-9317-4ef2-a0b8-b7a18ac0713e} + + + {dce19daf-69ac-46db-b14a-39f0faa5db74} + + + {b6e22500-3db6-4e6e-8cd5-591b781d7d99} + {70a49bc2-7500-41d0-b75d-edcc5be987a0} - - {03207781-0d1c-4db3-a71d-45c608f28dbd} - false - - - {e972c52f-9e85-4d65-b19c-031e511e9db4} - - - {eef031cb-fed8-451e-a471-91ec8d4f6750} - false - - - {f057da7f-79e5-4b00-845c-ef446ef055e3} - false - - - {f6c55d93-b927-4483-bb69-15aef3dd2dff} - false - true - false - true - false - - - {6edfefd5-3596-4fa9-8eba-b331547b35a3} - false - - - - - _DEBUG - - - _WIN64;_DEBUG - _WIN64 - $(ProjectDir) - - - - - - - - + + {03207781-0d1c-4db3-a71d-45c608f28dbd} + false + + + {e972c52f-9e85-4d65-b19c-031e511e9db4} + + + {eef031cb-fed8-451e-a471-91ec8d4f6750} + false + + + {f057da7f-79e5-4b00-845c-ef446ef055e3} + false + + + {f6c55d93-b927-4483-bb69-15aef3dd2dff} + false + true + false + true + false + + + {6edfefd5-3596-4fa9-8eba-b331547b35a3} + false + + + + + _DEBUG + + + _WIN64;_DEBUG + _WIN64 + $(ProjectDir) + + + + + + + + \ No newline at end of file diff --git a/w32/download_spandsp.props b/w32/download_spandsp.props new file mode 100644 index 0000000000..39b7f2b81b --- /dev/null +++ b/w32/download_spandsp.props @@ -0,0 +1,41 @@ + + + + + + + true + + + + + + + + + diff --git a/w32/spandsp-version.props b/w32/spandsp-version.props new file mode 100644 index 0000000000..7d9cd1cc59 --- /dev/null +++ b/w32/spandsp-version.props @@ -0,0 +1,19 @@ + + + + + + + master + + + true + + + + + + $(SpandspVersion) + + + \ No newline at end of file diff --git a/w32/spandsp.props b/w32/spandsp.props new file mode 100644 index 0000000000..f8cddb378e --- /dev/null +++ b/w32/spandsp.props @@ -0,0 +1,15 @@ + + + + + + + + $(SolutionDir)libs\spandsp + + + + $(SpandspLibDir)\src;$(SpandspLibDir)\src\spandsp;$(SpandspLibDir)\src\msvc;$(SpandspLibDir)\src\generated;%(AdditionalIncludeDirectories) + + + \ No newline at end of file

){A3$)m+bkp zNB3VsV-%Wx1m&`l202ZAELAJ5C9oCtitzto4*4rOBxKP#>KXi_I|#RqLmz~H zN?hyo*V23P*Ac|A`D+=8IC2^;?e}W7t?c&($Q|^zx4;vM&pGg)Ca#~Lzaks_IUdg8 zLfX^PK(oxq1D8E#<<+JKfM~D8s+>b!;~Dc;n7<5H;Mf-uWY;)<$n0`jr;C^~(K>$mgO}hBF$4_yaD^wXF(HJyCsd*D-u1xs zeH!#__&5CDt|Qa>E;3!@Bk^cDL9*%bGQ@4946emsOKq@LlxCxMb=})TjQUsfKOh?K z^E%)lxMl|}I&}1`#>2rCT;oi17<=F%YxO(eei%T!GXO6((}K}7AufPz9uU{|wxhpB zu)4+#y|*&uuhqh-N5(gW3n_zmH_dTvAbUnc+~ZB{}yb&W$kpOJ`+o_T#ZZYYNXI>8nZx!1D>92hTB_du9jKisV5NPA}z6h zgvas%!^^@&DI?%kL_y7kFDgt^#yY*s!&vsDO&sIsM%OfsdzMfgpU5`LeCnr z#Gxs=p<$00qL*h&TG0}Svr7E>JvST2o6<|Pi+!wVTy(OzWDf^dXH^wrDkhzcUN96h z`%2sfm{->!>H$=2xHP%2yb_nT)Tknj#F2|Hjp7sD9%1_mc?wBn5Bnr`y{U2@PauuH zp9iB&NoW-DAqzffI2<#}=_o!zx)rT+AI6ntW$6EDcX_win*O=Vl=(&+u4OO74iOW2 zUOHr&OUsm4yiwQZ5?zep6Di}vV~VRd!YxX=O+6ermc*bXl>`+x9ZpH{t4P>67_jlt zOifIwc(qNri<$Jf4#Gp03S5d3W72Ml>$w2DaScKHo&(nWLExE5KDF+tmO+*6Zpxt9 z{}VfeGJHwNlxpmd=o?IGH{gtcput2xFl|5H(lt4GroGFh_` zu0I~8NJm#_v%2ap;?l}L_^F#7qQf!t(n1P)Ur5mBV~R60b~4b6?oojuOWWX3SHX2{ zZXbMwFGR(gXgJsvbk(Ao9WStu;<{vq-sgC1oWu4i@;&iX9NB1O|T=+&>JfS@U)f@=g^Pw|JI(NXEI zEAH{Q+HC-h@ALASYla1`h`%b1o+-C4k%WXf{-i~SMb7hu~C3aV03L z$K5mhK%B)kp)h}4c8|xU4iNt$bGEj?N?drpmO}9m=@#}O?IRRj7K{NDxL##D?7ssx z=P&pZEyF%hw*Ia|opIQ<&eIP4OZ~&{D`U03eGlcoRJUT8|0Pq;_b&_#DYTe7@R=vD zUg0m4>OPX)yez!MWaThyx-laW&5GIg}xAh%IO#Ts>wR@S2g~;waT@ z&fbtsRonekQ@%q2kq7V6Kl)HX^r}x#h%0dIVT{dity1DOGGdzH)I)dp%Mkl?P1z3P z_qQEOf^voy$E9&2)}*H`wPurEEGT@xz*TO}U?fI@E;mmj&0k9{VQuKe$N}sQJ+D2; zl|H>Thb!1aqNe^i=arolqtb1nB{e>~m!8lJ7ki&gZN$dI-(5wa-uzXm1TOIx^1|LG z;yHt7oq)#-8VLb$HF^VR;(f4D(Z3o!Ho@o|lryA9 zkTaSO3CKz2uM|!Sx6$fxvoeD#`ok0k*Y5=8{S|}`Rd_i9%Wxqa#2(3a|0o5g89I7+ zSeX;oq11Z~P2p;O8R6u151iDnhkcwjW@sT?x<|17#la)oc?TA5Hf_AliVZs~GTPit zXZ!`7QMd(Ppnp-JjKmRc(@A<1X)E)tx736LDSQp#h917hYY2~QoPpHP|21o%%vo9p zmlB)5gsZiMI<06{D@*OOqWJhoisyc;t&vYM0sRXIj;1~f2Qejg2@Gq5oVqTT3>O<` z>)iurW0v{6>t*rrA^X>_u;I+mLb#N(&1M({=8wD=O!o_K|kRBFdermaVmmU7fi)#eiDc^&2bD0*$HCMnXgLyqpnS3r;jHYoi zRSZ0nfb&;r)tRV|HQ+zi(jH$JaD|@)u2E5yq>w&>(0g27uII~P=y9ow_}E@bD8f~t zgupTTiFV*|;$e9tF_f7E(oAbzmzKTRlX@^^(g1C%C0SE z%g8=QAg~-m^hnq>?2kWrLlQ{DC;&ooV&~!ZzPUN zFzs1V7AzgCWJoG&BQ}2y2vrVT|T*Hy$LU>GE z&1XBaxY(LvKOs1?z$;KBINH2)d^C2D1DI)~yEFz!i@bk`D`phm#K0SLxB!V#>PlSk zJ%&eAHyx@t`3kshK>}`xwWfanTuwC`AiTudfl#sacRk~2ml2B>X(Eh*J}%U`Oijp5 z5?VmG8cT_%b{#h_*`pi=Q6V>ElQ+#S9 z`#7HH03BK#6^6@(@DZHgq3piq5W^hp^okFavp_fL@2A?$Gkdnv54asjv=_7^Ii z945GJz2T8kFA3v}^qVOdmn(TY{9Rn0-SO$^0i>)Qc7osnUk@n=xAm?FJVwygdpKP~ zab4PavVyEJpZZsE-AobYR)$TC=incNap7p&f!)G_yz+m|md3DpMjq#%`h5ou?`0GV z7yT7PDRq2IAK!)8?!eQzzu?5A*JgZ18ddVZW6t{5cOmzZtbeW3OGB;I;GT?P;X3Xk z$OHaL*%;Alq7+q%ZhaPYyL*%%induA!|E9!8r#|<@X@7Ag&o!unJ}majp(|gHes1? zO`A^`(Z8gGzQ^s!g0faygg-E*BaTp4e=yplv{ z6dSG>70LP+^t1jdSK4`|N1r#$AgJvV5^#WJ$ z6%-6yj;;f%;<|=lxCQWfStvdzaP{>}D8dt_5Am0^!>@W2B8u+1tR33tBczP4d*GU4 z-au1Cyyyb|L*$w0aG-23TlfGh@J~D7y6+)Y+95g-eyR*y5ltPMzu2XdAjU2r|1o3u zMkj%S#m%?Fc6$}tkpmNDKiPm2qkbn>Hu$VV{i`uNgeV&E-x8jQ?AI{r{SW8`-*>>Z z?NL|-7d;vAA9{s1AqB$KYo-VXmyrAzb)NCp0aJ;Xv)!gRO2|d;rzno?(0;)qUCgVu zpW1@Ix+SjX&WJ0tmv}=57!U4&J9crsj#|ML?m-!&eV~`&2zS5gG2$;dRE)g>xcm&R zz1jX{tJe{7W)!7a&Zu4ZYy1wB?WNnm)h}E-y719(@p`SVu-W@{h~2_tf*Y$+!c~)es2l|!u2HXD1F;gWtLPw|C0*|=j=9ulU&6=My zZUn-`JVwzL&X&Dhwlj>Wz=ahWaCu9J`Rk2LTJRJdcJngKU#KB)u}xq#1twCT<}1a9 zEAp~EhR57r_&R>*gn0^OexJhhG*k2nd(nhJQFI5Vh-=WwxDj#%{h8@|z|}qUN{4Uj zPT$I;1yA9qm6s9hIb@7pQhC}TzUNKxFD44Pt#NZ-r z*hQ~wz{zsADJh2D&)`xYZlih5_-p3=OPNo}dSw;19rCDC*-lsKFS}pvvB)8D4SA1Y zuP9GF!pA_A-7hmucE3zf8%Rx=MDC`}lrbAK?o*sp$i({;yRTec^_g;XW?WeTI7Qc8 z8F-|`Hy|2XKrC}$j)bdexDX|3R&GhD=x7~faRqO&D^_p~*hX|G(y;e+m~uQVtx@D$ zSa7G!5duv(;s0XLPfwoUSO;?_S^g)hd&khNwzG)pX+T$?)fE({1+K_t+K&fUafwq2 zlRN%Y>5ypo#DsGXxQMZB7GaYV&F*i^yxf+h`1nu#)8qQME4>)q1c}@pZ?*M4A-4F?_F2ck|NNn*|ad_29tL<@}^h_lOpoXITJO*~qi; zFmxy-VM&_AD1Z)eOg&hP0SZI911^q&(eJ{Gac4WldXaX}NEvY-Cg4in_Inw4m@pjX zWVS-+dpC zY3n9mii$h?h&u2P^bB7Cd;nIL3Tv5eeJ1L@_L!y|r z8xVqU{rojp6mJ$Fszc>J{-zHqvBl^*t|g> zUol)z2KJr<>>adz?<8DW|Eu(f{)$r1qz;U>uunI9_N^Yxw4Jg?gZ+nZIz$z;0IoIN zLbBxkI7;&p4A&$N+L`{s!qnl-Huwu;9pcxPVBq-ZKBD?;hpJ=z^p>0P7hy;Cf0mFW z5UwU0ygkO?)r0mJuKR@n*6mMFw9SYZPJ&$Xav;Zz;msJNZZlX9N&(rMO z5wym*MnCv<;=1mb0Q43g={3+)u5B6JV~Pln1OQ9@C)0)E*(Q{98eJow2x z*oD7;kYa=)E-Bxb{s7v77RHqz>+r#TnwLN;s{iB)o+lf8v-A+S-rI3m#DC34m-tsi zz;&Nfnan)a)3|ax)O)S=KY=aVAj^#ttDoUYv5rcC&K|P#ndS>Yxz0my0bD9GaLn{B zZDo}3Gz0`A?E|R4ofod`DLx{X_#jpO3hy5$P_VqU-{h2C`b(cOtoq9?N>}N1It6?3 z7jHIO6B<~`+p`Pdg>fag#9)2SUz&Rmfu4-YV_G53RgW6)b5ImDHEz&f=wFQQ*PLt;^0}%iILxSnev_4zOVqUcTukOg8t}*Q~@y7&{n|G z=mqyDh8}_Q4j10M4lW2woh0|yvB1*I!<`X$=)eMxBXSP5sq`-@gY{LgA zJ#g_=YyE4s=)#>t#Bbnu_A@_$c)PizF5E*fUK&Fb+5J}H5lE%KJG~_H*ArK6pkmt9 z{h8;Ua;O-B_M(>78*%H02#Yif1&)x{sZh8-287-|aUG;CQ*PhrGeJ&^;8L9B4^hTwuR!YUG+?G{bfc8}4d5)PtWl|Zth8J%xV6fzWYD-FW$Xz)+)B}eJRo(* z8fu;TMS(IkuE@2O0!|RS`Y2B97?qHbUgX2WrJ;JjA;PzHi>WBGGvUH~S`;uRsG(@* zK2CLFeByejgA*=x5WNbojPYq+e{8w763?(6OMlWH+cUz=R_TnmPPmX=H7>wdSX}?A zHwza%vl4$Mu{oP7ooR+=_1A2f)e!wLPdk+b#C+V3DSSqMJ-Rj=-REgn%b|Jgk2Sn7 zt|_V$rJnq+Ppa8T{(9ljxaL~ZNhR8h{BR7{Rga`I;fi1KD6mC{Mq{5#`ZkaP`Xs)o zuLVVXo-RLg$j0(D5BBh!1T=HYft7MWHW>t~m}~UB3u7W^g5w|9N>yR7v*EhQk+nNa zSqjZIW?0nXJS@_Cc_wZUm(^9hJ2Ex7aM^u76AV?`pm4h8>68hz*Nyp1fj+Iu8A79w zl=fhh2}KLwvR`0tAX}`B%mIhKIO6zP@z-lA7A#6Jt{Z8YY^F8;q||$AzDkKdKM#5g z_5uU$Ad@&RXZ}hU);h|p(WV__p;&#oxEj+f;xAje50ELoxeq>|Ra=|K5KCOP@PVp| z3o@qU&_S#I#31%7Xl%Z+ppS9dN0~ERN{R^Fs)41Hf`lyl4>2gk-Ut;gtq9^Hfe6IYe-sMEd=rrR|meiI8^cQTEVj)Un4Wn;@mu*0aSWQ%E%u_-7(5d0F zntI&Ghn`vWk(I0+a$g|pOgIylUWmZ2zC1+TQgS&KY<%~NjG|Key?*9>QD_&W4Wu7_ zK+{i{b0u=%3|6QUcy>azp_24ZRf6U+G~r8BfA=?7?{!E6_PQQdmFM*mF+v#`E?w!( z9(4UYBDnhJe+8LV77OoP{YDXY7J(%Vk36`pre_&;2UC{Tp#$;%j7kk8b3}tU!q>=- zQPEf{%??|Qexj!TuZKWR!lgjSed`LY)n8pjScM84m!Kbo=&y0#gA13wD{al8EVaYy z>ur8)SmbKM6*HG^EQYt+7dlXi!bLdm8(y(XSjTRr3@Ft>V(~w0O6VGfkR^^q*Ye&{H7&?DAN6xN&Lh? z1(yv@YcZ5CB5=P*es&_Rcyy3v{%XfGA^-1Rg_aVeYG5)#YxKF^Dy-$coEQ-o65!B& zMsgyqt(1vK8euB_;_imvGpP znNr&%*1&=xK4y8*55SU>aACki6e)BGxLm_vfL9N}w;h;pbzY=+7P_QN!j&FEUgtEV zN8%M+>N+jne#lkhDf!hO?RlesC-$XE?E=m)gL~Jt6 z?h*JUh6Sc`i()?kYxcoLyZ+&EL(gFm3HQohdh~B$wL^VlaV2yp^UVFLJ7s}nhO2uF zu{)8{lauUsZItY$niA##9L<p2 z9#d&OfA)5$RYHbqKSjy3zulCv2^p0a4%j*}8mC%=BQzu$jq7^jHAprXJ_H-lO!;~q zqNtpgpK`;LXtIc)(Rm)Ca7o$y;7{@>44zZ_Cx@lxu@bM2`xJ-FtWE5}0$$Rnf{U#q zBjPfWf3?ljH2fxNbUtxSAITpAb3QmWF)xRPp;svM`Y z>%sYUSWP=8Yi*!DYY{`Xq>RppE6;wyc|lw!lyFv+9$sXb|8v4swZ|E8RomfewLA=M zaXO<&6f!;&@na5@BiZRL)SY^a8!;2d`UeklLqf~;vDfm_4!H^pl029X_YC(-6pzHpUK!L;7Mz|T^N-kwA!3@+oq3;}L404L*&P$nqh$37aEnkMt3P(G%W&34@d8s!)Pl1!M z`KR?VB*R6e{dY2}Ehn^&JrZPcQLKg6C6iN>#I=C79irDLhN%NsO7ZM_DGT6|MFtzF zPW%q7zQ!gu&?^pOkFY57*X0x;+$+Z~T!mmOunr{n3o(Z4FPS7rs8wxwztLH`gzzv0 z6ScHzSDOez4;4MD{|phO|CNe^Qk(WIt;i8;v?#9rIxb?rg502M23H*T0}m$3Hd^E_ zR3v_zxcXzp5f@%)a#=;f+Xx%3CJ=$ZKXdC6gc6s!v#pj4mq&Db9Xx`sX(k5+!P-M; z2u5s6r=%!F!sYcIaeW)&Mg+EUh1x?8Cdw8%R;))8c^2yS)fAk#IzPv~4J{JG9fUJn zZHP*6<&^|NoPvq$=S6)Bc$|2|Tixm&M{TjiOpP&1 z;>$z^R{unW0i#9y^(wOvSNsZVF9hQ$PZeAURcT6GHe7Z+ur(M-9bOf6@Yj>HP-*M6 z3j>6s6ik%#9L@q~3XhY9CL5m&7cYN7Ez%N!FXAuRW}OA^6=25f*xKAIimVFV>24A1 zI@DO7Zf!6P$DOs~!FXI_KYAh_)26hg4n_!4-DtEG}Z;~6LN;KH?{ z+uG7!iDm>#1ipyB)Y{gW>0p}Xooa;eqj81)&EisRN=wUN-J2;J4veG!;$`CqV}s8u z{RX(&slqmH3{wTjJPyOfQ1&Gp59xJTfI86v{?gr_`d9Z~-*lP3baxm&5ag`L>M5LD zP4X~t+5a2UPRWQiwO2!j>{KFq`@#>e-krs@fWNHtb(Aq& zAx6W(uLkH}y+Z#mMMrveoH9nZ?oJ?$$Q+-AnZE{Xq9l9~i$KbDX#N^0Qp|&^B0p1U zhg1e_N1oFH{<4d&Bj@l{E;U#=Y$P0kd&9^=sVylw*4~AbZK$J{$&}HOt)_;0ywCT2T zJd6$#gbP~0UnQWDI=MpHW3_W>43;4_0;RdqCFLSnE>#`K#n%nQC-e@T) zaK+O!_m}o+8i7Meooh(AB7ZW+Kfdux;899hL}Sk5iqiyUp}(+&mjD0e}x{=`f^x<->qm( zKY+rNhrf-ef)?`h>H%EmJuReHJYvZvi~0Lk9mDR;}> zc#G@*E*)URMq)paQdq;1!m;|-U;wqQ;4M=g@VL%8HG zEds6bt*%ERX4l8u8_ZLASo`!FR}p5KjCwq4ktl@~GKOsb&v#N7xU)QiYXN_$U@Kj? zEG%4Q)V#k8*BvCVoBep|Are>l3Tv4=ct-PfML{#_9q@`yV$9|f`l87Ws;d%YN#`@1 zB3%8@_G55eqDSmIJ}NkSAq}#*YVK-nEl(;+`KuBxMD?#YE#|gWo38WtVVX-H&w1Wo zR_ciuPIbZMN2SV(Oixa5CV!n=l(Z+~!jSw4(~sLaXGEVO}}w3hdaS z&vn>8OmkUIvYVUIUkL{={wEdmuOv@tXLY4V_NUpj47G7Y74>RGUU=N-Zcg&-Hs-D) z75#<*A=!zvsta91TgDQ(5?)=kzCBOfaUTA2l5ykhb5eCb902zS9S@Iw<>u*6A%JhxVTqtWYf4~K#NBGJ78_5UL5}lGVAe-aAj{aTegL`@3M5_iq*&EuL0X- z^`H6BRq+FdYx;GF>&#?}V|6m_aiTUJgGbqTb)TYNNoo@~SeG4`v31^o^RWMk(&TPh zD@f3(zV}6x^siIIti)i|e`~_v>B-aQ@|XPpQn)(A)q0H(N^0?bEOY~C?7=|7I69>< z;_bS=Gcr)eXN0}C%xK#LuHfqQJhTpnEsj|Q8|(CbZxk_{;Zl=jctP?^Z~oE(UAWfB zZTF1PMlCmCFF=n7r|$!z5uJb=LC^jLalP-rMcN0T6|lx*@)47Y`bmPbqkN96*(ReD z{OT$mpBXN7gB@!Rid%>|rk1}NHZXgHHE!6h1*45Z;%cQBlcSyO0#}cbx;yE0-6L>y z!VM%U+hH$3uF5zsTq`Un*89DNONz7NVh7K01qnp?%W%ESsFK1IV7gPhNsNaJNv#zh@S=OfH%oX2%j?E%p-(_lR!>VRt?R!AR^ z(4pX)G-x?)4D|^ns4{=qK)kjN#d!`XZAH<^t@ol7gU38Bw%8R8MjD1NATk5#i&P4i zt?^Z|_Iu;0N4#wFFfPpeW*{Va9EI<)kD9+;J4Whq+$gseA|$~C(kYyHA*Inq;B#ClHNq7$-uzX;Rc(ihydM?rp$Xx4Y!0kj;Of(V zC9W7rfJnId3B-%H!1`kcetd|St0&@O8HqM`$Q_~_3Q3s76bo&kw5sv#0XvU1f>G<}gJaDFSJ8;O?$n!?W zV>*-+IcPE9y4+t>F8wsEoCK?wmz9&s3U!_NwxW8J$oG5Wbn3JCq@3od8K#;3<2l8X z!e5mFlZyP|Vx=v8ctW&u_y?bBPV;o-B88e^uKsw=(d4T?c(|mQCsPkc|2Q<=^kXeG zKD=`4;R1h?s-mqv9RFj`Ea0!QVz$vWW=H-1*n7VpIj-zXFhar2U}LH?*)Xt9p;HwF z_}!a=cBhleY9@_dtlxJ20Rx+a2GRht=uVnOD+RHcms10lA2ed`n+8jZe%r_Gg&(Gk zmRpyu25T0h78~%349m@1E<-iIbc@C1!b*Xqiv7Ot#IMXMl2t{v-8SYR^TfI5{)qeC zbAQE+8xhHdYv!tHud0)bt}slRGT?}8v1L7>_FYi;Wht+E-x68rL9)qTO1Ba+^VSc@59b8N;gs)7OU+_MApqQZo?&3%XDWn0i3W z{MA|!aOU~_-N$HOsbfN{d{}(}uARG3T>UMu`bKH`s685lyB6Q;m;i$W4CP zVcSuSYsvuH`k87e9|6&sRcPX$(XIJ?pfKu^GY@wE(^1m-+S4i$HAAwak?d8>VTfx3 zrowuYL+md?kwkh=!^oJ# zMwE0X#w_!CfZO8_8Z@Tfra6YaR0N$oAdB~r@pv7$65)y;Kq=}pa7{c^LzZoye!BK- z_1*v?P4$X;NUz%-%pS!XeH|jQSx~CQGnryU)mZKcq-pTr{tB2P^z7z_oM6YWSH?IU zUPCPX9nZ|UJ30>-q<+tB^3E%7!way%$ggaIouM=TE;`iY<~R5`DjL!3#mXHUE*1WW zQ?fq(My(XbOjooQ14P4Rxaq#FD#=T|mrgw25Uy3`ws;4NuW*H3oTEVq6WJ>$wl-X$ zzwq0{_3n4!yu{g(*^Bv3;_Kk63g>AM_!h)TV3g52x-$YBebs@}UXk-Shg+sdGOQ+p zAJ<;1T(h*Py4maDCrEzbJ-5*-9!jlaZ^;%sU4Ih;n&EnVV^-mEkfu5O4VU&G*0{QH zz=%$)_CAM;>NJUA__J+?df0_1TD4kHI*)-%MKk6;%2Qg|V*eHA+c&|tcFXka$j&_7 zLLG_Mu0a${ci>L`1on#We_r9z;H?o}xQ3r8&t)7u-olib`E)h{zs(Ymy|NE-2Yb;e z8l1R4)Wyg+;QUQ{5m)p8`E1hAA` zd42@~alN1w)eGu32J#FjAt#CK%5*Ld%)t@q>S+YL=#gl%eF;~-U@vB7Ir`mzmm5^L z`gfqz_?6uK*jKoqY~YHot9_Np#W(hep^twYM&N3Gve(PrLkU$ubEuBhzJ@&ItHO0_ z52Cd%;hHZi8<%@ruu60zPNyF3=y1tL$)deR9$vDSzF>!kMHIAR#1#qG1zmCy>rl8H zeMFzk=iwOk8oq-BUUx_o%i<6X*ADYj52QLrX(JaUJ(EWWbEk*Oxer{egZA_jx80E}AJkj&y3?NK0Z!FJKZ5i#`41o=7S8dpXESU1c#B^^gU1 zDS(MIe@rOG0f^&WhGZua4R=C`>%)0_p^hnt{2@gH#56K%pMk^P=U^{3rT0L%?iArL ztzM{yuJU=BAY9g7_F2rDf9D!->i73%YI#g5W)Bkw7KU)0-FyMKmfi?a^q2q9)2K89 z6Ea+y_b$mE^?rcZ(Z7p-%a6dd=B#Sk7p@JSPSkyCR*F0x!(MF^dSRvg3{o1vvX5AJ zng!s9_P2*jBo2~r2@xE~ZvRu_Y7^JYgC(?lBy+}|(wal5??H+hxYp=q+1UFWw$?pl zp3-pHI1Ojit8Yrvd5rdD@10|$^dlArpJYh#PbLs^2PV40RbExb0vBK!jqjw0$?vsA zTf(I*4g-9JORsL|GPOub3V2_$1LyMcSN#;?)}DtO1AKvtE~DOPP>MVr!(O_SQrz?% znvPSPB>(p_h*PP_23ozQ{nT$%dh{DR#I=9fMOdW`^oL{+gv+iL$IvzQy{3798v`MR zWM*|ldum70;3M=K>}m=+xxKU>N~yH%9WIcQ+1FT`8swQX)~-cdmp5~G^ys~{>A_j* zMuw|&@#)`^te=<5lV2bc4e!?RsW^GRVd;rmX8;lHIyCf9sCiSR{;=WqGTXS_arYa( z;lW6A&W2;?Mh#a}?8{!YW&u~`YOm)ZSqG++o^#3zx$B=|J*=rWI#W9iEDJQfP9!&Q zohbf4K%}|yc-;B_5#mxmI_UWllCB05x?;!PK-9ohHNwJ+6O&&@(rdL=Ukb=u<^e{N zUp*Jq==u!T3c_eKZ9D?S#TDG`zU{F3QkyNg0Tjs2<8QA}>U~oR zxTnmW;Tj2-htkGnNzn|>@f}VO?WI%@Y!EbDUAnclk#6Ah*)@;h^KGiM2fW)V0#I`t zO7hzQSASa5Fnlf#6 z8EH;*`pUIliFAhR2(njlXTY2?$F_LNl`Fe8ooq69gE8HpWM5zWDR7ObLXjknioe1< zEcthwj4dZ%ODC;|NHH{V;fg4N{g`ombPo~=hLEyXYZZdk!AvEtOb7lKEf=oBD?Ajhy3cAeXmWg_DvM>dq}Qfuh;Vrp}s=%?uT=Cb1EA*lC9!!*~KjhbMlciN?6uLW)OFcjl{>g`AZ@3Fw zve)VWVQYKYTjUj8xWsx7w_Fsxxk+_O)=L}&RJ!CkKl#|e^(nn&bVFe#Z4*B9#NVY$j)EhOKt*R1r3HPw4?%VUmk z70R6beqk?S=&eABJi}g_l6JvIpQ#=)c~bK3TNFK5e9ciqN*&lxxb|qT)!5@4Z9*&w zgOV%dryP@67NYn^DhL^^uvbc4stQa%&+6NJe2ChLc`vfdTLgy7?6odjeTJU|1iGzE zAYe59lx9@1;fNRTKM3F+K^wRd2d@`75*z_8NA^;lq=XaTrqfk2BLLD3It|GAEV$60M-EGI3E>q!FTTJrl z#doMDEXsn2%j}g$BW!+95nwDpJ;UEdrAyaY53@i8D89uz@Ckz_85JT`2ifb?5+|7{ zi=~J5P}4NMrn0OxkCoaPyTVDBAVeO(xVjwmG9=oomrRo%NJ(7Eoqf;{uF_s8Y>cY` z?v!kZf8@wigI{e4m!|@h?7jY^5_$ileX!Ssg{GD~>PAUMwr44RzFoBi`-ICsc-d!g1vZe#nAWQVtDbc}VGZ zSVoID-G#WUmxt1+1?`abD<}yatwogXXFqnf{j(?X%qgV)*tiByK4})hlLP#{_!5_P z@*Lr8Nfdho6Rx?wXD;qJ9}2fZM;mXK-lt39>BkH6LHfMid64=CRi&ommXD4rXTM=L zIMG=@hAuDQ+J1)tFW}!keVC~+T`XwGmf1?WaE?oz9f!>>q4err%ph9NsjjS>3t68@;eY^ zuet!UEuKDMAkBMYhABz7Tz@<;t zMk6RyB8mIw5Jxv03P+G=Nh6i-;I#qLloh1a`yBe3t0#_{>O=!;U)1R%Zpj+Of|jG% z(e1T!FQ5voB5Go|HXL#X9jbqIIyHqQHobWBlIQgo0;xd_AD~2IH-&RV4DBv487|hg zloN>6=v{V-kc^i40sV&F`n!OudyzmCQtQ3RnzJb6$HJw4e%uR4ExUy*Zm`PfVxu|Z zWU}2MaK`Ukg#Ufv8bP@@k_uVgNlb9UY;49cHg= zdlUXC15LTwihiEeLAbuotEiGXNzlE;(*2}kvK9hcKbYa-2DEsW=6*b`q=^f;Yv39M;^H!a zQA#6yOjE@hr4G-#q8!euKU~Cxw2)qf>zv+jQAF${9y=wEM#(yHUApHHd=o6ua!KIQ zuYHOQ`hx8Fpm$)eWOLx59OG~Gu(sDlPh7hHg(K|6(s^;)&DrZV$Gb!8VK-kx_!NJ$ zS7=te&JC}TkG@Z%WPLXP*Ikbj--T3c-Q^|X;t<%4p-k4T9wMmW;=7T}UO$5>y6A*! zLYbsTQ4H5cY^o^wmTyuA+S*sNu>`#S+%5NVs0rrGb`qwY5z}|MlsN1HKw10^)rRW7zA(>kt=l z-LC94V8~YFcre0Mdp)F<%Eug&cUD7zD|-)M@XCD0pvbL#ij5AV^SszkSP$b3NQNsD zuG`3W^nki=s7ewS2033;sqPfX*&RWKiCz<~?qU6gaLHcUSdvy{foND6swdP+=efQs@Kzqy$)(}Xmz{M;#XqDqv+6J!Znh)?mp-21O9!|Kv4^eN1I4><9*>jmF_2HAP6`|a<;ZC7GTbfN3%CM2V3cU2 zdUzwJQ-v9Ohy&sh$@;2?4P0l4=3M@F2!XB}#NZS56pj9{!$9-64vsyHd?+QmX~4Wl zkKyYrhSBLV9J{N665iG94d2BCpgr}dWB3~`Z7E9D*|tX1;TjV(4CEw9UENx)?IkPP z^;a4YNQyk_>am6{?JeM9`--nEM69bz zMxX9Bns38iaKNUTOlu~}>1FKb?)nOs?#nLPOEHha3|H)dD|H;T4yCxNoxLj$5XkH` zV%UYwg{q=enMmIK92sB4HM~cqR^@3g*!cy5Wn0ii8!k#9RMoDL?_E>5T9=jK) zgE^XXM)k0%fqaJZ3wvTmK6B&pLfGfxEDP|tB=!%RNW&<$hyNcoJ1052p36>7_YpU& zmI=fkk4rJCdKAn#YB*UQ(D!ivMZEQXnPl=wjmvah zwQ1Mv0=n%!Vtzh_@~M4~B~tQiG$}6VOfr()?B;XXX*9Om~i=SZ*-UclTsJ8^M?-p2yUeJE9<^_#7{F| zvD<-90+=ZFJZzI!Z8Xx5Y4;s;PL;?g1}=c zrV{D&3xr%nmTXt9?OWDB9D68j75?FXqR4}P?}xt!u7@slXF#~lPjlkxGgKgJQnHb| z#5FZfkaeMn5Ldd9-(v2LL}o9xubhxNT6&-Gf*1BW zn1VLa;noU#GM$6CtbL8+09->>(Fvp|dPH^ye|@PVx!$5%besH#WRq1e-S8M`MU{0w zv4{R3%@gc(@5s1VUe-kbmy5EWQ?VO_>%IAO=`wruQi`;XUi8;$Q4H*^&kQ}3Q!-6- zdCx3LuYopAy*|Q; z7s&dNU+N07 zoB>?tw9C?z#dPrzvT}xrzVH}(r4KiLPV*j#0HA1JHhyj70V~>Ellg{C*ydB|wTWvR zVInm$)x*|c+eN2@tFJkdo-oi{B2{#@_S5~U-$33Gy&u3cmXL6TKL9SxF}1P#5PRj1 zHcwa~{CzG$x~WxiJvND;eJmOjwnpPj~~krtFhb zjmvScz%>W16WQw)a7BSYuQ1VMHYw9oX60zN&pDL6heNp9gFgo%_J>iLLb*B&;JZvj zBwR97>gREpy=q)GevJc8Z1WA~#q&{_`qJh3>J30c}zAhojP7lf)yRHLf&7 z1-+C%a_G(Rx6yWq`v=qLd*O(Vfb0}msyi)|%!obf565t~dSKzwyWm?M zA=wHd*~=bDgo}jv#?kH7L&sY5hY*k&i&_h^>HB*SMQN}jLkbt2%59st((doL0@v!R zGkDeazho~p&tgJAkJ z?F*u&tnD}HC7SX+lE|*Vh~22y$I&h}xz`ylVLk&s4PYWoX=#1XNE}QRGMn6iI1FGN zW`DCKYp zm+ni*o5c$<071-ygD@1)&S+cE1X+c8n zF>$qEF_bORI1Xj=Rs1$1Ga@A7d`2q|0MAWzq z#rPrW!hE3`3=XD=x^hf=9ZX|ha{$e}_urEXxLn!zpU)|K&nKB@OlA0iKe(84)HH)f zNKI)QF&1&f3?w>bt+I3$#|sPY=i?my)$NnmOOO7?TLGC^WjB>=qDL~a9-*#{#ef9Q zW%d{ap?wq-O2IC*YF9&Qbac`>kHey}5gt$TtZm$`vNY#&n4{wgZ3CC=)x_l)=Bff- z0I%(}{GAHz$gH{we{JQ}6^mZZqCDm zj*QDr%q*w3aH3d`X!MkYbONo2vr+pvuI4zl$S5CM-Lyc~m7$}yEw37d(sf^qAZe&Z zYneM8GLO85u%+FPIB+Izz_b`(nuE=a=nvO!^J%7|k+x0P))?W+nOslbX4ug=n9O(z zrCy;VTz2!89=J%`*AdLVw$72ZiHliO8|;L$5RE8U1@1AU>5svFdT-2-U5GF^uF1DO z1lqKuhZ{%7Wm!n`fYf;%Y3ql2?sxdPz19TDj;8R}9y#H{hfe7xz5b%t5o~1kLVgqF zId)LCV_)D(!leL(2q!8A^T7n7)_Z^YXoQevFLrxdTOM9bT-$4#R!yOQ8rdW5oj*fD z!i7nq<5J=bRpj$?5REdABWf5@&s ztIe58v^oIO=bitbFFcYfGLDn{PJnw3*Q*`U~ZDVDZ=-L0a^Y@HXoI^QeHlwvU=p< zZ5GA{u(VO}_GdV3D{qZ!c-s+I)hIRnUmhYQPPtJ|O!;SFx2}h9A7-z;Wd=VIB@V&H zfmt+M%<}RS=a5aBX$Tju(a|3wQ2Y@g4O$GsuwIf}>*5Yv_9}6Cs!3PzKmXr$DJr8( z`D2c`$zOmO9fIrb?)k||>Hn0Y`rwPirKfY#FZts2^Td_iRe{#=d3JlnoI&=$HD&9^ zgw#I?SGwj{{s{t!(tRAx+cF1EWaxj&t-NJ_2;CvL?)fVdl>_5Eg$$P`t}k$obY}y6 z@5O+6_;_4w;sAm`N5jRFG`{Z52a}?2s~%eJnb{Ay>{0fI3J*5dA0~I*?0C3d<*<=( zQ(I>TO9JuUiympFszglPXc-5y*PDM%jjU#-qto72E01*nagddS?wQ4*=tiNX_y3Zy zI+zVC2 z;<#RBxLCG^i@9qocJEe~x(!^tXoQF|pYI{2NDm#gwX;e#l+nKAi1Fll=sSMG(;tPH zIkaH}U%I^MFz?;)9KWE|6ZY@~CCZa<-C*r`;HgdVKNOdIY+Tk3iUQZ*0%L(%JZW3) ztIYz_tB5}4g~5~U<%f8!oo5v-QPJ z;;z7dh<|!>ia@;m4+E2JIdW2Q{YA0H#b+;~?+RC#2Ks>%(Qpk}*E{FIZhtsJKI-X< z^^~jdDT%eFN~2Uh_IQ;(x(3|##I*sg_t1TFTfGCl6ZZpf4pM37?-1yggVTz=#z>zGUzJz&ZN7HFOs3#`u?xsVjb9cdyEs+b;NKfcSSVT-XZ=+BbJpYCL+78oUqFu z-p7z@)cFElhARy?`wc&WTl71w5HR(qB;jH1UNPNs}f z#F@XYEIf{TNY;FXE1;Z)dcV0+$!F#1v;dJdUcpo?BjDb0b;jCWn#Z>2kp$FWBW-=M zej^J|5kmZvr7i;bs^TTWg?v0KC9y;D{N4>FZ37fPDo;UrHB{-qos>8arK^FfRB`kM zsczT0ro@!ZUX?cXSI)qwQLoZGKfygNsc-it^Ir9ibeU$}^C`~uHigYE1rY2^5isn-35C+Iry)S@0eL>RP8XIwJz(((P(tEV88lM z8Yg6q2B_7zmg7t52BojUr#WRYJ8>OEl*6^J!{Q-w3$Exm>es8-6CH;ehH1 zikQjO_VRr=CmQzYVZ`lioE?+us|`8H;th^c(TFUN)vaGUPo;|Lse}dPB&0DoOt~)F zxZcuwZ)Io5E^=c9iGpW-WelyoY4Ux48vqFgw)>Dvxq7q>ia!%vuKMR|VTRgNPF zw%*u7$k-3TxakSS=E+ISW@O*DRHeF2H!t0hTeP>%2+(B>*>Nom)Cle#}-@Ba2F@mRJ;*4 z*$Sm=gH_1vHEJQ`<#jqe{sk^Nqt=C@Zl}6lYxW!Tp3cAw7o<4jI|R$hdaTS$g87z2LYt`Rt|I;_rEDXB(;iKF zm2R1X6*hJO&QzU!%3zidPf-$@NB&9aIMQ*>20$Hal9c>pI_BNeXLF?*w~^cB1OF2r*lOjGylJC3**fp7CuJD#@}mSe5q!}n+; zd#R6&-2h2`zK0SlN~}sDQSTw=!!?Ii#m+q2B(6VMhdN~(zBa)qe&8Sw5NtuOW`9Vn z>ftazO2=T!{{^h4>$NV6$r4h0xJbvxC42D^Kx9GXzt1y8fvlp&`+Of>^F>$p)eTI* z<45ZVrB&RHgO8CiR@jTm1$&*k+=cQy5vK#NXoUYcb$D9Qi38k4`=fLcT-G0=CyWw@ zvn8Jkm-WF)QY;UJoP5qa_jqP~iY*f^eM#(Gbx~~XZNexR;y?@i#{TO>(`Ny;$%gE( zE<`PeN<+nB6CtQbiQm-?eRCa!+xRtfg}n+~Im@!33ph?g;YfZQL0n}UkJn(Y&R?y= zM_U6HamikX;%ciN${>6PRir(qIzjx<;dqF>j*V+q^NqKVT*CRr3$jwRhoNms4?ZHE&2w-ZFXLk~*`&Wet2 zukqvzV!!E;+7`R)H~4nx#H~Oqi0NAiLP*Z@q`SEkH#{X! z>ndxGN`;gWU|=n6=?NGkfsWtLtJ{gg6~x`7z5ak3bS+_}hzTg%^bsXNd8XXk1AFO5>)=bQ!Ab1F zMOuOBtT{xcwPW_Q4bn47#mkB((5oKel|B#~xad>T32-rb;-@(K#>}Bh5H2>F2Gx7M z6JJ$xeh4CZ>92^ZeHAQm9$ci_r|ZgYHamz*H;L# zQRI1|@fP_M&L-{Ej@3#WKzebFSC1(&k1Rnl>hciNh?qB@+i&Z%;* zOc(0;6!oDq>oGvT3N)h@&BaY&+o=Tpr66n>%dzb46ppNgI2Be3of!psF3 zq8eJiGN(S=(Zq#@8?STR(5=J+;Wf~jmR&Rpz$o5$hl0nyeI#512CsVvjdU-}U6U}t z0m2KH-2vre6vCyVOWyemxHdZhxCkL}3sHu(g5ZTqFk-!bIp6jNap|o>2s=l%_jZ-K zF_{W1j}K`&_PHa5A$98cfGM89^=eTS-MROOOQXu+xTd~Jhbt|Hi@JD?Qw6OtFJ;P| z46;Hm)Bz)z*u-ShL(pI}P9gPTy0u;`oN#c=!4`<@8c$SG78Zxp(&ymudwD>@yifPd zPj=v~xiyDKyWYhSlqz@JFAzm5WE_hECtCuSaOkm*yuEl2;wib$^chh38bU}Mog!Pb z`hCh;h#B%CApU@E6$k~)r66~dKHa3@{*eb}%q0VGWnjSNkkUR*@$fyQnXJQUWJ8Vi zK@<&l!Ys|;>qme+{n8h>&VJlQ8k(xx%_ZUD%)%CL5Ci_P2j9j&-ge-_07-9jG+eYC zf{YK~$}8(5))T3Lt9J_%fYwlz@dG4)yZ&WVP1Dq-%2kR!ETN}fJrJgU`wIkZ4Umy@ z?*doqS*~4#F?%I91B>aixFitH{if;o2LN$`F7f<|Cr%9pFL!*_!v*Yk)Epps%V^8kAV z*sF6JJ`J)vqDn>kf8oFzxDY1l)BKCL`nrs*apl5=^2D1u9*1jp;rbbYA4BQx zci?k{zQa9a4DHLqXzvV=+r&{_QE{J$85M1Ih-oeX!(evq@Pl-$K zp_u9pl_s+F`1P_QF2|FImdO)#_Alo3dls-=*?p%wm zcrf8ghhKW&x;{XwsqHm_ca&@d9>geoLR@;MMCUW!yOO=8Idg|n!NpFW9ATnY*fFKw zr&DCO@}QRKBaAHwWuIYn2+*>Zt}y6)zX63xj6P2zeU)K#iiC&x1ZV#MZv=`r95T|t z)n_X4?EuaZ+$cn2gy(#tlj99d(Kmk#{daC5CBtQ_6bOTjrbr;=+}KEq+q%$;tn32x z8+;#;8dfq&i+~4ll^#z$?$TbuHO;ZTRrX4RYgpTBl_%2u%Qz2ZlA6E`9Wwsad}z0!L9Fx_1W9^0wpK+wVcKf`5T)Um}Yqv>}y(-1kN}>>Z28t;r*WV0LdW$!gdN){y zE>K$yu5`@P9-L_&z-xP{Ka8eS)>K!ST6Z)lM57{L>{A!Tw!p46>8B*%s}jKr@L(_X z3rj~{SZ|{a8`Scp4*rSume>5wU%|o~8DCG+j zG=JBqHRW)4C^d@>9p_`nLH~q~^f9pxs_{HZnUPfU+BguG7PLlHa6_c=OZ|eic6lp{ zsYLc?!zwu&0+p{~C8K>`N{u5^PPX7vd@;A-b$k(%jDWF(5j%PZT;h?iUG%FC`81D9%@^Hf;u{;6(XZ zw^@fhqLkj_7^$VEtb-{~aUYfFqDhrTPm<<`DaFK*Ybr5-&`Obk6F9$DzHjZsXu&DF^ODvdjp4e>{R49#LysriD~&`jt^KrZidxd*MDxIAINM zjbC;U;l$Md&wLWnb)atjf93v+na=}?ZQCO)CT!HBX$+U_HDqo&mp#tjr*sdvk{=2*oD;X0QHu1tO!jFIQRAbxO=>vTZ^fvxM^RRJcaOrPuYX){|ufIR;^h%RFAe zKiMRZ9mD02FrU*l`sO=0CL11H^+G+!;1b-LWVHE;$An)rD|YGDxYYhKCVYCtA`tc1 zk)%s>Z*w|1;&zbzum1qbPhqgm{_AiLwjIHFh$o;p-<%cE(v8m`3D-BbJkAlA9Z@b^ zTLBK?%0`d|W4d?oZ*z}HGN3)yMh<)%|DwB|K;kVmv@f+sNVeYF;&W{A2Gbj(<`rYxqjtcQ5g%sfy>cw$?R60X(=?r{Lu+!rsG zCN3@mYL{+w2i^s)aVe$wDzzjDOI_efT1?MVxldf_QULqThj0fE_lYUF_n?dpTn_03 z{0Azl8rRhtR|;?2$~*GNbIjoF&Kk04L)QrIXoDj*d^kV4S#HF%szl4~;6;LAo+98ci zUY0H3N;^zMBwXD-aJ97i%S-zylIwhb1aSNR8)C1yAoa;u=iV2-h&jwy%!X?V%DD7E z0Wa7qV+Xe3kdYU>L+-i{flIF#)|~-dm%`t0v3((r$Zb8c3D=o1aGmNgq{lzH`q6+b zafFoiuX@CZAfA|-xO7+Y%^A{CKcBcN)yaarhU@U#WF1TR_Lg@4E#lfk_`yZE-SDj922~@bW2_bvqUlP|x zESo4W*a;~Xt}bJz9A?t(n-Hy^ualhhAUE3A4l(cR#IpcPfE?P@J=UG1~>Mo%bLPZbO+0 zEqx;4inpMQn2%^PaU9D7L=V<-zu}_fl^;R5%I?*^1YEbTgv-b6jFCjbl{uuJ2G-68 z)aIPTe7*fDaP9LW!Jj-Eu1A0AQLXcUb4+Jo>m2)|1j;tfYZM!hVl_VKi)~ z@QrhFtCF`vVXqf@e0Y2K2yMeY4r92W10hiKsUp#pY&sr1Ss(vV<_cU%_o7G7Nh1RI zGf=#-=@EShmTI;7ik1#DD$_kM(I5>tPAM~U@!zPj(iv@g=78G4U;;L(vLjr!u$crz zx|1Q0sMy)<=vcvjgumGfxLk<~-Q~%tz{Ld8A&YHS1M|Y_W|#8^>s{Es$_r>pQ%79N z^56{J`_z)mUMd?VmuOIvk1iifs`)WIz@3Wq(S&xLG{f!e7pxoIV4 zG9cInE}kysEU!U1=UtpMG)c3grov>#ys%vAZBQG!(ye2DgF`|O|0MR(JPS)c&x1|+ zFzH}Ebz%9&xp`cD0xxhg%x?y;ptU{XvKpE|iaMt!Jc!u(HSp=mBn=f1;i@0Ive1T$ z^*FxmP4z5Xwae_qo8^Y<^A7@~+Fp7!Z{t;>8NGdL0N%hwduA$}zL0W$qUUP?7r*e9 zgF-X`k8c-_;;_X%S<&;u<&avNRYX@4IO3LSp5xfSH6ide&uf&?oOks}tt*h?YkS~{ z`@M1^GGI;8dT_C4A%!zsgwlwGkz8|hB;=ejZNJk6SHI&uBqNs1NeB=EvdrkI*$cBZ zEJg4fgDOGUi(ili1^i>M`0jomRuH0fajwk{WT^r7cMsu26}}LMy&dsZ^@P}xaxHUgy)Ys!1QIoIO`u65PkrkGD(?=2E!xXo|D371&^PS{9*$3DujwXY z*8M`f&b6hf)kdbd#oTIr(7-1SS?~e&NVH>}KFzuq!^ zmaPkBFC?d(!B8EWlDl7c)VagI|;g2pJ zn{H6T9^QJhfV4|ph9}|8IZgr?bt66869`7;^_q`NZm0hzB>u9 zjMR(uJS@1?;7#kdq4x)YIf^5CFF8;Vy7hiH0e)B4I`B z$Ucss>#gm5Lj0epg15U9M3!_OJ03wipriiE9KOj?=Mc z`|2_GEf0o$$}8Yw4+alh_LB8%moKE)Z+mJ;!bO%imZ-+%&3!^3uGktWJuW&WMe%rK z?dyu{mCuT}@g}dyqsy*LYsPwN4e9eQ4UOg!;w6B16E_<^jD zVcJ^S$`$x;%U;WnI>`^fMdzbYAszFe_7(4SV5&xcxH&-1lH0Q~v4^(;MB(z(Wx#>< z2Hbj7G8L}-0Y2&OzXVsv#6kLfnFa#vwdHvvsldEAo$3#*eX-)S(>}GN)yV63Y!>I! zfLkLeAT;c?IY7=*f3-~R!Tt!Max0bgJ>2JL5N`&y{t47OkfM&hZl>95j5MQHtIQ|i z3lD{eK9Lirl#y9~NL;P7O9kn4>~%agv-x3O)xLO+R^y7ulC}`X;f6~a!E0Rc zUDk}{D04+pD?0L=Mk%de>lj~;)c`p|`x_EJa9 zvryuzGdJdk@6aFz-Z?v;k79G!!pTPsTnk!JEh?VL%{FS-CO8xJ#Ui!I z6s)lhaQF$>C);G0qiHdUHG(D%?{}SINND!~ud`GY(=ZPR)*69{tdeBDaAM|D(gnNu zR637!M3)`~#(49di|jp|1L7Li>o)W~NbL8gym-;NKtvdzkvJJkZ2H@P)aJz{HkFn> znc;%6AdjOxM%<#N9*n08gExJTO2oCxz;EUb8wgnsCmL<5d~l2g(Yr|lINE1FBBxro zMw~R31o1QOo?PNb!j@_?r0U08jDI08u*W}RMB8teR#o!SCk%8lnjo4oGb9i_&3;7- z0iRdtW%RMPflyZrdW>kexV#vp0c^l5mxJOMufjbPmyFsvkMJuaFyV^0zb#T(>aHdA z(IqavosdwVRu6}Ni+uhD>{U!9cI+ww-Wg4mzAyA}7Ww8Sq`q%%FPO~Xj0U_%Epx!Z zHz>RfZTBlT=j}yY)_l1aQ@G*>`5vSe{;0752SU7f^W?Y?U7OTZ!P8eNT$!2-$94cNUb0vzPaULQ3TEb~kmR2PD4EjI%D1Q?DU3DW3Ky>N{xiH(qf^H~ zEX!xH7t&xUArD9>z5E%ayKoO{T*^sLcQNBl*u(Smc#8l^{fmzvzU094G2^eSzYB4E z3XJr^U;nAcRn#B=*K~&(QYvqut8v-uB2+~TH*4oJ;!;8}ultjSDB9$a;rcN%A!2~u zfOX=uX?zb67X2Hskjb?@|S<+&<%A1yvI9mi&9x7p9trwmHuJ+I&x#2Fdyur$M zu7d(!-QkHu!Zi-Wb(%)JQ`_ss58>uzXf!?p7H=YEq!QvW`tlYazsnaWFEwy2!$)tj zY~UJ=sGSBddqRY`p0Rz|V+A>~5O2JPgwL{-^lDt{rY?En(pBw;Y)ZsdJZds!z11xO z#f)Nj8~ySg3JdQ?oX5qovHO*EJ+!Ih48gI$p~$0WZeN|P07%4@tTBs&=?~G#ZSE_1 zGG^ozH=szir!K-nYR9yf_U(l}q%YOJQU_7=%LfiEZxH5ju|JHj!KYy_eFQl6OoWex zfC83gmp+zwLe_Ce15fLs3K*^q63P~E4QpK5%NctF(%W3(pED!M(plkRbff(C9|D)P zubooK(6E;Wuk2;Z&a>f)LQ${Mb(&_tj18|<_BumpXfRFG1#WcDf#zGTTdrK?P|+oE_L|A`IMbe@P(j~t`Z!gQWX+6AuVGA*6Q zrn|8#mFhu8!lnBbOIP7z?aNnT4A(dSm%*VA=f+s^zD(JdEM=XDb^@3!L(CwJpAlE) zkjNA)`GogaCmpnq=KK)82Wdc6yy>FkCp}2~LLG2jp|+&>n(Q?S>{8QGo56{*(I8e# z9#V^^k9H`I*v3WAic6N^;GFESnY_g*?^AJgacXp94w;)k>;$m0n}}XhynfB0UWEW} z4q`^S;=ihjmPq5lPYnaOz=i4p=~=Fqky=gh_qkO63R`=lebxR=iMXP_2Ckx4qjP$P z5G#r``o8D_?N#^w^zWl1Dz1>|#C|iJSQF;h;p|3@$7@T~vm93#xodY)kC#p!uFgkb zMSGF0Xelz=)ZSHXlM3Gwt-LB}^o;GRN^xGW{$gJDL>HEQsxQV1MkU(+T30Mg=v{#|Qsi&aA5eVN9IkBz5qZQ8W+9@7f=cY0Iw_C_9u#&=;F ztFX#f;ux%M6kX)Oup}kk$#o){V#i)}93K@n&o!+!3Cv2zn{ESg{fuw3^6fq}d-mO7Y|;2Dv_5@_nlsnAnh2#PfL9)vjO zze60R5TeKv=y7kPTV z3|wvl0&RYBN_VF-RO&AR5>l4bzJzN~PkdCA9mkC8%LQgHS}9W?%LCFd^VtmP?Avg^ z#*IWV^V$2f?qWRL%lTC(+cdwZXkRbF&4*9_2M*{EJ^AqoUqyx$R>xp^Xb<)Z$gM|8 zlj@W<>n^52SWVN%>hxtjWP!836n|*JdNQD@@mb>d_7KIEtT`+ze5fi3orTOVPmt|j za)HT~MUgIYv{1CAoeFLAc$Y6@1rYQtJuLUT`x-U;IID9vfFaTqWofoy*T=h%VR z7+WGZ3tW6DwmyEQZh{R2UN3ntg26=q3pgWgUD!tx4{z3iB>q1j8qq$g!SQE5gE(Ls zMSlpXw*_KF2*lDiHub|_!Q)E6t2`Elzo!tU(wI{!`T3$x&TIu z(iT{<_HU5f+E*NVQ}|7D8I=Aiu(#GeU|pZUt;dz>egh>E;Kh)@Y=`6WCN5=6_WByD zNZT5SQVihg4^xNp#Tvha3;j&#Rz^O4i^vSuHIJHLorMFK6?hmaJxObm%Wsp z0h0eNfHMuyzz)adz=bILS{gKav9_ed1yeX2L>^p^tZDTn@mJt}lRj!+iSI#791y5SFuDskDfJ3ISu zr%dg916QDum9>XT7{%KRH1S|+U-3u8)yNGkpLVYKDBf777zg0m?n4v_*C*poP!?)m zn%)%8s~~_Llz3KLd$iYT;(3mM%&9+YuTa@&U+}^HQGgfW<7YTd7{2Ha8@SHEiy3ca z#I>1Hj6I5J`xS^HnW8(HAx*tRYPbh=n}I~jD7y0MfEhapb@rwXHaA?%_cl{eOY0@@ zDJbBWRQs6Y&CCJU6k6*Khsa_S!5MX@6lD{_nUf=jSyGD_4b$@}^iC~XvsqCzK^NreipM%oCIDazgY&>L%k&^vBc+O%=S{ai#iElFwLznidaP`ImXuI^fOk5i`Lt(F1&MkSWK}x7gcR zOT&vBA3$uhDt0cS)--pB#J=fSXk12?0d`}DJTc9s2Cg#5fuqK+Ld*DOuN6o(F5lg~ zQsJ7<=u0;;gc4*NIkPM?l1^`XDE6rRRnSpzb<6Ry$bj`5alaWbHN?K4`cUWd z>)jNNl%^2{tJsiRtFff^77tflHw>6dxnJ&MUb{uSpugsW=?hVsqieKh`QLQlfJ8E_jrZW}?1EyIX~< zb(QMa!f1jhf#Z4{AQiY02YXFvx|-_sUf{Y=PT;EEIbxh9@rJI=sE|IWf$O5jXt#sx z$9L;<)VNXx?~$FHR)kASGy$o^+neCJX0Q(k)hXM0Z|V@}@4go>g_2jo+>aM7XW}4BqgE$})4Y>9&+{8E?JGE+RlegtZ*17;@ zxUSND0!py9f%S8}(=;G{f$RTr$n5?@C~C6xUe0UNF&GxgJi`ZwSp^ObC_VWyYm%Ac z4F_@H!9;ytvGiFFlMgs;6D8LR0qF;b!gb>JIV9J1kVxQT-!W5*ckY5KH;sD&YH6Kl zh5pEGx;sXoLFR$zK5}Q**EVwyC(I_UA>HE(Nzx_g>(UBS<3d7WV2VhJEHgT3H5Fsm&UJ*II_f->FIrOf)n&mh@iDgLaCJ}mo(k)t)gKC1bc-+hTo#V{9;p_ZWtb)6vW@#A<)L4V zyo0U-Aj=5B>Heg07bWn)$C*5|pxAJ|4tsSR6-n1e(f#^;%;#xD#XRx*9HPLEc3Y3^ zB5^FQTmjRAn~eq98dr}ZMmB^UAz*1WNqz8vu9u?#Q6rn-;yJpy699b__b>e+>fxt% zxF;LnFkX3n8?CbZ^gNV`ISO6II6lQYtWx3XDozIhOKwwgemda%bdMrQH%-i56W~hu zWw+>G$!jD|rv1JB(Ey?)g)}X93wP&U_y%kED>-oehUy{O9)i}S8`*}-pAc8F$=VU7 z$b)5OKMx$laN?^CTU>0lLgvqq+Ty^RP^vy?re}NFhVI@eXjB* z3|Ah!WMpK6lIr(GU2YWm;~dh>Ye*!#QQ}JWr@M#XqJ26JrdSGqn9hjnO`T^1Zu1LI zTo+Zq>i45%xP>cm9+B$i+P~;f54)e1fCO)d0xf7A-iGT{p7SJ>uG386A)-^jR^5jI z2WITs)Azwex}T-_M#m$!1ujRw5&lJ~v$L>_oQD+kDqJwk9Ii2Oy^#~wQc6Dt_)U$* zbXjjAd%a#Q4#?x^EZHO+)w|fU;@Cq&#MQ3rp>S!vH+2Y161^VMA@jmp-<#gfN&Is+J+ zRp+liT0uV{T#OTQOM@-=y}@Bk2&3LAl)C#vbD%>MCmU}&uq!x8VJ~{Ay3iMU9mr&_ z)hJLtKAFA#R`dC-8RD<9HW{uVb6Zo<`r+UHu^}mWH7;TH!%4yRoNyd`dRgJ@dh0=Zq@iHWlm2mRBbf zD=OyJ7w|p3jdzeo{6GRXWQpkI6|2gKlMj_G_M&=!LsWm?YrKH~qm7R$d#x}KDo#Nw zJlf;4Mbj-jj($is@B5;C*=`_B)s>O<6*d1ltzji@-Vl1a>#MF#klT}!bQ3Mzrzm#0 zGXJI94v*AayMx&8Sl5X#js8$|#$qz|Nhn!ggT2(gv`Z!q%(12l%QH2rLsE@DI_$j& zoE{?Te0Zg#E~C-UUrro)PA=#c{RZO<_X7_knLnkuPfjmHE{d!kS|TGJm}Yx~25>n2 zq_)!G0S?h7vnsjEv12vv0oU7AIW)RHS(^EJ?i7^bsppyQ3sIHaiVfu51J-?>=lic| zSqW$@_#Z=IR9%}g>#HoktZUiIiG>`GI B&6DUZhtSGva&G2iXs?SKQF(?>bD(O`t5aJADyh0{Zl zJZqV#0EGjT()q~hwj`j|37-gKPXFxu88$8-a~4U z*GZ*39!vE8!|DD6(fDs?J|JT(D{RehIFOPaPhz-K(WDjZ*C;MAYU+^F9#ctLSQkvP zFFX?A%Mh}Q4*tWp!Hi;$V;}6yZ&Pu)u7Y$5mzMKmA9tlWHcQ@l)1y@1W5xph?JUMY zx2~p-s(wCsmwtw82NDaiczcL&71Mj*n#hVhbg$`vtJN*`w^LNhsH2xeK)~X+%H|s$ zC7^xF#hbU~NA~FV$Q_KfuCk-+m}Kwa9KORm2mJA7a~yPyFnst46r$u01CGMQ{t#UP z-Td354mGZ+*7vo9)@2_pT-lmKn!B3}PqH1h>}GUf9xZ+^#Tu1^_j*Ep0W_$MIQK{KD-GovNxF;t{nu*^8mf4pQMbEV*MvQka7kNvzK}lepV1maI~68AJtPa zCEBOQHRL9#pVyq;Z=lb*bNy&2T1kSg=t?wy7E0In2XX0P_PYtaE3;h#>JF-owt0~0RRL$jA~={8|> zo8BVfiXG%c`<6o#q%WD~hq9L~xt0239IYN&hs4^{?tLvFhfLvn_iB5wVidSuujZ!# zx+UE|@sNz-+a3aOVf=zf)YwrAX7Ageli$t*Buc7>u`ddS8q!~X2qyofF9Q|FC&RT$ zQ)!mhUXB9>91rK48;9aL=X6GZpCM3hmlk1gBf~{qB3vA#qVtT=#C3=M_?x{FN3lUS ze*%Z>*~vpge+<#ykF8DbvQk^K(;-u{R~T4Y%qVtk12G0`oe|?Khqo8Q0Nmqml&m=j zw0t^XKR?Dl`Yth8X8{3OuIyp;P|61D`U?o;p;_t&@Dot-bGENHXN;QS-#O3puIxfQ zSKnx}3oN$bEPv!UVuA*8?-Ey_TV%LckCQV@Y5XSGRc=I1zo7tR4P5!mRq9F@_z~oQ z{}S&!pM-3F_%d-ssRJ&(x@I!<=;!xY>hX-Yq7l;dy;4fG_mL#@ z0e(K9-J+Lnp&nAFb(;(FO~e2Bxp-N%GQ5(`dB9OA^7}Kye2Ag0 z`0RUyEBm5aRw(BGh}Y2q-(qU)m_gzfD4moVxTeS#=n4jz={&A_6=|h7aeX>nq7aW(AfU zcbassFgx8e0J3mp)mJD9${WtM{;k0*;HRQBVaE_1xfL*K*(le@UajF zNTL$g05_pO^o8=chli~7`@+S1CEFjBDQFW;;m{5mmLIl1I;(L24zN*1OOxV#W-;IL zz{U2JUVa1a^tQuH50*ncTmu*BOJc=yYm78H99I{~efZ}^oMRs1?G2A}zOf8Q0SyeZ zx-y0Pk3uOfX#to891ULr>rqN{iL#$kCaDJJTYvliv-fr}l3dxDSlkY(f&p(mf8EjWy{zX4%|cP zO^>E5z@VVn;jO7LOAnmx0rtT(hGO4R*{ppSv#Xbem^6zO{=V6>R8^Fr(Fn;ffkD_NeIi&2pt?}?+0Ds~$EbJ$j5uWLG9D-40FZz1B zrE*Cp-n#D5b$F}g0t(*3)w);h_xF%5?d6JB!26taVvh=q<~1(o;eDT$AJSg&_b&y! znIGrSGGhOUO>og3aYY{aVY%t`)-wDXRFYb_;$GDpEa=!gzQN+iUV5nV3wj@0$&4o#tIpd*SKQ( zitTr>gYczYWcS4Fi~J`=4sC{CFRGvUXmGcW^avXpNVwED=rdel&U0-)P!ogl**FK!@M}F0jF~XzMp~-ZmOP|# zyPra<9nNyv^8}RWujWJAOS{djx=M>sWjNKmJB1hja?PXFojrw!Bc+ky+JJJ%aXu}! zpnp%eE<)-xWQ6w@Kf0|_HrQ#P|;r6Z+gV;sS^){#sIhoB3s+` zmL#Pk%wmk_#pSRa<-VFu~(;^Q0+Nwd7_A^ngL&>Iiqs_ixVql{t8 zlM7uWn%slE^e77uLYYf59t7i{TK&r& zPtriWXIL9MIT+_|qm{;9#S6YvF6&&Rr6wPe7eV#{7p2ADlv3%?Udb5D4G#yH52oh6 zn@4G{T*r{`u7|?<7vs0rhXeRkjs0iiJc_4h*6zb+s~?=rxal)=@$sM#yb z@=vkXrPw3tiD`HD0BMCQs8chi{_r;sXUI6(wRNK-4MxbR_rSFS2w%FriLvY%cNSW1 zHTIw0%pr<0aCaj>DSOcyHIKRu*$Z`jVscw|V6Uh+$672xmCtNp+GiXs_0FX8Do)#7 zV{#6X=dZttzn*-1D?^^|F=~<{;RcLYl85UKE}|NCc?}2{k?N~qjha&fnsszh^DNId zxB5slV!{@#ah?5Qj^#bZq8k1=aSa`Cxp!Dl?F%Sg-_0${}~7H z6E8le>5ACt7U?M6Vw}GZ{B|x-VfTYA_`BBwHZOOosk(`hSEdTXr1 zDXKaCz(W;!U~v(^dG%-yVC>I2T>0YV%y;2uPjsH~`$Lp8d5mC1EnGui>Y_xALO#P4 zAYXao?J9gpcTM)nnTi{}$ym5}jqwJU2#c#d3<2vyf}v9O`mKV2s0-i%m}+x-g}9KD zz6U=Z{;Wweprm5petXy0OdA|qcwdhPj49YpM$E;UHFcjX{#9UqOlWv zkVtRGmWdRF%LPb(aG>@;<&xCj&8s5K2=AYbyq-F6oT%1^C9ZX5Jr2O3^LuGN+&%6Q z7o@2FJ~?S^H3JW8V0~88>dPo;SFakv2g=Bg-d=LGl_&8uohLibfZxThn*4wPY z-FGAoXxy{pI9!nF_F?oVi%2A4w;5D*)6=I>%XhR*PKTXcM+Tae;wTpKR7Y2T^4?9xFE&FC0uSzxZbH6 ziu+*_5GH$ZG3>VY;Z@-X2)GC@t;=oe4VVkK?t5gv7Jw_Qs;TMpd{)HJzUkw z6F9Yab8_5oaKM_fd>Er#naZGFvJW45NUh>)xu>gDy{OW}`( z-(x#0D3W4Ti^Seg4sgYrULu%YVq}wvp7@CT1eDykjvCR*P^nj^SK;avlV;qAtsM#% zVY|&aBeQgmb}0&63a?S;e1Onf1GB>{CT|{Uhq1sa?qDPbxU}~mPb4MZ(TSe;Ry~MX z&~f>hl=p9%g)E7^noS68TuFdJxM-QkXXF|f)Pj>hZ{1`%=h5VBJe=?qcIV+=8SWsG zs9ABvg)-H{l&e*+Ra3$%J#qbSYwdDE-|h_SL{~y3e)Fzf6GhCEN?Y&VSFswm3F?f| z4C+}-zUF1GC%X;W=1M1#&ee&|)i+EyrO=n^B(K9i zUC^ItTwp7>lAmKdln%Hk9j4f8qG&z*IvoDB(S^f`zlXlFpHZg6_G%*j+F-5moJyzx zHkO}9!We#t68c(Wt^z0A@oODW*iONQQcr*FfR;RH$%nqff zf|X$%SGX46)}Qn4P;ZJJvTtB2cI;H6KYb69hpNe5;jWIAZW5QayX>{jIz)fth>Dw^ zk#iIG2r14lqP{iiz$OsMx?7%3O+2(M8eR5KII?m(8Xk=4x^gl2lH!Gn= zY=5@_XOS*4QvByR?Uf`AdSOVkFE zEhbbkX_@k9(Lg21ZCwpV;Zj{*%26Z4ZJi7e(eB8-6$z04YlRP)vr(Xv;dd?sWS_4> zP8>ud$C++>+hd`B(sqcp9gycuX1GsAZ*;+VT#k|`{zGaHv`W|FsceVB^&DeTYT+7t zD9f!u1lb$4Bjiz%r#r=O{Qn%F35@pxS7jawk#S(+19kD|_x^AvakWMm((Sf_^&;%h!*+XfTG z2LbM{hdhdQUb0N2Uy3D29d&81XX#jjBN{|i zS>B_=`^eQRiTD!2P2;?X>e>qMa3-Ow2y0*y`sS-_!}~N zsRXKJo!jo3rJbEr+T3@3Fw7Qn#NlF9S>3V zs#Z(zzh4Bbg=McPyis-d6rkwT**rIazxbH#Q0+Z~w?!_{0K%0}?E>T$uCcWI zLZnf$16Q~nxAAbHe>L{HLjN@&bpI;QUKur{#$I=ew@tM)UrTbNA+D}Wp;vdc z-&;OaVUEwu0>0;^cF34++k>}A&&@CA(5R{nSMyrSo2f-FV+xq{BB^z9tx4+@{s+!XR4+7ly#|I)6v_K)=M;X38FI8dSmvXT5FDi zEaJMlj%a%O*oqY3jcv0VQnaFLc#5JkaSmLpr58Zfw;xuq z>r8-apZ08Z|HWAH>)vG{q^m_tl2_{H3ulkr#9f=+16F~D-0y3b{*dapp7n)@b?a&A zvwTQg)0S!(QJt=xpw6hb;yx3XZw+4U42~h6Jw_ZwIoEo^b=)+^iswE(R{oQ^=BHos zXDozM%g-ZO??!hzM4Y)6cQ+43_%zSiqsEa>i~L3EwLoaCEs|?FhG5+7wI8fbcqgbM z$J(o5#xY7mCAFXU(DcK89kM87m15;dNxG(_jFr1?cb`?HWnEdKyfc||Ud4?A-j8E8 zO_3&?pt@$nqb}FNrS)UZ()7nq+GmVm^zH&kKgc|`6_?(At%9uX8)=VSVAb5 z4i}JwvkY(rh(LGpcRaoRfmdTD-~oES;4e1Zn$Pl;K__o zfz{g0BgbF+1Mmh{oWqCz7R#Y{5-QsvoOJ&xa3$B7%L1^zDNp9B*9*#zARfkL52%JLvQak#+(O2A>5XJB=jnxwqWEQr^mf>6JAALwy_Hcx z>JI|^dyw2F>NWnYEoy6A$it(VK9s%UVkc*&Bo2Dz3uX(r4%Sex!B98DikW9{gofUh z6a{#@_WmJ5W*idq{(Ss)Mg?h@W#GbfeFeCF^SZQTqI*SnXk7bzao=`P?JOn@s1NMn@w0g}_Z!hh4p zm-MR6unfhB%f-UOwZmxI;L;HNDY#I%?elIT6pCBxB{jI>9IDv+GQis5AOM&1p;B%T zS9B4-l~v;U+5v4h#ZQ#@KHP`IH93qc`V?HjE?IFloaX(|c00@wCBBAWBQ0Mt4_qy< z8#!>D@j1qx9&jZCjGTvXeF65`+xEy)#9G2%iE{8cMfoYajYwQ+eU z6Gtuz0ggU)7Uy0XuuYDdF$b4NXcgdMP;IaN7ts#41F|$4!NC#H9uC{ZAzVa>+2tW`IH;1?x8UT8})!eFjK=1?-;#_5-*^F?8iW z2pGH^#dm$3fJKVd_Q15`*0e*cH-5}!85p6abOF~)P`_=ndA#tlnFE_<1miDG-jg^HF4%I8Og`=-f#!tDDJY?x=7D=2ycxdc^RIL#qCbVZNICTAKYyEgmIk zJNfA0c5qbuAy{`JE*Zt19X@|QFpD%N2dQ-J7pB!tGlh{&Q?P_m zk1U#yX|hf*yGCwf4}3_as8vmv7t83QDI*zWmC!!BwbC8WHJj+_e#*sA5%BL^;c7Mr zt#kzAQUsT`%9M=k+ylxz<=4W+!X}!?RrUP)1a3@@2KFSr=iO8;|a&CYpm+v4O)m6$xyb;&JQ92C71p~yNKter` ziJ*g)Y^bP8XswMw_A1R)hKpPdCw?)2bJHB~yh)0g{orV@%Tzs7M0KX!c_CHTZ?*v19f&KEUYRxn;@ zd^g8v98hTWukxlSFi2DcIC>v+AU{Xe64xFi1LO(T=m5@;o4|S|fC};utt1dMS>Ra{ zls)a}P`4~i)W=nhoMmX)tHGsp)g<%}qP4FL5!%d2;5QQfQf1+d^m6t2i9n z7+hM7F$vgRS37S869z0nGuEB;uQ;&W^qaks9HQtl5nu8{@QVR#1;0qwm0(AHYsmgj zsc<>DRST_9+KWn2oWmKgnlyg_mxsuhMywpSLL;^wGH~i zd8pbdTxw3zF30w2d+8>uZLd+C)9OWtdPy695rAm8C>gPt8m{3iAXqy-P5;t5ir)Y$ zNx`WSc&f6Dys;OvcYAS8Wut{}37W9=H7_!@?bX7?INBF=!evFys1>QI&0c(UG!cZx zUikPil#Tg?t0N$u=`$r&Cdy8TgzMaNBFzcdRix3Bngpg+gSNLBn=E?_u~kN(WcSw+ z<7Z4nobonDrJuo)(Q|jentS$g z<`epXOvyyclB$X2RBw0sUfbf^r}|@HJL3^OS*;Pw#vaz!TDUYKsRos#^^}Co)*U3F zY6F&~HwV0FGqviNfrboqH;&VF8mzenNm^;;;-xCm95 zJOz6|U#V=>T`m9{<&n}OrcDk9_78iH=kv#lc66+G^VUV;2xYJf99bK`sn^B~AJU^) zrCB;qRT2At$F@ItTcrUg*Qm)kaT!uQ1f*yl=q{6-3H5@7P3wGG?!pw>MO-O&p$wNG ztsQw44qhGIGe(bj%)U&c?CmDINzjCvlp;Ee)t+I}zfMs}N{Irk`BWi@z2j&GN1 zt}^BE9qrIfSZ@70CjP5E3(6mlNTx%?|XFE)C zhNl5cWW7(gI~lTnDVV zLvbXo8AH@idlJ+R^|9&_*92-U1r==el0ON=l}TN*B+g;uZI9ygneqhWZWcL`v0U93 z(GKx`RKS&3zwvD_qZ#el!lg~!r-~}r?U-rL)?;Rx;}(<3@2_UaRD;Lvu!=8S>4$X2 z`GdGn2H;Xbl7AGcM9aC|yTU~rD=E-*i;t1h1Gorw+O)&*TZlhaN(lJNp{z);EIW%l zS_9kK&xi};-ZbzK4cD9h7$Qf?2kk}Wh7ZX3pMaf&k_ML^Sas43qRKN_b^)XmToKj z7^2R1E#LEEwRX~L0hy{DzEq{RHZf^%>He&bUSO2yPwSGu*=)23*KM}LltC-2f+LYE z>OBsoxkbl&NGGPf2;qum4~Yvc(1wJL{<>V^;=jmA@jL9}EqiJFYjAb?wY}zSd`3E2 z?M-gLOSjrzz;%{GcpAV4nFp`QZ6d^Qb#__9Cm^$zaOm=#(Xac`Udc;U!-;Rr0&ekI z{R@SS8ZfK1=w7QkQM7h|jBc|X8m`^~t^x9hiU9T*xNcu%tmUcPYgMiA^4oqE z(v-~IV@hpquRUjR+rh_@aRei6C3}q^bo$SG)*!^L76cHW4PdQtUaNrS+>y>+jceG; z5Y?zpTt7oi9($I_*;>7nu$nSY>t92pT_c;_F^894HpG ze9j77z^VOSd)uD@HZR-$u%}U9%b>J>;4|3m0#|g+gFU0O7$7W5?f%7@UhDI=Nw|h- zUgqZBd4{+cZny%a#$HKYgBfJC$PvT(m)>(os9~|=d^126X}_5D z8{KYwWWd6X$?ch%?Sr!1-S03z?H`^^syy87WC~d&R*MtDDwHmRMZ-&Mq9Qh9_kGqz zyd9{iQ?01XvayHW>@}@3!MickBFMdPQe1Wvp5Y3}E#0TRk~zeN;&;0&xXLA5SDP@C zvP$t}(clUy9D?lsdXcXptt2_bl>UI9I|%0pqX(JP;KD!02Buq@k61>oW^CZ?9<|>a z-z?4|oY<@#rh(#7^wdE;gm8n^?%eFqwxAU#_H~Ks$k`F!hZ_E<2ZcgRo!O?M+sAlRezWI%IOZB*aC}&jDP~Fd%zQr2UbLf7wepqXflSf^$*k5WzI?FifnS;a|d-U zMKx~7(>pQ3aXdD_HYl0L!sd`7V6JESL_Nu$;nWM-43w zJ2qf(ihklRJh#M5fs8aBDx3aMPZ<^Rd5jZCbRi}usgkj^-p34VGL_o5v9~xB3!!bY zH%rI+&24b z!y^dKRjFYhitKr6AaTJOyHl6}VJNM86=`?i6>E8>PSmp3Mhn-x%#MA4xL~GOPf1vn zEwYniFUg!v7#PUL>fZT*hcm)Y^-mXue+R63?ZHR!$Heu_hdl)fR~|)oUq2T`AO0s< zsa)1sw3lZY5Y>3wauAZFw~x)tCsIN1j? zTBl{2XBY8|rt}%Lq?O(l`21=3*Poe4wLDwwU!Gaac=U27t#K7a;HDH>jy1Xc6pmHugqb|JycK>B&LWs@rqBsWu{^+;KNOAE2c+mT!^7nS&Otz77^bC`pgfui+ z|H4=i$$XJMq}l8PVB81@F4BFb z^bl7DTv@MFSpRbQ53wiw;wx3GCEX+-f%UHj*Q}4yXs5$+`z01J;)U&yU*U3ZO)NBW zH#sG1T<>@KrP59u{GBKN82&|Eo^hTfBca-mf4H)U>mt5lxcXy7S)S=uY7tjw0oVD! zjLBS1Fa!LsV-)Cs?2wf{nkivK_8LiUZU4N5e`IB&TGZq7wJGAJ&VzH+ zSK*Q}fQyD|O#!k!SI?w1+d>?(Al7F3saF^npI5rQU!zyJ_M25@4qZI2Z~)gi^xo$x ze}gOfZ@z?>CnBwWtQ|6a{2sZUbgiXN8l=d0GGquJtp ztulmb?=Y^FW?Y}Wfkfd_g$sWfKu&Cj(ZS<6ofD8gF`Q}^W9oR9U1c~0TN}@*Aw3_+ zGyH6R+M&0#W6;G)WM#;5_mxz^v{$^(u4DFU?dW*uRvTOeab>kX(q6c56^}FONodXv zk>1G5w6Q+@`b{EQ(*j-kPXZl+bp=GXnL})*DjN?CSCDNO+=mqZ?vn$E((xXlqyYEP z&?|lMuKL%Nw@bf`lc3Sfmvr}dhtoQ0euMV<0QJ|#MKBn+$vl4e?k&Z-oOb9` ziL2JG4T0;wf9-X|6s{(|Zdtyxhj3B6NnH1ew@bf0>~kL8AN{vYL~(1Ceq>~o zV|;+Hoo2nEn9tTmkK+7rT2&rZN%xI?PJglz73+Es$TslRyMIf?iO3%#)r=kP(@D67 zw3jbX#1=g>_ATEbQ3C@tu};Ela3y<5UdDXv=4W5HjP{dqi0D%&`4s&F>Wg(dTxkyQ zIGcnABAzPRHPFoZZSBv#{NZ;_f+0sQ$&VU=>cQbNb9J8?dZIuL(XEsp{@YOd)+(tS zfrpiU!A-dyvAe_Qk;7ranidGhp=DLj$}i=WNZ0Wj-R?!-)?tdEcNk@dwa50YwGs|E zLt7b?KCN;o$AwYlUvSe;HgfC`L;<69tDZ7Mi=m6sLZg~SZ+N4FX3@{lA9n&^2hD}G z#?XK>wv}7Z$%)ky!I;xvr`!xU^T@khHY0w`X}hw{sh%dt*Ofy+LqBS~qDMr)N*UD=WL= zTREb<&uB4!$+ZxDei*W-W_u@nQ7_^pl3)BEedPYl2RUSteIr6Q zZsQw)niG&Z=4is!!v%O!?0e))Z;MJ?)bPv#w*v;+7st48unrj4d_c8~eW^5D_Hy2^ z(v|KLOxdG{xH=#I+dOjr$9+!)$o}Q1MqiGkreBH+*L06S(!j=8fHytC@@nDwCx8@h zU59@4(Yb|2Il~mDwlvgLU8U+w>=!uYaCS7=ubY* z4|vTc@9npEjl>I z%Q3avq`LSnq#t_57Y!0PC9bojZfS>?*bWnLjt)5YJK!Ra+SJDN5*llVxYl%KMvMQt z$jh%a_HKG=NS%O?;uGTHH6EZ08n?x)Wv~C~dL1ic&MXafgqZw9bbwUbeh5zMr*WRc zS)dj!er!6?qp`KRwZ=QUA&Ot!4^i|7+Raw-KI%X2t+U3Mdy9%Fz=yhky?FTz3`p(= zv+qC@Wf$T6Q;J{z(|tN8pp+SJ<-9sepB8tH$fSjfu~z!D*Qmyo+}ZV2|LWHT8HPHi z+7hNYm?20ngSi`XN+<*VH{Yw`dk^V9;-3Ftu}Z2apX+KW+Rb_8HT+h!CB2xcjcZ6; zoLq+X_AKHi@6j~Z<^e`{gY_gDLJ4&ahBSw$7Z4CKpi%$YMB8?6)k_P!Vvg7sI1fB^ z;_q^L$<^H`XVkuaMXPh?8y_`D5}F87YF>{T3`!#O=KBe~Id5AG`3MD*;zpwunvq|C!g zOI*>;t6<53y;?`IGY(d==2UzK-9OHwfE&5SUV4vcMKxBBk(OXf_c>dh_TtD|yaZgE z{0D*2U=CL`a_N-?Q&&+w*OkpJmWSiEUO6I(Zf1_qm#XB>Rhc|s!8{ICJmJ!K*gArO zf$rezEO>$6jNv#^DZ`)JdNr=`+Xzb55%Ul0u?d=`NFzoo#pY4C5|-oBDSj8Ytbcj4 ze;v2@$k%c$9L%SXk%mvsJd@(R+Hm9TF`~%cw zKc|@Yj>5IjFzkESt%$xQA0ZBo&^@5C?q}TBp%-iE#KJkHJaW{*V9+M}qH#+TD*5R1 zdsQteakpU9=CR=9OBs`{;m6UzeJ2K=DH2ps^2p!Nc{nmeZF^-^hK;=vs`}zpAly*N z_I!DT-m{gCTN{v_2ebX&@w^I~VO$4s#|gJx7|~M?T>p1~pOmb=N5_VYDa8|zr89I) zK75?lR1q3`2~pc#V@3^Rq&VlAN0E9`h|MtNMv=#FZN@yO>tLcww{*Q<&QW+xmz>I4 z*%>ao4QdLZq{n7lRYxDqd12+e&xzHZqYtSQB_7V&8{eUaOGSp`PECoRO0_k6**vd|pZWwLq+P`O`|-!1w@>Sh0@x( zw}mSp(o9>X!o|&l7A~__%**%3o(^dv2m2LfZ~MKW4^dR&;@2wNRvvW^cx${7rWP6j zm#3)fvn8B_KH!C0xYX7!=Dpy&6}1El1Fp zHa$B$3k1Fg(P$zEjTx^(dC0&OAKWo5vb%dPX9UGpucdD}as^w*9v5ug1D1PlEysQ4 zUVylsf{A9Y=4girnA)NHXa@_r4PO<+#zVsudqx7qIB^oOB@gNM62&G1I&5O@dti^Q zo{Qq|-pe48()XV=;URde4TQZ3aGlX;vB#_J!5&;|R~cXB7;WQ5K*NbPuOG&xcrjBF zfzgVRuV{I77#CXbyo%*K&CQ;=vYnU8q9!+YDTDJ3w5{F2e^Q^ogDm(`+j%qDjs{if{5A6c3_+vyj z>Ug>wH=;mBLU+9=;bEBJ+M6N|;&Q^ZDO^|UeEXEfw3pLp&CcvLzmri7N{U$yTmj-D zuJjH<7I8JVSb+OC`4Vk`LI`TDTP4;oz}`Mu$-jKlgTAqIao!2@2jirc!;9QIULPjJ^6*p zM@j|7%H=Ka0fR>O109mf!B#Rb;c}tD)oO=GmGp_LX@_6wjG5@62)H~lPzf(UaGL>q z$|f0a??Du82RN<&1kz@%!PWU@jcYio6A71Lp($OnK5W_RyVnTuVL4Xv9WRM}o6uD%|XNyR7jz*XVwUm>oPL%P5zj$U`cIrdj`OO>W&A}8gJ*4Pl^E9Ztoz(gAeKdB4~0%CKFq> z)gis;(OQP!ybHDeYArQ_`d8y^Nm(sFO7zK>e1K-gc1%hxY49@7!}07y$@4nZsFoVR zHR5MTKz}C6FCs?j%V^1e)~c~mck28DtN~Z_r~IBnO=l=IPwZ;_=L#;4&V6nq^wqo_ z>Cv;-D*r{>FU`zSfRG8F*}Gj65)GgH&s2fKa>&T(cWFwWQdCjcmZ`NfF3vQhKhv z4iQqhts#e6PyM(W?@IGD^R#EuPEplBXSjg`mtR7fiM@OQX<3R{H!7FA4k;Q3z_>G- z;*U$+9{i#>hqE`EgWD{nd*fzu7&4ZON}(b|if`~gYR*%|y&)rI=eYcgr3n8NPQP9; zub$t`vFInRP*%C3Eyc72I^tpq8)ry44zyPa2<1K~bY`y)3W}-KI?L2dxoV&)Eu++g zO)G1M8CA`GZ_FawonFq6Yy{S;yHa%B7@%=sSm}i;&SA;;Iw~;AnEt8ya;3dqgz{cd zC#n)3&*dX)w8J!jZ+kFyC3lC%*sV7mCe0C&5=Xb#q|8xn?TV*F60R{NJ}R#193J)S zmE{a7`%15c(b7pifbs_GE@7euS4X$bPrrbWXNw;A2`JW%^@I@2UI{XZiwko+Q{lfs zjZ!*eZkcv(VnJs#RXs@7#Ssedv_eDWc$h(>vByGUdn|3zv_l2EaQ(*&2guGJU0oUx|Uuk(T%~u;g0S$d&GGuKZI*M zhc01ao8DG>8F5uLvfA6oqtz=f0ckeqG1>`8*(*mIH@HfRHE!I~hOM%cy}r56Hq-Cq zQnA^FQi{?&NEhg9PTx^joJSdiZ{)y%UrBuyR@JZ~&B`!fxGlg$tAp*F+dlJ$u~&o3 z`WHt+_dT99`P|pvD=%ba_@=hpdQtf*5%0n!VJGwJJgn(aK(!C zn}mexmbBUfE}OryE4@m)q^lZh*=q))#CP_mQMCI!+MUs_;ts`qpg)idD;=i0P|33A ze`&rt0=@AY2N|3>el2@Nyl7*uWVZ;Bdrg)_K(zYUpXF$~91pinI&N4qUuSmMl?R`p z+T9(R=88>N3>squaUW~U?a@yvH-#mS$k*-m3@ICO*I%c-0)B0K(M-ang=hR8`j>mT zUT>@xALUp_y?{uqKcU073~9_WTpJz<=fG9kYpb@`7;~iiprBb06?Q+F4i0!a7j;Q!Y#kc!_P~4nX*>u?^o_mf}ihz>#oi8O5QrXLeQYi;7 zx$W8ZFmRbYq3=1cgjJOMF{7Ei{y)SNeOc}B5^FU)(_F6%J*J~-TUXmwjTUTjve%3Q ztx<>QpL&kh=$9(&N!7R_Po-Y)w5LUN99wU!(BInc1t5+iaFQ1(?sEPbw)>Zdz1Ry* z-oLampUwg@5kzhhqJIHGm{k>MMZWNRP+|wEA}vznVRwKPU}+37WHs6Purwr-i+bcS zr-?-SaAvQ1+F0#g%ggaFTzOe3mS_4?(l8B3DO``k{ISMEy)R=KcG$`P8P8d2y$y7Z zMl|wt%w8kYl-%9m`cU?Y>hl|HpG#k$iLcWt?|n7EUI8&ht6$#8VXsHv`9|@!>6Yir zm<0wdGS18BUsEgq5-Sfw6iGKw^~0go|63z9q1D5Xm|29Az-SeYf30KdY$;ZFghL;> z_a1{d42UUO9dew{qKjxVt#Qf%kIkFXs2%Z@V)rIrllkD@J!CI3T+c)Kz+c`Jt`?i@ zTjVx(FA|si0WS?zh~1m&-iRvP$o&ww>c{Y_gXcZhi-F*JjPYcjIp15|K_Z+kU zAL?tWM_xj6Q_GTdq&RQRyQ!7snyKDpO;XysHEvuS=e(^A54FG1x?Ck<900CM4K7w) zG_+@`Rip=8=O0i-aeg*Ds9n$`2_dxlmnt`7tk#%J@82i7c+A3_t>a;HyOO_!<#a!HSFZ@0vG0@ukXIf zu!d?}c3MFT*O*h+k+`0^6%dr+7d5zSgtui{f{>?}wE4^rBeP67-i7&_bCgd&-E&B! z_qJpTwJo#PaF?qLBg`*$2NKi1Zu3UY;}0`xNqTiR&LtmaPd2!8!=+GL*xTy{gmi^V zkLEyrU_>;P>9$rfO0*=?Y-&3+ys!(Xdbc|Uka2@c>y2oFaNDZgypBlC`@PZLh(S46 zi-wf1d@3$`14dS6#`s1>PY&5t{GQ&-qv!{BEsVTsINZ z{pbeD^~qgdUXXQ8d%+n99ld~q-}cHy2p+6uul{@RCOMc!@h@d7qnLk*ZpmeSi;4a-Qosde0j6FU>qPN>Td(*D=lxW-S(UC zx*XZHa6L|CQpae$B=cz1yz0HxKD!!a@|``7R{IQEIQ zeSkZi5)$HfKSuwGW_J|^rV^F7qEKmbOh|5P}N#RpMVYF%K+ z&WqrQHbxsDI<%AJJ5L znNs0~E6L#bYWX#bQzk z7sfg4)tH|FOOSfW?7Jv~;d&2gZHd(CU$zCxatl{-pSYU-w?C zR>PaJ;My0ps5{PMeW=-33gP)yk-+?&|(ar3%uGMi>c`*Y&pxEG= z(;%@QP)pjm=CMi7Coe{{ezY8j}-M^wtW!hur zEPOw?mC;^jsUYpGgN;%!4bfDUFR*MD0b)T#jmy1lxN01mY=^f88Do(WGM?h(uJO=^ z6VVt6-CfSZXNZeeKsmVQd|pR!zzb4~S2<)5eHQt{=G_X;*m#NCGipT+S;7>;r43$Q zN#y3biC~D)PVNucOE1{!vxA#2>Y`P|CERfUm|GKY{ln1Z5aKrq6!h|jS`z#v>EP}) zR_29%z{2!}N{VNj*?Lr3g|FF<5XEgHX&~JQBxPrIE2Zy6x1g5vT_^wsEE$E}#saOrfN2{jGOR-)sJy42i zotHvfZeD~3BRkKaH*tiFzI$L1beOb`F)0)9T%|=4u3uK3I_^Q|wk$?EzF$S2F*_B> z66!Ra#*cI6JidFwD|Ltq{zJGF-BK!%j_+tGlUESf!ljQRES6iiW;(TNoq6euBg^!& zc^m~qXigEb*eZzOVz7}Nj1=hM2|b2uz@!~!0Dq2idqRMMl$b-VCWmvVai~iDZAcsw z#E@%&5lAWOCR$xM;zPJD=pYv1;)RbziEwpWr*tuy8ua}S0xs<7SMzD%njs`fZXj$z zT#xf46+3Te%|j_#Y0d%v6&5)fqK70pc1Gb{!?h<5E~&4WtX?g>r6XLuOM!Jmb|7?z z;~eQrbmXEP|H{*P3Xj_eQwA})cT1x9*NL^A)S0_GJ z8n~-HdWg&A7b%?uI}Rnp6A4kihoFF55FWZ)5|#{vFGY^tBy{0O#TSojBN~t zz<5>^0rT>EV4@a;lp{=M7!KJhc{N9-H^7WEHZ@;$GUX$vzzP?ojO;kn;Q$pIu3VWg zRm}R==&F%X{mUJ&U{Qfze@HalSHL`rzt4lLfXic{^CtYF7OpW9b)N8t?3GaI-hk3b zEl?*TRvNmpR|dgmI!ebP4F+!i`M}t9<8AtvyTg#3YaXFP8jy&4Q{ZxHhZ&3WmfB&O zqeAvK;TN@VO_(S?f8!7?&BOZGh{ZQtHpG~Q{G_-#Q9$bXWpW#LD5#vWmn#DNJJ)ks ziKeA@sE-)w`_`TXxuyR2^%oHQ(VOs#zElY~5<0LNxE}d(qm1rAj`OV22$xQLtTc4l z3sl6ILgdAd!8)3ehdQ6F{QMG9rAklpI39i*?cB(TYr=xS+Y3aKuxb2|#WB-NS6cqtaXd3c%$y*_8;(uKt)u zPegypF}4t4Utf&bdl%*Wq{h`fhY+L0!+kUg=##2{(=uf@%FI*dJa4sL1u)oouobq* z_yw?IQ8%YmCM>eGF{M&Y8V_Smhi>x#YE4pVEnVWm;rbr9W(Zkjf7H?;{$wMEg4FGu zH38un{ROU+tRbdRLR{lKE4?rsqz7;X27CPMK;-KjY>q=+E!aX}T;;4pV-H96>Uuy< zuFv5Yc-3dBI5b44rsK0T^F>I)TU9_=&;Ep_6Z*(j1-*S^pr)6{&KTeF12u+M9n=qalZ-qbg7#H zm%A4Z#c*0t$zJ0-K+}mmBJDC#xjv&fBDn1XU)rlbLr(FltacHbSxG<*@KHECFSD9r zhLkjd+l%wc+qjys8}G5C?yG3Ai@2g48c`M0-3rVn$8R@)Y1Xk8zdnY4!dmXHuQLP< z(-pEZbY@u!s0?P;q0!q#^bA@cS$08pB5yZ+54djThZ7gK;1{m=dL5#wv`<4(=l0To zh0OqBpY1l@11@|T3gRNE$#sjcsQ(H26OF-1e)tkI`gQMeSPvhKBuYXOB(NR!fXf3o zPSPHh%C>VB9`&!b@~0rL9pjpb%`1!vR6iloQ1}zd`=^?%|EXU6CwK8hTfV`h^9y+h>Vd2&pELq&<<Gh(mETRn3Y3r4^K+F3=1fzdkI43Y|cAAbWA`W?%2N zavx={9+EI=Me)0on(Wg6udV+W31^Xm8!le0JWhKhqkJ6F*0B0ZQ)A8}rQx!IT;(MT zUMZmR`q6JvBCa{Z6K)%I&Tr;bxe?N)$Jh?Jd4ml?GLgRE)S4nX0c!iwCGBN5>MdMa zi$_U7*s(|>jC$&r)hz1^*YtjXU$~M3;bJ(O{o}_eWl-A3 z!70RAzO0S|qiQ{}rxiyTQfnOB**JfM~DOuSf>#QEMSjR=OxbM(uVPGkV5OD_q^iUJe&J z5xGz9&+!p}5fjViGk9%ZR5sbR;fB zH`2|E?KerGkNsTq19)h!?*F3Z;~A#XP*|2e+D6j;v`)tR$O;$5gq`sHI7j^+42f$O z${)M~<&;v&#%SY44_??C*{vRlYaA2-tgEg@7)D)I!$w}=`bBM@M4o|DvXfA}v4>=n zI;q{QQ)lC0hmh0`$1n7&@$i$o0SIm&&g=nPN?O}%t%pcw@k71L<$&oqQOjQH2Aef5 z^jwcv{5AW3^ejVh?h!rINm~7jMY6^zTwfusKF4|Y*98&?SC_MM+g?^fHLejc87`XJ zXc5<(-Fs7&%XZiv=NWP$N|Y+pX{}cG=oc;xNNR_1=K^r0u#&sGj|9bYh?8)Yh>xA+ z)#zZjsvQnDA0X1N;fHNj#5A(!f`*nMuW^C!W|To*z~$bA?h*W!Cd1|Hbg4w)QaOZ6 z_7a4CcZ;~#zltIQF7BQ^h>OJ|#q%ffDEdbdzf+IdhD+5JqshesY$HU!69q(D#D##S zvqC;LE#h*XNsq#%?MaOr?yrH%ef%LBR&ocpI!|5CD|=;3uI+w@$vb}eoQIJwLX~J~ zujjalE;@xWN{SH08E49=uDpONRvfZrNtcK`l3AZn?hClwy&E}7&&JhX+k(BmO+L*jFA;&Q!n0g1SjSg~7{6hXq394ICdXk$4VYSpoTD`6abgU6yS z!<8}$NMh2MqHyuEXEtuQdr6Mcv0e7pK17MX1zhoP7m8KwKPEB4dn#ClNKrSCbHwXq zC{uq7wpwmf1AcN7ft_*AIKbud2?bq$2B91`sN*Hk;*oq=GBg3n5@lbos)frI*u0l< z>R(^~4n*Bo#^1V2TwAzm{~MdoYBI3ZQU-6eg*pJP8Oqcr&hFd_30&Bc15WG7z!gOZ zE{BI%j^H;6a1kPde!gL4%Qu=6O1AgSYO;^>*nY1r zoCf5{aQA+Usvkf?!+?R4^M6fTH!#2rN5nNua~MSJHf!zMBGEVbc`DIL3AqQ~1V2?6 z+zh|N)Uwy%fTesYjoJj8Or$S=Y0;7F2WA9_c;HA(8GdSqEBD_*Y0uL>lf435?^akr zny;)(Qj$!*78AqtIHZfeS!@gKyGX7%o z`|RA#T5u6QJK95r=14#JNmbZGmaTlGzK~0`a4glUQCvmHS}nyx`R}h(A?7CGu>bGY zR~M5*XHCOeTEJzWfmi7Et&12_*}&6}JT&j@NL@1q^WqR|@pF=+gOhBC(7 zeHEj*(H}NtkV5MX8z8GF81{0=iZ~7|euJw>Q7|LzSJ~JyWL)jSD!5!4qRf4@!!#gx z=i45W^=Jx_AE}T3;#)b!S=m>(rpLymyCz+&xO0H)M9r7Y&Cep2`=Y8=X`P3oOAhq` zQMJAj+)y#V#;hxa*x+B}wUSqJ`M=|i0eg{fJv)0He%dqMy^Y}eF9(RqR9WivR7Cz< zg1vI9MOWOd?B%$at!N7ZamU4dG<#dkra2_7a1GZ^Z7-U}+1)%O3}|yO+3U9oX0O(v zHzqVQCfELFyj)bU7d;xl^jYKHh`8>&1OE=!H;K}#6X-P<=s%anvRCrQh*@)MS#e~tnGt#ePz#x7e?X1 zc~iwzM_%F@@7$u2w%|=K2$d^b?g#V>mkShG4{nQ+3Y)sW0*nqZ#yNf;@k6zCL+XJj zdixT!N{=if7r>51rM-a5>}Bg-*{e$k-SB>1mO=a0;{%i|zC9vBhRa^#ZP=?@u%yMS zU@;$)=sCH&fj9=?JZns7-E}HuuQ-Cz>?Qv;heFvaJ(yM3Fnc|Qm`mVN{~9xm`j?7~ z{*|HDE_;+V|Gy$|+{nNlsLS!_DlW%;n&g8VA+pMl_Okt@eRjRV>@`6+u|_k-dMXd# zJ^Z31CnJItmULD2l2L4JjauW{+M}+v^U7XhzdWw=Z;_MwSMt)D@&p9Eycg$?aE*X) zetdd$I0gj1hHI~|%3jvLQsfb>>hTN*@{TabJDcTL`3u*Ok)+f(zrvf>)!*WHxB@9E zQV)(=LpARD=*(|JD*G3+Kfb+2A8h4_k1^MMaC09;?gJOr>$u2X0Mq-VsylSLfUNn7 zSNR?+61MDRZ+7&$(8i+)LwX2L1K5Ae*N2~Ev$c=k_6Z?*1#FcsEA=%VvM${G%Zx;O z#l>Z?z2AXo;~}oQ46e(YIZ^^w6yjT`WxkRO9Jt*5fYRBE{48v=+lN2mD=7UT8;ypD zrhi3GGE$FggW_ed6=5E&LriF@^BZ6`oc6CmQm=pA~G~WOH zDyD8j^~x4BpHIVY?&dJi95L_l@taIx^Vg;ajuqXm6PMfC4~WHIPt)UL9-{h}#>41W z;I-$f`Y>}R8^OOf^V|;%uvZSr@nybfk9`GIhU9S%*X(RU5yn|~@IR|Sz+~i1`xOd@~X?FQAi6sOsUa7$~)chrTp^_N^ zzm@C)aS*~ICV)+j)P6xsW|R6fwZ2tB&N!Y3ZKOp1?l z_LorhuQ*3gQhWsE8Q_Q>CF^&713aMgXSQDm5J&iRJSu!;=jqod<7a^O2=O>HlD)LN z*=8H)Yo#K4?XpRC-1m{qS^%^DMd|UtE6IpzhohYr;ZJig;Zpy?)POh~W(=3c!#MB3 zk^@v=lq5N-g}7E%z5@R23t&(0?13|QE#S`xE6-kj9Wuc<{Lok#|2Tx9FGrEkmeD$Z zD-AH6+l7RW$Oqtx5gd(hH7Mby4hU2*53$w1*np#LvMqv9!YHG-?tIz5&RiY9&#@=c z|2S4zL5~+7gQvH_E^*|Py@q}>$1}GpFT>A^n7u~4@Nvj+jcZ(8&nCHh0CtraI;>TD zHPreS4bsg=;4;W+bP>Z2*Bf?a&ZE&LM@2^|$_PQYY`rlfF0GP?PCWv?j<-jNliQqpRAc4+^Y zigS2Z8R>D4lu?48+o1V3n-_;Y zIXLSkDgs#Zw>YXkgGS@)d3hteeH*1q@+o5Pu!e?-hd+fBO~+u?zjPsOaSK<6k@|u0 zi7WC2{F^;CFOhJ)%QkR6|Ifi^0ZjJN_M|ps?S5HBzQiX^(F{M_=H_%rv~e^JV9tXb zheosAyqtApFASwf9h9C0RjuNcS6{9VH8fhr!l9d!;U4W}Scto5n#*jC5TeE+h6Z8< zm2Y-r6m$Hrzd@1o%y8WVtgX{hilTG1bZlYtJm)Xf#m-ACU6cWrJ=>+vYBlhgffgav zjR=B-OHU7m6P8A$hl`l65`sv$BpEIf_bssG-4E4?>HD3@s8q&p)iy6ROF5&xB1de*WUrc;-$v6r&!YH$lSIURYC;UTR*CvTUBv-vdN=XB{+ zD=tzeO^enO3fuuzO2yIN&mOx~UB?x#qDOSM*)2rv|5Z_O^8MasR8z(p^dzyNR`lt( zth9A1!{wN+$Dj&VKoO}FuJo>^Xn5V`Ewq^~|LbGa=~a?Osc7v&<^LQv&g(K-Ew3>_ z&VmhH;9x#QX#%7uBBKtAQpKWF68&*rvHtH?t!X84z6=pAJzo4C&xNxZ* zwr~w))gFUYqrCY%7R9_R#g$R!^d2s(e~}xm{w$!dvnkg}JB*}S{0|TkuKaB>w}p`! zm6oV7+E}=_=vcY@e2y{&MDJ1gSh0)bv$;prGrOx>8I*5~AhLq29VYnze$hnLhH~MZ z9wd)+Lu)~w&69FzfJEuNDT{o7?04?uynO(heTd8VWk16;V}9EKY)r;ifIvwOKPBOM z?lE}v!o|vrw~$GQkUjTI4A+>r2E;Y~UIyhih7g&N;ffnvL90dvudL3&k9}X6+(dSu z^(gwfYFUR<*n$lRqwxnQ&Et0oF)jiWGVkS0NNl_IMg+nj3er>mKXvaDBgd8A3BFL! z8T2}p$%YS3S*Z&4_Q98horDZ`(kfN5(ZKX&;JNN$u^R*ztvSqeCx_lqYPy#BIJHpu zAdtR|8m2|x_O@uihmm2S^=iti@&FvNfw^d4cJr01q4EN6(Ikr3RuQvsIe1g(*>4$_iIc^bUK8%bnHK@&QOZ|KTVKK_v$h^_$ zK5}EYcDA6>xR=p54f5#iR)^IxS*^EN_PyUYN;Ou*XlHh2^&Oy2UXDOq2VfV`Im?b zi?0khKp@*&W?gQeQuLC?X-Q(QzzI2Y)^Bu)z*0jvJPtl-YT`D;F>T#D4B4@O<6WvBj#~@N4Qw~w3S9rg$);PZmLxb2tZ7C zLlTRjhO1AA+6hSp-Tl`t6?0U>bS-%q5p|DQv>1ZL29Jm^3{6A=;C`w>G^fm!#@ke zbpj#77`OsUBc4QRp?DYLvqd=nS$9*hI> zNL;A=Q}F7=5;!ZG^dYRUT=kq)s}ha$tcM#At=KxxZxPpz0-sIbB7=k7Mt;`(?!C3>PHZmaaL?99I&% zh?KtxrhVrXu2UXW47kz{PX&}vQ@Gv*Efoixi z;v&T4ZH`x+=68@#dIF-RFQ1GG;9{Ry;nGu-8m=2UxCQ9C+y>wG>cCQ1GMCVo$%EA^Uv*a(^tMfAOz(*+rJ<2 zY$M>x;k4^;mBTw z>+Cw59kl6W^GXMtC15mBxh=t=3uAxq)aNPZ*7(*m#Ch5)z41@s?gF8cy{_=`-6S#) znd-qyH@*+?G_8PD{3%^vBz?%Lb)I4t8JrDJUtQ~P4N}V~cC#s5P1eKy265#d1JRr9 zK17uw&W?-!psqNX?s#UdCkXBF&8e^Ez0dEy2DhHL%3iu(?h2BaYD0JDb&rgw?DA=J zyKhmI>-LC?g<%lXZ zUvP>Bli}A!@nI z*8^&Ug(=ca`mEq+@6RTY8Y!_%gi_XhNy;!eM~G@069jvpuRDb{Z@*o^%6*oPdG*wx zHJ(o>e$L=cvbnh%NuYwXv`dbN9MVA=F(^EZF!l5GFqyI_O}tTeb2BFs8$oiP)zW*MSve(92 z$eC87o7difGH0XGE#u0^zsHz3TrZ%xqb?w0iN5mp{|#EL9)rNaM>)6lftBY9Ty$kXG_&~Mzw`j+6S(27m>msvV8%3gNZZ; z>^hSGrXJ^{`i&l(_C1H@Kp5amG8d2s-KH8Y5A7nfqFGyEwveR0L$33Tl+rc4zF3>yT#nS?_sZPxKkWR7-ehq@VV1a z=oX{>=a95RJ=ydOwTxql8zY-n1`)Uj=j@G{z5dx}Ec_Ba1$T%&*E|6y52x=`Gzmt8 z&%Hq`14`t%f*R$4!qW(!2=U01a9u%QWjWni3&Mwm07arUV;H<1_8rHtDI`K+Bxaj7g@!j+duc&WkE*>AM((-b+~-SZI_=Ixp_2(_;Y7Zd#n14Zs)(`s~c zd=ttO0ZN6;nmtG>4D^93@SM*Dh@!oWC)g0r{R*(f?KQsVkvrByJyuM^Dsv}X_fT@*t}glh{CyKh9`lD)1fPs>n#kM^>406je|PQzYANoBx^hwFgbGV5{* z=l6)~f0*Mcgp07_) z;La(@Udg+NY5m3@>=IX?Q!B&YXFbfIgEE3E^Url4n!QHEwMy+$4$D`h2HB@06kv zjNK^E3HV8tm}7FSQwUV2E*)nIFipPbdKxXYFL(r};aS5_>VJ&HnY*OCkMz=8@XCbi zn|j8EK?%4nfe-m0T)6V`Z=rmhH&;;||1zZZN5ZuQQLiZ$pAZ+HySKXMJhbD0JlH1;T3%DTQBMxT+PB~cmLkL+jp?ejFsHw77|Qe-+{umtl@V^{p*#Eza(nh=c)8;^3>TNQ zD_lqj-+I3_y=ma`%hRAS=P9m96(Ap%fNSJB1A^QjU{@q@m+Y$smUxizrEq1>fwl*)X=|`M$a>7Q0{~4 z%|N-oG`8eYkE(tL2`Y=}4zest%g-jj#XaI}#{$)@uwy>5HR8I-uWDOniK{!l>lJaz zP7qfbrp~C|gf6Rg((9R9RXEdtU&^^^UxA6S=-V`fDBXVn`OZsd4VS6Omsrt~H(fDR zaa=#1hpDr6PW;?)VkXvl_A-mIOA;UFW_;PDc-p~3#kizmWW4>qh9T?(frJ--&X*%Orr#2Lq)8` zwqa(f`4Y|<(ma$*(s!{^rGA;$M2)SJjfcaTO7jW1PWEO>3dxNhPu&$R^i@W`R>rAF ztX~jUR?d@Svd^{APo(8+IYpO3_ZTUl5e_Z^QXSVtdJtC@iA%-bZ}1dxWP68j*#{Ro z2-?#>V4$NiO8-W^Sk72%)XCNr^LRG?5H61%ejWWda80JkF<(!f+kA5Ss(0?UcxR`=N!HdO9g$Q| zo^t`Yk-bh((MaG<13LTk=JIfwVjtai`WJ?48OoaoRN)$Xh+AO7 zwVt8P&Z*}pSG@ES=YCg~b}8bEw8k~iig^xQvbI)vEOyEmOf2;gl79ibONACLlduY0 zwR*Um1c1MaK+1Hv9dJ#xudMV4x(3!gk2=%-1#xxy4x_Qktr#KA2gJ1molCAmN(T%S zy8#2V{gK(MEx*j<^gnd=d6g8-#Yk&)s?TDXkGSxFH&p!$DYO$vNqECoxO&jh>tS3Q zVT$YheRvC3|Ex#!yPtt~sI(8q@y)+%ax1`#x{Nyytk#8>kj7`62Gr=>RXQ#NcugoR zj!P99*+lYc=zb5<`}+|$QN)!wNRBteY02Bz4qU|L@yWk#lmpki^Z}UK*Zz4R*Au1_ z+n4CQjN`O=YqpYP(xsBN%KRDhEi`53Y06ESM$fq6n3B!v26VnmwlFTMJu;eh#pu<^ zZ18C?qu@PXmXmN@=?|eq%fiiNj;9>wClMlP%#Y+Go>|`8M)-6KQnIn;amPbk4>U@C zfauu-?o^*SOI<)^?VzCAx&vB68g8`@<(v|m)dBlaai#a)L7eezFm~p4Lz}Jn2nb`a zR=y9f?)gyF!;XV8DG{k%(x{>VyFM$SBz#B_>hu!Q%Xa=foCm@sdqw)(`%6Y+33a$g zr5fox5W0(}psdm6)dDWz`euNXday+(yU99H<{sd7A!WporI#Y^a!asgK7qD-FQ82i zP?7o^uiE@B9lnMHf1_`NDX!F0Jb=1=n&{fEf!W7WiHkNu`Y(I%6i06eTrXk*3Y5fk zaQ;2;Ic+LZkBUJAv!+PrQz*NVA;d*i#POC#L_WRC)^0^ya{#yAj!CbveSN@zv%|t` zZ*Mt3>>`lpcP<5FOzn%AMLFT%PIw^P320-q*ZxP$-fIznesLDu@xnbWeZ0ten0Vfi z?v*Ik8tp_ngzFc$@Z$DrFERP9aIHfU4)lis_L5HmDHkqJT>SucZ08EHRlXe&fi%A4 znK2Z-jDUIwH-aM2-)}?=-GG?ve}b6q_8ye~jY`MhCj-1vzSWhW$nagI9VlzG5$IsV zWFP*E+pD#dd0c`lUk7Wr0qVL(3&4@xrM+?ww!}J? za*BnuAlx|gb~@13C{QMAs&E#zS9^|Yg*e*ld$_Rr!_@)O%h}H-Kf?nPvlqh{uI%*8 zUgvLds&bkWh{QuOdkq7?p9ciP_52lhwF}^CoMJzdBcL_k^fFRSHhCw|9|L@yA{_z8 z^AnUE$^~o@YR4r6(@N5+?3J@rvugqNDkBPX0C##7Gc;>o!qxsh;$#=D!e4amZC>+& z_sCv=lx;zB{Ln=6+&ZG~bqb6S#GY@V*aX(*y($OUE7|%>MCz4bbqa8(tlB?9iMTw1 zEkaoku7I!?nP>ek9hz$-F65#8>H#wLvoUbp+-J(9_5iHbzRX_dLx38=tA0Li1gmn% zyX}Z-&g2~jr0njdr#vOI*Tw|yN7`3_GGRdbLM{_ph_nwS*=8{vWFurbN5%}-8^pE5 zweoELb>Og7U{qTK)^iEXH`0yG;MzMS!t~fI%40NGz=3`Pd`=p_ zoTs99xSyYgO2S-TM4}NQ`a5@#&jhmeM_}GX*7cK|AHoN>i1;e`Uug>LNUV0*V2NVIj95Kd5cc6JNWIJN1inUd^fj{cbT{_+U*%>A!?p`pQ+Y4++Z zBmHB%#?lyB#$7G^=hS#Tjg@QXT>x#{EMpd6NwcYx4_S=HC^n#MEiG;7n@8ew?+erLlP{b^ErG+h&=1M?Of3v& zqy8cHFT*iJ>;Ccx730j8m)g-&V)Hb5ov%UuW6%jTz|Xz%V|^R*Dq3)TVKw`2dCkdrT?1ooCC5Vr!gt2jhS;7x!T zy$?;g_z zQnvlQtk}tiSV+NS3x_EEgs0R;@MRoHwg$ckRk$23Y>$dLWuD?%VG3~P`!vGVAXfIW zhk<{%;bE`#2thspF6}==_&!p)1Roc1So<2b3iz|E%wB3=ve$s^tNYu(fuI~X+=pd^ zuo1vW=||+r8Vb}plhjkO08Mv?ug-9#!L_P-$hz;~&N<^v$}y533?g2p+5|(1_^NX1 z>G$;O5+@Kvmk)^C=xpOuG*2RYCvx_B5t3d96t3YG>fvCvzc=|wKyb5<1EssdspLEr znK-4V(HkraS=l!0xg^qFQsSDx6L9Y{!&SaJbS~crxaI*HVOjnJ?mMVWsh4>fCC$hK z4r^ZpmxWrL9{UZXe7Jp`&~*?RJKthtN+UTCa`ymk>pDGksW_#l5x+0mu$d}rFo^Z= zrim4A@4XSxzQA1hKFXoJ_7;4Gn||89TBwIME4LUkT-jtC@c$1ifo>0l)6ngLb^h?M ze%|)?!i9QBT#eaYjbppl3(K2fTO1dfO2Bv|s&FCSw-4cBw`BEjc|ct06+{?rhiQK( zTp5g3QJd$0!`fFt^LKh3WVu~P8KFQzZm@X(bA0R}imsQDJuPsJ%c zg{%v(KvV0x_RTAy9#8W{!`1Dhi)yf*s(oSgETYs)KuT@-Qt?!=m_);U3#Wi-F_w0T z%N2;}T!aFM&;=ssbJ|x4mvh%Y4gg!;lLJh+w0Zf6xUkATO=CV?Z{NAb!mLpr1-3PU z@}>6yNrhpZ<`OLVC@z(7Kz!72oD5fS2-gkxpJE8x&IlLwi+AU0_uyahB%nVL5H4ZJ4+B_OdtA7B>n*^b8$cPhdFtcUeC``{EH*BI=D z3Re+;>zM47?;(=g!g0QQ6DezdFI>R&b6n#L0#@|Vod^jAcFB*2;Hd{&gdV~bsu=Cp zwGn(4U#~n=K+5Z|M30I?54-eyFz5F_HWrk}Kp+H1@TYtR6MuD7qhyBTpg>NqAK zYM`_L)%uP0WUq?QzQHu+)Ov-u_E#r-x_uS>#_N6Wk{kOciOb{uX}pa~zBQP|FkF2g zR)4so;V=orMJ8NyT7PK!mf?bp515CpWU~05B5;|LK5aM`BJFy&kZo>m5ViH%T;;&2 z!Zl%b$HH|QIJY>~bn=LNte{zBSMJYZ2v?jSX1@qn(cTBcz|EluQmx-OzxF2F&98a* zfs##KV~#8MfJEdcQ!R|^*!}-ov6yHXE3v(V_4pdKesC$E*NS}xTE!R!!WMTrLvmqlmoZf^>ZqpSjw@2srQaflj++)sA4 zcDZ|8#LnEPy?l2nN@4#M^gg@el(>FtX%Nu4Uq<#vd%)EjVPZ>jJVc!2wXi6Ifp)HE zs0x>dXt-wkdy_4$4cET(JCAroY3bgBP(_)q*S7n2V?7<=%Jg?g>1lw=`oPs#;%={z z2hOkaqeYLUhD#syslF@12q!gJuI^|bo5C|HS4!P^D|R_eqxCXpKXYnbSOX4wJ%*n` zNqZc%I>gnp#rN?%@F6KVW zmn@8?=|6W&l{3QKDQ3BE@^iLT|8|@~FOnUmneybuWsJLVfB@ONdDmcbY%waP!jaEs zW-(@)=qpXF09U7h(lUt{y0{G{*MuE2Uv%tU__ucgxb|~#J)`Oqhty?cyeBXk@OBPU z88H3dgBn0%_Ely3h?~ta6upY}^i#rqx}wN4>vpn^@u*H(uQ0`As!tD?i4kA+7-$cI zCU4D7#JtM78N{;bOzIg)8Iw_F1Eo8)72)&i>>aeyFI-I(22{M4Me<)SBjf_d;_pdS zPbiez5o2aJlASp&y}Lzab=x>A>h$v00&cDDAZq74Y7?SGW(0ZU>zSYwT>IP7Kcmxd zc}R(m;02D}{|i$MCiK$#l`cYR|A_||>6x_c?=7ep{8;LzGu!>cO>Fb!cw}%qi#c3^ z$Vr3cEBR#VlU_a@ToOKpTmO?a#f6~F)H4)#Q%x<4bY3KT4M+P*8SyNFU>lvt_sjyt6B?DW=3={TmE_a_E6eBY1$bHJDYGhB~B| zsg=1mW{9DA5~ZAIR-X*vg$%;S;{Z|3U_^*4UpznYK(huWN)KSKbifj^|6P*y`44ew z10%aD#u)zkD3s(a{X2*HJQY~aFs@bK^6Rr{j$*k6M+-CLANue=A=NCNo3 zz+t#veFsvDxKt0Z{1vKJ;BI;p?VEjgiBeu&6)C%iJf`c`Bbn!uxV5h&B23ApMC-u# z{2#^0VjX=5wv59Ste4t%PM6g~_xcVZRqcyfcHvktVC@v$qq*(vw(C@M$nIV7P#UiH zs3>soV#oxJ{H=c_8I0fXK>9c`c2HR>^;A5atbL{19!Aj;sVZN4IpPvpQFw*d(;lE9 zQ_JyM3JBFf?aN*G6u7$Qt$o2`fQ;2};e&>V-<7?_jQEO&|27}|G{- zT|G+7udv38l6QIPldZOJTUz^!7j>UcX{0S|59El!bVn+C?JK=Ogp&Kp9R<5L>ha;< zul@LRKsPdhdZ7Q4qBjO4uz8_o&!rLhIzca$*ci?%W&P;#L&T~hc`V=!sDK>6mRUGP zHn}2fE!H)<^Q5Z~pL4SIB^*{PcaXll5;{`#8wA8uLoS%a8~h#zW(gjj>maUs9}i)~ zsy~E(pSWs`AaxPS4wd_m@CiXMeE_>jTvkUM{z}gt`YPKi%LUv<$c>GhNkmuL=+u&~ zLOlLt?aMk=+DnT8XvmSl`#3J*u&uih5^|ZtJ}YDAevRW-y35?w+SjQqWIWpn3`=VB zW|`mbbs0zBBuZq1>I@@4_uHjc3ATsBA@8Vhqg|dzX0HNL8c+`#+H*{gr;)WU_10!D zB1-QpgIjko!8zICMMqSfu}ecz`%3SBg4}jy?aL-U850p<#ST%64jc_GL?;2FDLbbE zEd6~n&-^~kG;(0V_1$?tug}7(TM@2w4-I=EN zhFmy>>$#6Uj+MO{$51(K9+f2l0Z4dE5m6XDh+Ud0^L^ohvIm>H!5!f0e#G2rJ286^ zcfAvNB59|i3y`t^%L*LzPbF(#p9KW8cZoAdN%cI1xaec^s82nlxhc|ve!w#w+Dq*# z)8e-(&Kwv1UlEa16S@&%%I`VYD+9d&q`~f0;Ch|*S|$^&f6_e%FOk+z=C~48#)Zh* z*N#WvoK?o`b+e2RX)9g~mnXl=R>Lo;7}>b|y-x~wvp>YAU*VO~G{-C!!}S3hO$+Q) zpm>q~QifGXEA1sz*?d?cSk8Bb8K|m-g-w_hJM585l1`*n^hY!xx+-*1xb$cbZ zh~uBf0vU^_KdrN@s7pB*&`(KqpgD$frHJ6KlU>*c6TSAM2BLq&@R}E^XVg7h6@Vwp z!)8shfcQozR4xe00^Hz@T!m`@x9*>;l!kC3$B`#cdLs!yOe=JU?1RUj!o8A3SI2dZ zrfTzfaaS=l9DcooTXe33nClB@*3r|a)xF@&+qfqB950SS_d)~^7|C#@w}C4?cm+z4 zEp88>bOjaj{xG}3yRu>@vc0SVSH^ar2BAmd2nKUvwI^ zayEu9NOy_LGQxi`OiEY{T^oUj%7{}wbI$w2EXxAy#i6a&C$2PsJL=ZpBH|d0Gd~sQ z=W!Y;htE+ZJI|$aKS*|S@{sDt4s0=xh{TN8EF9&B&E{$rkRW@qIWA`2=s9M&u;$#K z+RMD)G)nd!Gx0$`>!$&De#lYxm^P4ybql#N!?l9IhKpIkQoJhWV^TmfpV7nh9)Bqk zW?o;Ku>FiFwYkgPXgt4bvi}-7T9WpcB1en!d7)2EJvhOx(Zlt%=JAM_=_dOT^)o2! zCE90*IE@k^9Fs$BRMNNZd7Uektg)GVdGwTWYGt^T^&4FuAG&O<4w#X zY3ORX2vOZH&iI3jop*T#shuX=PIXkO-D96T6nEBt)%679*oWdxKa_Kpo)7q2CbdjY zFA>Kl40tDut9j**-_REr}{HmiJgd!Pwj5)j61Vq&ux@oGj(=?7DBv>sr9 zsSDYGvrg=0Y&_~OLCU#Fppl*mkh?h0;epgCMyA4!6N4g|i{ORqUqG^JG=pd1fOQ8E z+G-y&B)93os5D&Z!niO~s7PC%Y-;fXb|%@>!zG(HW^&{VPFGJoB;gvcwi&Kt#N{H{ z9GCKBxQ^4SP|^jYhC2D*=HvPqk};MTqhNDV&o%6x?e@yp~KnGOPC%MNP ztk*gL!OPEp%f2{Wz}qY@Tvm-~$+UR~yk@T)iL|%>5=yQ23YRTcLIv6gxLWtOaizB* zWiKyouZY;{i+-RzApDW?arTXms9k^(MnuE+ zyn8_IY|VI%3rihPUic~e^PLDW;>z}TYy~dhTE#Uvoz!1Br2G8YFr9kK&3-7U&~ z`N#LEBsjxGp}oy(j3^3MdL79bja5uNTq=(N7e4oksn65Sinzi}0k7;M59tBQKZyz4 zZO+%T%S*(;P^BBf>!44!cPPdNoSS@|)0Vv*Bl$jd zbP-F(HQ8oxt(&R@4AwH9}r67azo(CB73kw0FJKy!726dfgf4sdf^sc_}Y{9Ul5yxOOK0GkuDfIM)}E0~cNSYT<0U>d*l1q{`$ z7vX{HxlqUT`vb+ZZBPkw0@Xud6e+?%ZMmEDqJkW4wo)4|D>AsGF)Ro(ks?U zd0DvLrZ*_cImJE%0TF z}JsU=7MP{!8a+}^++BhNoQ(1B|Aa_>?M@upZob2a4 zmX>Irm-ze{xZn>pQs#vfNQ=P9+MB>NAg<;O_+RDmi^f>p9X9?6!c_f6>LKn&Byl}LoY%t^TWa%M2Ja;@*(-T~ zFh)b7(R3tFwvdlE7sfR}#AKhQkiF8kkWR8oh!;6`%RR;`r+jHOTmP=9i@BbM#~S-X zw*#@sR*`i=gb0;uvBnv$6O5nyG~gOnHz2C>XSKw~Mu~>aIpkDIP;i0 zq?f+6Fs>gkB8MK>D}r5y)9q|PyvVZ5*vKk-U4+y{jjQ@`)(Eqg+xEyE|57CD#0Y*9 zUQHH=TNP)Ysv5tdZ>BC2f^gCLXkQt4#+3Ul^!$nTLD0ut6fO?asb2-V%5qqUh77gG zm~G)|BYFGS?ZH54z-X1d3P^qFbT#6_jEV_tdVKif_K%UdPq(AAQ1)@Si6E>%((5n% zoHb!WoWjMv2DlEuwKn_vODu;KLKGFM8YyHAY3aLc8w(M$g`{z4UqhPl8gqN`Nggs9 zz(glTJPiUEmozbnU;?aX&%b{aX-vup_ZV(b8Z(NDvb+vPHvgUZQIEnOUi?A&WysfqN^#}PM(~G2hn0S&W&EHr}leH|uoqOOKbb;#y z+G|d2FI;m4lh1rDJ$j{$X@DMuwmQ+N>KV^g*%(>v%ceH!4{He?%17n1$8#FNnE7T7 zqo*#wS*O{QsIGMWA=fX%F;MQ9vf7s}QGHB$e!0ivlE11b%ez_IJv5K`k0xbtdg;nu zbZ$&_M>sccs%ae|##a<{R>_Zky#i61H$RP!#(X5vGYFG1oEU{V>3hBPH~-j@=bJW? z5735xIi#-baMD94n#D}3^F?-yjpr z&8zHGZ7GX>T2Si0;3>mD`Jh8-0ZLSW_Q-r$;Sbdu-TBpUl@Xx=LuOiiom>heE z?EkuBOA2C3Ix>BdB6Z(|*giux1`{>=8y*oO9KXgv(f+`P{d79T5y_{n(4cE`$tqEQGKmIL)4m{`g6N;p608{j{Zz8G8eMDse zmMdil*#5EOkw}2J)Q>b0@?^As{$1yGdjYO7l#AO-UzbP@2x(~3wv368?7FILS|N}! z-3&NK%F34DtXmi(vf%Oe@3sBt@!k*6O{`7m#CMim=>-mX^I*zYBM* zef1(r=>G2&2y_o&+~W4yK=|ZfggDi6J>pUuUY6yS;DZf?;Ae2)Rdg`ScEK|oc6X6| z2U54Y1JDX%9pw2FXMFoMAYD zzx~GndDy4HwX=TAMmOAIe>g$;JFP7gl+uVm^Y(@RunG^^OJBBJ{_YC4R5lQNpaok9 zPo-R~eTg@`BMZ!OQ>iWwA~apFL=(1xDQiDYdJ9VX3|61>4c(G-^_L=h+wb!7@XrH^ zBnh;)o~(`60bvk#sANshR<(hLGPmzMBB7+*rO&*5sVD8f^tn2H zU+rtC_GuVIByt-eR~*2%_e#&ga|p@hmgyHt;7;J-e!t1Vp@U=b_SN3lMMCf2LvmF; zMC@dHBcREvu=2=aJb<>KX>=FW-h8fSA7&e{d|GlHyM{~mUwtHmoOv+y z8$%a)O=KjS<0=K2=F2(Bk6$+Cn(_ZI^tNlI;G(d9y z6i0Hqyb8X_EDDlrJWv7CUPgLibWSDm;xDGk7|&2dMw{aukLUreGYFkIUnd5%!7WH3wJUhr^}7r@M33y)vu4}(knD~Law z&Fa!Cya)?O<%vtu>vbxVy;Wq3u-#auBrf}-VW=ux)h=t|kfkG&I=2qfWchnkvKXo^ zyN^p08y+bKDE}p^VEQQv&`8Py%@3JIvIXyjC@&8@aIx32)k?;~=WAlsFR;II_U~5% zhs&jVNZD`=-hz*YXe7c=1rFJ(!Ufz_kJEwA1>#CsZ4sX#EsK5N8qVzXJ>l|DRz!s5 zO97l|xUGHi1*m-&Ayc3Ghj6{ea#~h&WQJu6w!(~OpGD>?z?~CUy5^DPOK_(w3&T~| zdu}7RRV=zwkiF9Xatq1^4wos5tOIjg$yY@K_FcA@OAq71 zI%xn7T(ZiTa4pgK+#s@#1jCI#m~efAIIYpC^Ef+ECRo<36AUx~JG+JO_~^qK;9}Wl z-viScGCrH&k>`lxvf*NQqa3IIa_hIj)iDRtKAq=$za(9|hLH32l}u6(dvSEtJl5(V z^UC3tM}VX?=WHEPdI|0%M2O6tOMk?SD^D{}jsr@BNp)ZIsgd`+krhlT)uHnjNA@|qb!g?*0PMm|;OZ{lkBG@`X!#r@QFD0KBa(3Sfh&!p%15WmEIdEk*kD7Irs_?ll5w5jNX1D^x96hT|JzD)KF6;WV zzxVuez~$1-$br^lMy!c1R46c+mg4fgNJBH_IlXf2zfK)@?)$0uWt|;c>moKF^Skbb;I(5iiwTqo;OdW*rc*<(H9v|YF zwBeazx#W5~vcOjn{oz`D)bwl;a@1Il4d1D0S=o!4`>PevY!V;iQ7&3!Ke2Q)!bOMKlbvjTY z%=o7q>pQyU>@{DgasA}4aTe*1K&Fm`&#MTD`%Lht4+7{KIir_{nx0C4<}f4mIlWDk zW%ZBNiMq_Agl1j-E4N|PGzo|m*nqh4%1CPqZhO-MmkfGg>Vq>zo8!NIvoc&6b9=T7@S5XVXSFVv z()cEdsq=E`v06suO0P?M@yhoZzQP6XmZSfi`WY_Q;56*0^-v>3do2(btYSFsv|0Pv zir|jeI>Rh<9i()RrrRHQ)WZ_j?C};e8xWFq!qsrC!5b^8ev0e&ASRcnY@S3$o197} zyDSmI#r`laZ^J#Ol6h*dsw6je=jsKd6U=g+pg>>L!ioA3C8tMQS$R1k0FSN;SRaS! zqRIgmuGxQy{l<6$0fJi0GD3>%U)T!fS@p2H-$D}?Ni14d8IL=D#tmAe|yh{66cRk)gg1&q*!3tOi>qUV>XApN94&M+eV z3maA*BdR&q4LZFYK>9N_mH#E{AZ41)@*rG#hLc^i$TQAX!lH5M^$QWF1qf++*bA2g zA--@WTf}uo0~Rk=vsdm%$QX3h-NUP!9tclQaV7ELej}B6S2^R*!}R`;xB?Klf8Z)& zhSTS2xFVHT!FA!b+D1TdyDKWUJ?zyb zuE^}{Y3S)f5~Z8yi_qDC26y_?enaC|>48hRweKJ(`F!Bo+Pdg638z&)pAZ6X$u;1xlz! z$)zxLaXI)1)Zb&^Z5-MAK$oq(npl8-jFx|hLw6Dg$~PY9wdUS79KJ#`su5H%Wl@y-)*-Sb%2z63Fz2Gjg7 zKe!Vh4saORjpG<`4mf`wvmUnfs>2xtnAyvMi*GVe|K!D~O1C8DSjneKo!ja!=c<7# zDu>mHxzAIi%;o|#f7*T}Vj@b*7rYnJT%bJ>E*AA6O0<((?JGOrqp{B?&-)S#W77~F z_D!Nxk8di+mw5s%K+*t%UNOL4s?k}*MY=fJ?uy6hapXDQ?>jV|)=NG-F2o^S|BxHb z6f=-t3SpiLT)B2h@okP|lkE%7Yi3tdcQJE4R%kr0NRRdVM^)w;=d*d+u%U3#JhfhO zVbQQp2*;k|c=34w==&8@LoY%te$n|loAbw}(bUkt(fHh6ulu<^(-amsKfZ7@0enpC z_I?rSYWssw_Z)TeF5N<~TKCy^w}SHm>2joX@Vxbak3>-LGO)$J=hN?7xa zmK6pe;Gd&0g~HiTj*1cs|jcTJ=Qxclf|z@5i?{kal#Zqx z(>^W-E*DvrTJL?Wd>dEaxCOUJrQ%`^$7@s+3j@=IglmNpg7hYE*}8Ri8ClAd{K&Gi zOvgEoJOv0DnSF(F00Ez*m7d+cs5RzPdSh1Z-kfLNnIOv1Hy zL|g&ss*lyy09&{2caaDCx0gNJWUQoV8$z*F&i0|3+6$s^4b&09MM61rRVlRT zSE?~404`UO%C~UEqL11zMxCiqx*y@fbud$St)_pXIHGSJz~;CxuR=za2dJ0XI`h28 ze?O>*Mw6)yGDsKutKbm_x~_l|Dc$i%^I+BzrEGGtlul%GD#m357cN$my1nN8A@ryn zs+@-F`_e4H=D02j2Pb^CemE`xNxgNl$91?Gp?iY?P-E@WY%UCGv?Nds(n}Dn_%JT! zt3EYzMTA1yn!PSSk+vrcJEK91p~jwzZ7juwXv9!_Gy?O}K37l&Y`&-tE2DR^_qyl# zVd|>mDE^Q|ja0IxQehbD=RZF0>k*hYG$3)Zlfwvpf@17~sZ`V-4z8g!&1^j#(e9rK>=a6K&8Z;UVhi)mtg3jBtOOFiWy+ADvP@mWm2 zZtaV>bR&^@`aBjFJ3+ITTVwpgwy2*3NNQgf+Ouk( zvqmO63sQo0cU;b60JTi?^={IDHI(?FTBsGfMT z3Z-6t`+3;`u20^W2GY4NTpA&U^R0~!1$opVTn$>_4nG}L$HnDp``5ff_Oc0hj&8=P z;3K$LdzRu9mwiLF%h1^_z!`PVQp_S4-#)W-?8xC@-1-deIh|A<#{rrn;K~p@V>8+n zuFDY9@;zL$o8ExWI&*(GIaQplTK51k4HtxpG~eiMuT@S>_p9E1+fM`awT7HVR_G-t zWv}S^!1d0RX`tGfVcc*m+tt*cC+hRt8LPvceZ)zL3vb;K7ym1TsELauIw!5A=f9vL z_sAHh4hfDa5%E&_{?z%{^Kf{k(r4bT0;kqDzOI?)V|2uM ztL*26YyY(fT>SEi(U5)F6No*-;ctI-vGDefNV<#FyN=~@E?n%jz7vS+;xu2q1iSUDd{+JbC7r};1Al&IUNr6ey)E>a%h7_$$aFCk;Q6$Y3ZP%N6@`S1IBS2`}AI%l$wHXvzU`Oi^}qJDkVM{dxTE#4oCK?aB0Y9X0^@oktvqIT3S( zB@f0u9?5@tXGqZ+Jp{c>r7v7y$shn%hu(|R3>P*kAXXY?QH4vTGmj^QU&2vv$;2AwZN+(qbGrmd zRFv_&OxC5=o-F5)3X(R4w{Ic4X#pn)H7(ina9<{d8ZIsCsL>sZ@KHT%WyGbs#ict4 z{Wsh`SBo_aaG$k$$eGRJ_98AUiL&r$v}EfFcp4zvZUx~odws`K31;8Ipy2xS*K_l! zje$$+qFKqdA*(PTiammmLm+- z)oAGv4lG5<4V+q{wr4i7m$k2PKqziRu*?b9fJ-6iU%>-JT$`RL(KVl^rn-;RBfAvd z6)v`~B(QLY8{Q@Vc{|W+MjJlP>;)zMsBz}?6hXLtwgeoGrG|ZA!UcP^%UHQN$;Ps) zOf~TE-$F)`z_RaU5v_!~%TvA=3Yy~5s>J+@W|$x|70sCScumEafABJ5`X%^mTmr63 zAwrx{vgU$waW+9n^t52+{Ul-hHnMn4b$^6#Si%P9-Gj@Q0W>f9_)fUgzO-D1&nrS1 zP%&JujOY(XH;{;Sb6NXh8up&XynU^x4r;R8V&NDrF5+kYey}Q+e7Ly}pBW|Vu5hl< z*O#cYou)JICkSbI5x#>v0i1O^(I>vuR+jm6C}&aD?L}wCufHTAgE$;}*ekz|vbea;NmiyW!DS8qdnsRS;WCi&sRTWv4~27IK555+{aF9%eb&pRdi z19*+^1@cH-TaXeum$lYMZ^Jbozp@q~h19biLTYf|vf{wO0gd^_kQ?glONeDNd(0$z zEpMSJoM5jB(*(YW!lpJO7%ISC{GPeUw$)aSC!Z!c{9nHtz}Y3JeOZ?=jJT#fcBOz1 zfWlwYxW+Aq8Xw>M96R4(A+edi#8Rm3bShx9gk{huH7C}KXC(lo$vlI|%b zZ?m)l{|r);su@&{C!hMnm8n)&xI8XWMqD>CBj1G6?6ow6CSEBQdaY+pa6y)uq6 zNe2)xknYKE%C!Bhts4Wp^g)6PuY4b)9dAfbJE_5lIQU16DCaGJg5?W-kR`?S}H z_PRK?S6qiX-GGlhj4*qhfzmoaR$JTCq4w4MfM7X5Bs5L(;jDldt}3?T21|ov+iFdI z3Xk;PXGLT-xs?q(qx_m@;f!&Zy*kNNwFKlNGAF7dBU-wpPdhMRQqmR~i$yz6wX9>` z2XIM*R~Ls9IQ54wX%j~Wx?~R}lw5k7{xxFw?Y9_!WZP;@ehR1EVSe;TcYh74AeOZ#u}Y$ zyj4IvL}xEg?Ul^8)gB6S*r`Iac@)w`?jI0WJN4W&!#vR*u9pZG!0Ue-GrtU_YVaFn z1lU>oO84451YPq0FDq-D-P2VDh@%e487`JfE_?Nq6ikz>cO=56Mw`t}-({?MuC2gNLGv$^I+n(8+VE7Ria2v;EMmX&WuJ)zaSMfGb7D=!M zO8*SOtww5E-E8*Z?y;Ci$(G#anDHIm2g!ef(HEg~%OjW;B84EkHVNo=iKC;6sT^xC z(0f$Xw@eB|5)BVdvU0MleL-9|VFqQ{?8T1|p*hV8{3-%zJBO|9b$UG%m}dUaWBlUx zvJcZ=H7AEvPj#o7)d@$s>v4@MlgJ?$qV>_jwKRsaeTjv2s3Y!QgliUN!NA}8ot zpfjTm-~uiVTO_-EQ&%YW@g9PwB|?Z2zgkK4Q#>}RI~S7EwG!cEFWr~4^3xHuYrgga zOQ4?agRR)UFS-xW5`F9;%k?*>1z!7#VJ-NuCQrq54trK%r+&|VCa#=AY*I#4slfnN z8EVv0n!=@4u{tki`OH~UKA{6mX%h%YwXaUjLw?1Q9(QU8KE67LxHzlNVcL6gVai?@ zzozy&9R1nc;n|{9u?&|Sy*%Q)RC&}-XX=heq|||6=4H4u+`(M^YrGvYUI_WBIwek_w!eJKduvKjYub z*B-nw&?B>SDy#p@6s|nN*=OJ7DA^>E0{Wo{XRXa1%9Fx8j$u6`075qP%l1=W;nKQ| z>1F+;$2B^erSs2z4A%`#_!=q~P3pw-PdU>oOwSs;a}CM5>FNyvU`SLX3m0+f2-n0E zwC4h3k0$5+Ms`44vUbk0vdvu7Rof^aJWR`+*P?0ZUN$Lj!Cra~)HOW{VuP`Vlc{KBoHmaR-#v5lk1$2+dq4#L^N@^ zc>raHfwR4Do~l=D$_!fR=^S(}O#)GCw>)gA#1?tsb~6Pu)V)9()=eve#i; znt2G;cyHC6Dl1aHebP;G~51!a}A8S59z-kyEhAIZydW zWdDAu_Ep2BjM%PhnV&lz+++o;t;(oN+}-dx0~eKeY0RSrZ%5AF8B2Sr^p_$Pt^&${ zkjbWSG0iMxMI)ucwe(nAI~L?9ysa_R{u9%|NM^4aUF_4-eZS49=D3z-qgb+WDO6W# z7%o;>4^ve!CoCv_906Yw9 zJ(wm_J*A~O&>0=O$jUrWXEVJ7{8exvJfk?cL;Vn#}R6=e{SV(M}1 zjlui+Fb`C0_km|nb`>%0J43bc2o=hb z#nzCxFq@8Fh}nw7rFuBWmFz)jxK8~vqOQkom3C^+!{|E3mS@zDINNF(yU&Mkb*8x9 z6)si+J)5#W&lRrIJ5)|Dfo|vooV_hDK88C2wX?gSGEG~!)NdHBk6}c8_}*~6d<*Uu z124*@kmTJ2F^yP5jrsxSOg{gbnnw``tE|!Sz zA>_i;&OQz3B4}y-HCwIU7<@upf%Z}sE?h$(dzwmv*vD{np@cQms23pG{P4TfY?9S* zF{LDCP-bfo-PucEd#u}!tA|)8jljj+*&o#+++x&bf0*1WN4Stj6dS*8vOmmsBM`k$ zTmv9P-QR~&OEmfdo}P6;k3d%=PbYDVff$+aV1dFW`POkHCrZ{m&zwPLTa-37z#^C7 z4A;H4AhJq`(sefU-Yy+ufLol}*`ET}7Pq<7aNQ=Z!EQu4;}IAO3|Ynup~b-)1piqN zf=LMcGrj*{xKfWG0Y`GFl!V}-gioP3Mx!w3gTdXyevk}TZ<~8qq3NF2i% zw0D;t^R1eAhy!POX?Ke2=gWIg+=q7c&<@)Ev&=Vizq~SGnxyPKm<`#2yWFKxbgMV==YQKX!rc@dERLKwE?Z*EXScOZ$4&Aoum5#k2|MN^nF~6r|WEeqrDZYpvM}pSK@V#KUsPxeoyNFmFna} zUUX#q!WRA?fc82XeXcc+mdrz;t9~O3Gc9f`5>?J4UM{;co6pbET1+_Ng%(P*VWBkO zEEM5$12z7~1uS*krH>|%L{5?#jE+Ku<>x>Py1x?Y@G4bl=z>w4BU=yBc-EEat$*|D zTTcpyZF^zB8YL0wW%|OBCe^JMHmAM?g(Q%RzKo{W98FWRLOvm zp3|MtEQ3DTz0(1MK?`1x3Z=5^ z;jdwP;d+QHMnrOC>=ct7X3S*~M;8K`4T;xlW*$mT65W9+3d>SU*s7=LpI$F2du5zo zWIY4~EhCVskL)r2G++V&qhM+X$?TQU-CBlQpJi=+b2g&%GWgi$mJ63D9?@Qdh&W6m zy`mB-1MH>0oe?;AU|PKdmh1%Zegw;4v?TKXZ}1K_*z2E#slAw72M1~B+zlG(H|~Qq zZ>ES82sz{B5)X!(Jg{yK_Bso!`3EN;iVAWT2yV}rlO%vGLfM!QY!=Ay$Z`?s3K=Q}~O|v`%&g9*I zJgvjqb=WFu{ox%366Go(ddpsk?4@cyx0mbgM(6%FhFo%~M_5uJPV^1yju*EV?K55l z4s8NR*NAX+4_WSwAmLN6^Z~A9^W84on-SszxY6)&k^GK_xPrqKry-uC)FI1!pC{3F zzzJ0Vo0%^li)JsRR<$n(&ixy{&f9r4@N?Tgmj>)75(u-?r`3`m#nV}KXA41F%LBwI zBUsElV(CK%U8IzjJ8dw-@jEh#7vd}ihm_(*M zRRtEHJ3}T~URlPuS%Ce2Kxp*Ob>h% z`5DSC35f1eaC`S4^>CKz=eKWC#)XpdGIElYk>Uh8*~=ExzYk~frYmqFEsJK)y7MvzoCTJKFBFy$-;CJ)JIo6VPoa?h)nETiW4M4r8?A{Z)AM4B<97|3?X zhC2bA_8RY8hJRpohAeBd*EmAVJ(x&y)b8ScOMM6+HGjEw{t2vm7Tg-%Qpr<#7))22i)C_IUFq-pPW)9C zS(WUcnLWrjaqhW4ald=+U);D6nY`pndkq=kB3Z8k_JP1_QOh&FXu#xEfQe@wmbRDO zS6VU1UT?Cn6GwIzEZ(Lldu?w%!CoV^uXTnIWvo*D94x8qg%5nP+}3bd`!ah`XZF(T zErT_WNFh+kprSBxh(s}E9#E{5mmnL8ie;F92p`{KEKj!Yz<436S>s*WOQkwJgihD! z4d|abFwsa;!;Jp5y)MmABFbJm{nQ_`S57MoV3GKHJ)ntaufi?!;%sG6f+4PGMz#dm zeBO#7aVW4umOUkVkuce$h&d50*9C%)Je+&y!4$~am#PS_8wXDPdl@cY+bc?CFJk-3 z{4u!M3jtvoq-^WG-LXe~A8$}OhO#ETU2SE}dxE7X-G7(im^v~AcBEH}m~gy*1MI$s z$VoZge?azI5C2yvfAoJ+%ShS$Z@^LBT<07_v1e0E>1?bArvqk3mQ?nvKV+I16v1@$ zl|hb4Wt_^|9FoL=EB{(0C)9I z9F)Aqs9I1@-tC46T^I6X<8sx$qTyaZ&=hP%Mc~)+2#|2-vvn%Z=n*^K2}|(AqZ5?? zLoZML;l4xYDPyo#%C`6}mR<`I+m093=<^Q+`c>Y8u>k|$g_fH*`+6-I z*8wI^TsM)?H|DT!Uw4N#Ole9bT=r)P3@&Qm3Zc+(+6?jDJTDbIo4wAZr7rO@W$FA( z=l<1QkBFHABZPLg<#Foc80zmCA+TnEIW~|h^M8$i(*r6*>KZAf^X~^~3YJ89<-Ax* z&qvRdVtqDTwfl>Z+Fuo}lxcNwoEzQnltG6zE>p18tfJH&$6O1J*4l?*LA9jw1g>ggxnu%Q3Ksh(X+MJw%Ld_DqSYTo zvGrby`w7j@hQ3I}=VcewUxYh9HIdGI7ET06539uhZkvk!-uD@#JqF8Iqpk7>H3PbA zt6{@lyw5;9G+(yvC=Fnro80jfm>c`fqvl2OT&a79K{v3YUMnN9xdIoI(#7}h1I+y+ zDD}VIS>oWM9_pY4;UdEiSbff~&@Iy6Q_0mznXq1eF8rSHWS2vv_OE;ZUbi>B#;+}T z_OHt7pZgk$c;)B5LtJ*t2&Y-1)e9coDT{h~e~w|D_o^5tpy=6!IA~7T{pP$9{~M?n z4B$e6uu7(s+B?M6A5dO`?6ZQAXHXWHmYO1#8a}-Kb8;LSv2mY?+@xIEh(BGYma~wa za3ROA!uP{5T+C;BIQ8HNh)*|+f$Pth=6}UVdc7Hb4kOAC%AB>YM+`Q|K>#k67>}s; zQ)bWBlIT8z;xJ)|K*rRM;kpZjaH+&b!o}&2z0j|DT~DQ9xNe7IxH7~}53l(qt`|ld z&`$Oou9Sh<(8y`B;rbQcu@XQ*W8q>-FMe8C!m@xto^1byXC!HRw(X4C*Cd+7^l4O}@d&o!(l z`$LxU^0+*zgzY)7rXu%H&t_=k3aML_CK)}C2 zTdd5&^@1jm^2(2Jn%)FUf9-#Az}1)fY}PrN2jF1YMlV7_MFYzYz_h={Zcr0AvF?UY z*3Wwa5lt>KD067IqMW#*07Z^Gv~;&9Tp9brU+*zv({}*dmWALdNNH+C=)z4`Dlf7# z84*`&`&IDeam|U#hJ_50wmlfGNgUEG4fP)SghZ@KLhV0&84W5`GCUvkb#9OW%T4- zvX82i>H(5> zP&P;q9;tm1hmq%8LvPR6npVc5UWVG)jeu*Y9-u!x);7UGN_u>G!Za65XhwxIEH{K^M#}%kgxNWJlMT0q@j}iyau)FhccZq zTKb-HZfDGm^$tCTW0gZC0ekrlxOIK0hg%)kLi>u}RXyYrz;qM`HcGIbpCApxHDgp_ z|E}R;MjyPpitwnG1!Vz(W4kS2G(&XqLy&YkKmTQ{`xL(Wp{up`BPr5T{p1QAxyXqc3}rGyS0!0CQZ23cM#or zD4x%vWZs*gY!AU~%9P+fAN}J2@^FvM<{pk>lE~cHd-iI1(8Fhd5-jIca8G1pPp>FP z@H?8jvy@wxdl;PmJV4Y}*vyh}(cWPCfD7||n@I&}qIg0i(T@rZN?)r%h?WcSir5N$Vk zT7)ZN?lQ~M-&sTbONPOUZekD9LZ_|$T6>n5}h-f_qxDpx_ZrMEZ-Z6;C%!H7Yhr3sa9 zOnU)Wa*H)V_FDf&K($s!F``lrO0RN<1-@410al|iJn)?aUM_QBu?On}Fe5@toNPhG zxo(eD%0qm0lYAYAQ56PPVsf!7JQ}CiHVrp4r;42;UTMe)MS2(zRQ4KknPDt@jeuD5 zEPT=DHuBABLb^3)P|`sCfaRcR9P;IYL^SRH-$7w(!ENiP6 zDp1Q!cHaRK?IpSdM5rRfqYR+Zq!d@2Z zmAa;w0(?M;GoBNK8!C@|{YvD7=jn>2>{XTD>1kEIW}wRX*@f5#Y{C2BGbF&;Vq{Mx ztg=$GR_JkR^hmYx6v>i0CBR9q)sre{Qf6B}>4S^BxSC5W6UGY^F*hQV9qbZHlp9oJ@nYB`0ME*q5UbTf31m zVq%vkmQ`vC(?p^r0O|{S>6MK{-!RZDTY0wsm{?OV4}N6^rul|;Iu=`>4xte6d?Aja3Lu(Sf4uJJZgS??0tR6~i_c7n_yet5`42vN7nbQJaq+=`uio0zocQTCF5qZs|SC zq@m|4Z7Mq~mgt`i!Rp=Pc6$|gITHSm9GKEa0kV|K-hN?9#5S+l3o;JMkWkbi(H7p{T^ z(JC9^q;SR`4j^Tl0co&XY4ntEoJu2JNc$Qrm?nklz-)tixJGZ5ZQZ^UCh@z7nSFdn zA10DU0YOCq9(xqXE+N=!1iM=f_bndUwLCyeYW#nj+JW1@J(ZxT!3asn-1sx(UdY9ZNaGR2kq@qJfl`B}OsVRmpg2<2#2c$|3}s*@cuoTN8)J;X8H zlP(JU@F9|#(OtJMdg2Qt`xo~lpA$mRJah3V3>meK@ zZsM?Y9IY+2qfoTWmDL4oA$1wKl};vYp^KbMv^h%~HwE7%` zx>w+ZvZEP5;d$!G#;*y(%mZ-jd2;r)5x2IX3IdZR^^3SNE=k++vg|d;;I{evhWahy z%DV?hY3jgGN@!oX$7IWmA&Xu|>J9o$i?3Eiwbn_C{)lO6NxKpL>7wCc-Hi^B1>hp5 zJLdb9$fT8Lr;nMfCb1{Aegjq!?#ybw8Uggq}3M0(mk;BCmLAaL(19;fOACw8Bfwa+Eqr=QS>U8sL+C4}VfCLmjc(X}RUie*-R*%iBx!Fbx2s-W@Nx2bfz% zd&fcgh`2NfS!iF@qog~Bh}ct+LWtH_h4f;fbv~EA4|n1{csI~qOn!q*6f5IfTdr`o z)V`|b70H~ba7n3W+(p>aPln4+7z*Ixp9q)g*a)is;3p5Z4{k5Rje!g0?V+uLCmO*|;G)q*WBr?gmJYjYdByi+ z3*XaD>7WbmBbW-!0&J2x=AI&t_;AnRL|pL>aCKbjA(N6@U@PrQ4k4M*I(Ka~SGiy7 zj^U+#JcJOX^`HJi4a&*tn5_(^X_TEkyJwg}$<&sj&Y*{Ix@QosoFjU2--8Dn@u%Ak zCnl$*-oBxS6K{P5^ca2NQk8|%=-ed_A$DNj()^L$QJ4bP$^}pPIGw+)0}d_q zp2zSFnY6);=4;%Sp6I?tbze3&fAPFqIy&~2SX#Op=NeZ-`8man5o)x$zNm3Ym<4kp z;))Xo&STvkBtbF?G+yLJbOEkS4Q&O1s%M}t0arX@OI?Zv8q}U1Gz;)sI<;mx4P2{D z{pXP5@Hw_%9>1>I)91xCW}4slUYT;^QFEzU^6ZujcXqIp?cL_RRbWg?SeYBd8XIjl z6c8Ks3LXu4_jc)T&*bD%vDpNn^!;3C|FqcOqfg&W8{XyU1E-Ec7<@n3WD)w}W*Eu(b%)4D&mk&oh=?#z3m; zT4R>wH8a4p47oR4BZoi<*?5Y~-hUj3>n_|KNEo6i&A_5<52m5)9=|jYZ_%COh$gBO zgNu|&HLm1QKo(?f)m?epG+D|yQ%+N<&t~xvHzL@4L*Oi90lLhCr9WZrg-Z|5t!#Hu zp!Q#Q*(bndn}AiDG-|}$C8PV8*asvZZ#lRF4*MivG?q+vi=`^+c!cbZAb0!~Z@Quf z>C&ajxb%8dJZ~Q`V`2``?a3LOQI9Nrd$5WVudaI^dv!TS5yb!ZCm!I5%N}^7V@NS{ z*pZo&x`CO2T10Bjg)kYZ_^|- zEtPE?5*MYt3A2kZxC;iem5_j%5%2H%64wAeQ9CCmbq<2g2;^k1JqNeP5qsX|*tS48 zab-A-W^BLl<0H7@cS~hsTu#=YTzcKc+E3^0AyPYJ1537;=2ge5&jVIBN5ljHj41=F zIphCp7e3a$G#XoX3f~5<$p4g)P;IS!;s0=ESbe)rw@B?v(s|k|`CuK<_a7I&&8=3hlIbby9y1NO6B0{Z_^ z+r$P{6yG{Rc*Er(;PW_0ZY-Q|7X5}Kbf_>tKboH1`;$Tw^<-tarU9q+^8KOVV#daq zLt)XaMw)sW@xeO*#dri=GMj;`Tk;U_U#>qc>*4e|6zy|hS|>wq0a3KW{?OKYa|kUC zK=Gsd4zj4WmvD7gX!Ya=!F*9xrSy#L3tx9}NO96bLSYJ~(NzVUxe4;H!z-&RwDm*v zFdjO53mlQGKir2A?BB37ekG0pNU>utXZ@vzdj$(^sO2LEE@D{}&rCUx<4GD8)iRYW zeQL?Np=YrdYSTcoh7gd_h(^IX)<~1~D!X_O=^e0WMD~|B;=2*D+`IBVM2%N6>PVKY za7F&x$gTP3h{OdcjC9umWfDsbxExPNPEQCsd;fw?QfD5@x*9vWQ?O;oCZ>7|*;d1t zkac|{+RNV6&u)6uvvoKlCakd_zC+WgeZ{xvBa*$+*u&v)#E!c}lN)sNu)oM1zpuih zTe$Xi9K<+)9pOPywq4=UGdG2aGKSID#&ABHG@lr-<4$})@JAj@qsDh+uPIHZ&3x92 zB@S+W#w7lfO|6)3P$@c3d!){T^N4)DR;HZOt#z}Pc32ZcBl4{+53Y-T>dr+gJNKw1 zseS2^_9>{P=ZE+ZzQe{j-$S}LJW|?&Q$~p{y8*-w*)aCtM2I{C(jJ8PN4LRkTz(Z& zK}aa-D7c3dyY1ul>e2sN8(>9hdGXCH2Nxm6f93H$&K#v|r2bGFKI0wQIA!#uXg)`a zP*aMdfEbAbOL0IVB&GBsrxwxAap)mg^a&bvy!F9F;(8y-m*^uJ{TQbgWv?j`j_%KY zh?KTG#GIxSE-m820UVnLpJD;IFrX)+aB9>;((CT8JPOIlo_#lI2-_%#xKoYfHLXfrWn(cB207LQUwN7$R=kUA;ERt$Cz4RxYqht6_I0mPH0)KzSn_Or zk#efCR_|cXD;*&WGhEuH#Pb06yi7NKe*=hz1LiqHZmrbM_ey`AQOyZil!3<%PV5mD zoI+p3G}j6@1SC9<}EW z)w!P?bRk4-uh=n>2CX$@h@Yi498cj?*TpCK8m_9=HiD#cU%H-)A@y|sU8;(HLobmf zsy&U|4;U)1f;R5QD&6N0^q*sPK@Y|R_&d$s9z}`Y`RLOAfHBbiFK*l|1d=` zXgdEUV#)|b0{nWJ)x*C<=bxy+S{Dn?0++&TZ_}u@d==zOK^4hDVU#H@r!@8Xx2WHO zlKr^-`E-|IjD+LY*ohiV9nOZ6@ly?t5xR%;YYE&F90g5Y4M2m#_P=#5J4k5&Gtxzv zhD~1vX1c=jw37#Gi;aHU+DFZ&ITkJJ;_CVY*Og9{G+ z#Ffs#+IzeP%g<;!r?!hDnS~HVVQG8C9+B+sUm3A&w~DT{J>j~p-1pZIlDN*jaX$dp z2rTBGtk@k)x(A7q_yVVr>(SCBE=n}5{@0k{FzgR>21|r+=N*XMQimBb#cqy}TQ|YA zLWyY@Kz^6ySGT~CaRC0qn z5T=J0DZTb43g<=DXeq)_Co+!f>H7&J+a*ff`3d=j0G9A_%l8|xN1SZF3Eqhvo{sN9 zVYt-Z4A(S3N$|-bG3?Lb=2r``A%g+daYQY;4VU`;gg)btN70+rc$!{gi45y`uhtq6 z4m8D){BKNTsB)pso=;{0Qj578PpeNOYv832@ijgJF{%%YK3kx4ldcGkq@3a==EG<|dv z!M8)H(;qR~e8X^!Rhp&uX=hcD0b2woLRi8?MNyV4Ic2%Tg#gGV{xa#^P}r-h`{fUL zwR&ANnoZ!A<+h`oxGus?dX78a;tw0RE}I8<;_>#<`E5v>4onoYo>;HL9O7xhO!~8# zZM_~apm6Q*jyBzLa1(;{xdW~)M^h$kxb7g(e=cv~nw^KNXZ0f(7S)*P$uT4(9UxZ|lyq4Tvi1wh@Ow+<2;$)>jdp!d#t8!~hg?F(SGXrq#LbQ6=g-~>0 zkJ+39j(BH;(-2bB4K&MCq3G8ASK{ebns96OX>o)8a)FTXVP1-BVzll&B z$qJg_97|TeVP#!-fHbtfH+|&cwv0o-{~n;+;s-y57;wZp$VW7EU@!U} z_^1me>M~N|s1&XZR-(iOxJkl=?-e<@kdpKC=JnNnUQmDdQt54F`3v6Yu;8fo831J|~Le#$;s_3UN&uR>SQ8qV>q2iFwV5-t2rJz0*J zk7zgno3ZR-7a*oM^zo8-le_yn#FcD97vFyuTu*3QDw1x6OZ`T486mA6T6U{?7fqS{ z8ka5GX=#Yp#lMiSTn0pABxxS#I3ydBEkl;0A%jjfzz*2p;u{_!rKn4u5LbVH2I(fo zh4`-_MFU$c3k(ErBg1tyz@;w4w28Ab#scQMf$MtVfkclWep7S#5tBE{c^U=s3E9%P z*mtv;fK5geS^F@GfvW`jR3=AA^a5u?F}IS&GnQQ!M?u*PLPCdu(R{;pxG2PHPA3%A z!8)XFqa!aoaH3D5sY_$)ps)QU;l8x|-TDiMV)c%5$ok&2Qd^P`MbyHhgyQ%%<%d8=vho zapnZPb=+W@OxY9LI*}-c-1yUnhR;%>=1r496}C}oGb*1uo(Em73XF*myO@k4TTOVb zH(}jm2RNqMlhxHM)e1r0qn2b>@Qt!vg?7NM)-z+v?_0JK(x|0we8K_7s9y@Ue3Ct2 z@9%g`>!+2`A}dfTPyM4RlB!tpJ-CA+sK9c1HwtWxiD*)2>oy2mK){(q$a)&9%9&_X zlE)d$=Dk`P$sEF7)8!S(a8avb%DC;e*wiL}!&M|;19~+0sl3SaM*s9q;0%blV}V3D zhqA7&L?>RU2h-bzdiI-ggpdE?GQEsG!fCDLaAB54|FSdnnOvoc$ppe{x^eZryo{q9 z+s=`nL)X8$2_A^sBKSr$M!eFHX*{@t0%o--_tzXkN;Vyov{wU{&1*X!(4VWoKwNO@h9^D*Onhk;Zfjp|N;i%u4PX)WTfobCSOG`WV=)+Y_HdTHj{Ba#i z1gR5)qd$cI4vTGy0*s=ck%>Aq%>YNluPGYEb3SrV`!a>lKy?h)oaJzlW?IX;g}ss= zFgcMvfRSFhi3>Y;1J}6lIqOu|3&9fZ4#EScKwJkC}O< z29^|1N2b1X@f;uWQRMD!po6qZ=E#JQ0!+o+dYUQsP@BC5^byTiZKEw-I6}zyW`)@N zpU!K0rC}O?>%Bl+OuELUbg6W$oB}WLH~puK^`j2%QJ|c&IYc% zcd4YkazZp*7ueoJ_NMdJrYr2Vz4Q&U3PfpW9Xp*5LWyfab>hGt%%@PYKeQXa&Q<`# z>gtd^LM`l~>Au83z6T!>Z>8Ccqv#*VO=hnd$X=Hn;Od{=S})ZpvpbuKj~qG4>~+9Q{5DO|S%cL1COK9i?a2;>3sRkp8=r@gcam^es!kcu%B$%h`?eOB`}SK(RGQrH;} zn7<dCIxA zm*LtU1>kbb{dHbb_R`A&*1r4<%3*{+Jq2y%GvW2r_~B767X8qnM5 zGEci)CK|?IZ4UP5n)ZT`Ti-&MAyI@BP0{)J9Iib8<9UTm{ZQUrDh16#F%_j51bbinmifXpkU@eI{bx!i8%8CrT-c z)~MaZ`RZ+0$!hU{>1j4)8^`-FW3t1xa72SNLV<~@I0_wR$tI>FDL zlaV@#&mMo7m;-dyzi4Xotc^kOiMhB~X*HFvTqgxb)tdAP_!o!ET9y)KCm3snCFde* zbHqqk8TBx=@P1;O92cG#{*EXzrVSH%g+4C5qr_9Rk%#gdhgDR1EJyX{JR0E(T&qyA zJGA?$`ofKnD``N_$<}#J|L7^N74H8uk`b*ZtuhxE_CjgsLRxDmrUi->$h#5=zOk$z z-5E?@@#^e;R0UhBBrSy5y)!eG{0?ilwWJ{fSr$3S@w>y;&v(oURBqg%RwT=r`7XIa zSK^{Y0*>xg29W7+23;pxC)2Ii&#sxcB-hs&JNxzY#VpU*1uiCy=?3mVDqQxC*@S`g zSbxA`wfRN}r83fMTXaP!nQ(P4dCH*jcKR5u=5&L&&K)T%i}3Dc6PMtffT!I*VcEYf zTrAo!LcfUYIhdNIn_~dzW3IYy7FUaJ{&PYs8yOP9#W)Za(Fn)>Wzq@wAg} zZFM_``(ekT2eS@MGmrKphnt11FGkuXMa%4f9%RX30AKBbbz86qb}Bk7BkZ#6Sx^X3 zYX+vyqg~aevVGB?U^C*1ta(xwWe%)f`&k~>6j`v_RIFb>9Pw+YqWIz4tasIfUHj(? zT!}*vbs5AJ?|SfvxO(ggg)7?St=US8T9L|L8~)ngDs@d>zpjpfy}5y0^eOhrNJu;8+snIHC&yOfc1t2)upF zBEA7!jrAzz7(3&@&gB$IW&5H$#bNF1rzzbewTk%0@0yGKyf4Kw&Kna1m>v3yvF22a`&Q~jx}k(>aI_?+OOV3YK^zo<^k>+=JNZN zBSgd&apKx%B72@C!rZooyi^0%H8?wWZiiwBPCXy9pFL4A+peC!>*L=W-jkH3Zvt zr33wxCkjTkNG0WT0oRb_II7xL^k2hiWD{hzrRUZw16hG-;-gU82bHDEcuzZfc%-Zj zHZ*-K3jko0PEyA<4$+9X(mCz5+J&Ya<=`Gil#+>3cF7G~ujvc&@=^h9&=d_^JvfaF zLYuh$P2!FzN1<@yHfU*FjFasX7r)YgQ3RM`Dw6|dw^0wd#*+N2+r*4+CTi(k2s&uR zDRn+3ze+{~(dF7+GSY?x9WVf?8&-8LZO$)kC!QA;!3Da+ON!cBge+aBo&$WRn=@od z{l*3{B~+$?B|Q8om=Uj*&fg8-CGD!Bse~jmkX5+qgz_Xjxvf z(C9#XUWnGccHy5mw05J!@qGD*=E68oLo8KKJ5S)Tp1zBEHT~EF2lJRR3$bVNcmIbm zxQJOw4A9{maywinS^ZC}fs;t61Kr6D`^CAsm8d1MeguD{Z5;S30f5o%k zI6&Y8N5?)2a2}bzJ7O`5c**2n{hI)EkEocFSv{+++~y$HpUyn}K-bo0CKybUNApsd z_-QEpmpbQ5g<>FeqO&P*JrpkL+J*~Ka_gwV#VVA}Sy^p$W&`dhg|k7r!|YX!D$2(! zs}ryNB=8a_4O-+rb^IT)t<+sFY~)$sx2!Yf&hj^(?*AJngJBbQi1< z{yE+GEgC)ch~DAIRzLlDT7t**burtxS^JJS1UKlLax&E5HTD#B#i?=G>a^yAjhGT; z4x6ONEnKnB(IdGkKm(U*pTZA`E4i;gOS3u;?YfUv?9trgJffUBuqz&Hjo}B{GCPE1 zG;qYo;V<&cnSyueEU23o-jOd=QIgXL9M5Ew(TqR^7H3d)04B&oYLiU|z7#1V)wmk< ziK{U8IuaN#QFF_358yOhujpThdUT6kA}&4tw7cNsU8ozl1~24gmYG?jTLGE9;d#v) z9@7)Guey!d9xNiV|IkU7#?@oK@ya!rY~Eg<5eJn*V|!NTaN3tK<(=&lqi{~BO}3r% zXEWil1wZW}$=)3oh-@sf_N7sYQ(Dv+k4D9-Yq3Y)->~*FVq44R$epd8WdVV@7#NN0 zlN2h3^g*Gs=NajDj~o#rdK4-g3X=6$XVm7AF3i2Oz4UTCmU?}0t7VhK*O3NtCncE8 zJPF47s9XUI4Fg#i^ru36i~l3qhy%zzi4LTQc7ZMf!j5u`4iMmd4&Wer?w*Bi?MpAk+IJtRi*lCu^rp~`A^tq^;5FI&ka=uw z<>hPtT?T64+JP>*vI7=-q}06(sb1bF?A4=k5;^dtacLHwvI|JGYfbGd;s3asz0|%k zmY98g0zxtNKUTk?JL|&=*9!k!&DxiYT(<{(lEUn#0#icP3r<-;T4v2u4_D2PJSWp& zFi9Lz-U3^S1~Eb!uD5BgKIa<=$C474hjIFHbvO;{U8Pl4;Vekuc{MDQxo5$p;MrCHnDJDZ6ukgx+O(Y6gG*T?bLP-X<>nPp<6M zeS@a*I2sMY>^1Ngi!EUK=mUcwqz4<5^^{u(1uoUY5l5BoRpP2)+eC+!in0u>-c<<4 zsiX_PLVLxt)S+L$4>9HU0IZnO0q01>6^-5l(<1PMkh_O7S^-jH7n?Pmmx!xNpFtLQ zBJDXa?OX0%XUV^MeO zF_k!s;!sM_F4I#_Nn;npnZ*gpnA>9B1tHtx^yUOTNp~X9afRX9RV86=$B*xV&jUlT z*!tR)tx4&KN*Pu2#}{|zaI5@r1_d(K*jTI63oCT=JV_Qv)q|eB)$1q2d?rnAglKkG zrTDuKj&N3;(Th^{zh`WDwns$$p{iGQi&j(vz!?;9$i}JDe1*DS8a>Yz(ZIE>9WShr zMl&^Ht#nCYxF}|C+pUEygF%twPy<-{W&#nuREm9-d~$>Ks_4Z3p5?95uN$Q%7F!J4 z0nX(+tTLG|_3Rp{Pa1N>;eSa=Jpy(LtV_muhG30u=^0{u0YTLzudut;pmZX|iGdS_de~JBK@|aM|k=3pX0pVRaEO zivNK8l>jC;U8U(+WIbjne@b0o(Bo9&ihY1rfotR-Gr2~!CN5kOxz>%tXy0%lWD?-T z8i@HknBlUI6x}Q{X}Ic{2ErkZ7QzO!kXd$c0Bsos;(x|aDqPKbp8?m$ipj`Gs(x37={ule4u{0{t6_NEP7w#Wz_Y8N6F|9d94mI-F6KZfeTmXCKIZ0 zwTPp!px({levZm0ospB`9Webbo!v5On6GiEm=qANR^t5H(VDr=|)R9QdOvk9x>B1+FMS=8=Blz?tI_!4=~)>!s-V?yiRr=om36k%oC; z6|Q0vN9k)7+*}i$md7=}$Be7{{4Y7@e4uaTX?a>zZp4hH9|560E`kODcaIq_+86tb z*u$OdIdD>e%R|)jEb6$D<#FO+|1<^x{(lR0-~yCe4$jA5&3gDx;WT2&N3XTk3g=m; zDRIU84j@JdkM?Eu%3KjqLPvLkECBm5bM{k6*?drhi4q5?u_`FNnoivxT39J<6}||B zjD9i?$iodsjmOcYVDzn0VBL8ZTnXD(dQWYK_L|?DFafn73Ms2~e?SNuayxL{%bcIl zElSC;WJ*p^WX`G{Ha8_!$zx&V01HA4pWJjj1suFsLDNz&T>I5O09E>@2=Qg)?xq$m?gpDV@S)+tlgAemE+t?lwANeBJfd#b&sENHm4L z#t78KQP4b;lG#fis{XQ+qC?mo(-XkSIT#WR6%0IuX9FSSEXI8tRqs&(Sj-m`|i`YDui z4!K50%yN&)qD4{CD;;A>)-uByBpyaBy&Eq1fDL_lTxwq{1Iq)hylAfhbMq2$;R7gk zG0aYhBaK4kR&F=oJXiM{!^9!8KLRrfU7V$iVqfT@;ny5+pz|KoRO5J2KM=21jitZ z=|y!QD?c(2MZZ$-EAPAmpFCO?*PQ)f$HQppmT)bMU+q;S*Vm|6x8XzL+StDiF0$Rq z6dV19HkH0Qf7^mY$xDCWur@v|oOVhxmV?<#H$PK2qx$1o*(wo>H1dU|aZPs|Ao+FT z`Uw&kZ4WJ-f@=hBsT`}Vy3t_^#kTTVRd($Pq3+f#YKk;%r@h?C;I9HMLS=)ddWNlj zL%1>z&w9PLZ3a{XR-EPUm$eBX;S-Vc=39vQ9be^EsnIg1FAi*gKt_kGoxPt{W!cO~ z878u+MfL6E&S2ot>CGyC35T3SS$}xG^5I}zP~u8S=fI3EMPJ=fur*wAXVYQ43dil$ zFhGVZ80k|Eo&740X(g2*aMrXhtH!U+XqH18a5QL)CWH2c%P&QF;}OT{5mNN5geCv3AY*W>-AiqRMzqZ$VsyP=Itgv+6(#L-3u)lzSN#h!0%Bu~5ctx@j1>J@g*T|^=B}c?*xYVvawZ*Ct1l{}C z|H;My?%&X448qye3kaiGg<>`$*qmr`9v8lISnBg0CHwi zb4itZdGbySFCA@w+k{TI9GsUpQyHu94Oe0_BY24dw019KPpYX*R)Pml9ON;MXv>3T zOw;HtPH|vD!u9b#_ohFSC$|H_uuySLrdLl)*ZDkhL}jYnYG75_^^zYmWB{A6`ly$> zhl4o1Vb3aYwdXA1$8SSFZbRxO-$!`ZX_x)H)CTD3p;7*nMkXr4mc_ z(Lkb*IkvBWJa7?MyJVsa9(X-32Uj(2b*UhA+?ol9$>`s`PiN(w9A5IcMoi_`b`V@^ zLyf@~MPt2^S#9mYM+|y4p;7%9p|}8uMS2IQG(<{fCQnWIh~#^rT%TL@zZ$* z;rq(JhaiTF^Oa#WYcO2V0XieYrSBkY@k(PRZ;QY*pV@0r<4P-Bv)VSoWu{m~98rOb z{hc1c#y&u5;&M$~=mO}!1mXM19>KWGYLUiOgAgv*^9Z;6=ew|v*8V(=l&4@_{VUNZ zKwQT`gO`-LQfkyW)k94>qP+AjaIp?V0SEd^aI+r-+jv~t3m?G9sa}FMH$6hJHUSsJ zaTq`*HE>;LVHz%1;Tq_(@o&r!^gq@FgU!+5u;gR|$S4t`C*nHdHPbCHHtrL+5+9(X zPZX2?$$v<38A^qVO*+z2pGH?jw0iiMgUPqqzO;C1-}}l_gjiFTe=zm1R|!Iy!woRJ zOI2A+Hjlcr$+Rz$k&;8DT%+$nDe~e^$90X(vsn*4Vzh;e9;tBA@J1bu6%AZRFSyd{jI)iy z!u7^JBE9A&MGV80-bT}tcbjk9*qmkp36IuMB{5Pg4l@YKag_E##*9At0O!T_ z6?+eJ(-s2L5w64{fZNxQ^yOdK>rY?#e&u(%kW2#tv>50OX7M#wWn`AX-MK|v+^lDd z!m50liDVAS?9&-yo`x&HU)1wBUD}~sT>?W3v`34$90Q3CbDR!PfGANMfAS&4WyoFt z(kOI=xb!^-i)i~|`JBAXdYF2cE#6~AnlNO>X4DPLqu$QIIf}gaMexF296OA<{$gn_ zL@Y=RN}rdNkutXpkCm#_;ATq~dtDlV8G;PEz zafppy`taNIUxL~jEC=Q@dgQ@|m?jpq&dWc{JnJDKY4J4Py94)?9bSnwBU-?vTLL|u zvu~}|-8{Bp=ctGOdJU1ZO9N-5OnbH{>6OEnbsIxInMg2eo4@>rKP!FCIJXDLqWz^U zyIf3Z$wedB&;IYBJ<*lMaPNKU`CunU2+bXYtKC-wFvB%M**2a)n5Vu>^$m5m^);Ta z^E`4zl4V*vZ!{gaamd1P#Zz5|>lQMS-17{TR6(^mJ^JLZsE4NCLda-*y$Zy8n_|hD zt=}kRparr`zxEWY;ibZ9xK9_?YD=FUFzUY|drbi7mhxDKXG_ICFyQJ>!Hhgl^%Em| zLq}^W_LV&g^#q>yd4PK18czuL#i-iErR9;tK0mgQ?7F5KTL)zl8p! zQ0l5=LnWOhz#Lx;tq(TNPG}K&-Ags&#!Ux?g};MaODy%^dOXBubhYXkc%6bx=rlhx zWuup@L%B*+11oS1N-d{q#b};WGSbK>(UT7k(FN#2HfNR3XJ^*SF@E}_UM#ukP?Wa& zP8V7G$2uKjbq*sz=tY74)p%#lF?DNX#VzWAWH9**82pnx4|JS6KLcrgs0%kDWgP71 zcV@?NSxzTVZo<25*;Oo0u8h=+HI{FAtICb6)8tIX$n%s}EIp!VsZ;{zz47+8!!^H0 z7k=4Ml*)e0y=FJ*ESSFJhKre0?sU!4@6@x+#AA;@ zdRCttT8Y7}`TX8(l%3ftvpS-(M6@*4>qs zr`jE&8|;Ba9*1fWKHEf*l+K*aV64JWc9n$Z|vk#nZHnRmvoK6#ZfJQ-s;s4Ahjg&Mgvc z)%e{l4{c7L3jrC~tgTYtS9VjRF}vd!sv>n*8Xa|eSKeh;{=9jq?G@kWYUWa;ui;0$ zdBnfy9gkt=dj}_M4Rx?u8kzw{RJK#T9lz`81H+<2gJe~TuA)bgIO1S3)lHtaAJ5UuO1yssyYxX>R0R}Qs|K7?TZ@dp9KKt`V^y(^Vl+Lgdlj>Ae# z3&&Iy6mTx=e#J%+MjuPF9q zgl$QCrPIzUQeK3k*P_OyDWp=*1&?Z&BbIv#H&TOIX|0XZm zPA>u1TTv*lLm|%V?9~}j7tz^uWk{XVz*COn`GnHKHKZ%ndjtK&D4a!X4b-W}kQkLbTpmcoVp(BpPH1`{z#6hDBC@k9`;affq(UW>RQ z52bBiR4Yi~Y>@7Sq6sUNE)j1wJWmy~HF>kdv`*8lLvJJ=hI|i+>RTp@Wm(wk_Yr8q zkfH(?^ElcJ#j3k}tm&lTFU(bP51}`8;PU`huU^7Y*f3fjLR52)Z+NPgpv*RO(jFR1 zSTqIcTTjshiN-EKmzExOHhaxK^#Gr`!q0H+WN;sFU~j}x0rmrHbWI9>{xyedYzC<7 zC2Tl=OT(R}4l4B|3(}v>I(BCuT&oD)QL!mr#`(Nef+#>rJXlR;FX3ur|0p1H+W;GT z&IrLv>QdL%k;p(aLpRZCgk-B2ajf|+lR+L6y|$Ei|B zxmD)W-z7D!l>L6JjV8iXKMqie*wlf{uGAJ$MN^&e2w+XVv3(~!gf?(FvOx+ZqcxOI z7rRgQTJW*XTkWH>Fn+17$I%QiMxN0IWEBxt++5#~y(;gg35zp|r-l1M^oc_MTmfFa8{!@sd9~J^U39e?38Ld|>{GQPKr%7Njt~;P)Avt96`e3Ka*A`>UKh zr01kPUxoTsB}Fkrtvohn=)!er9x!0syj}-=g0yJQ4&s1VA3TL+C|#T$)sbwxno!Y~ z7T3daGH^}j=(E#S5877UZ~vTu02st^!M14@QK8#)U}FvooyW|g=vS?>SLG(Y*<`9$W*Cb?yZ&Ph7~8;Yxw4Gbb)}r}l9{Vg(_)!J<~l@3|a9h1Mh= zJBA@?xJz#Q@8&9a1D85tOI{;i{`ZfCe7XZ~5LccmyHGi;BN))#w+=HzDDE*zeSqw@ z(pQO#rKlN}nvPb}ph2Kui?u1^gRn@2^t*)l{AFp#+6WkRZv2??Arj)b;1cJ7ZYQ}5 z9$u7qHtS4*3%Mon8ny~W!FH_M{J@qz(6r*eU`~W9%~&GZ)~EQ|aa3+$0NQ_=4wQ-` z$2E3{>q3g$tz0z~dB8Ec@jrueoG5Xv!cB@lV4ezGRQTgHmZ~R{X0Nedqc77iMnR1P z7oDNDaOnvIT=)6*sBmFD3aWgZ7v+-9fTJASk=|?e{Q!0$r1<@uoYi<`j|wA?Qx@~) zWeQOC_vyCeM*nmLX*O{k=2S01{nzf|YFj8Pv~)6oqhPpFb`d2m?2f-z;|f1RWz1;> z*{jX>9rRr+#g6jh^RDD>&NR6xxV?STSs2^_L1-yHKOB;%9w*gM*y?rRU)$>+9-+XN zqCQLAaE+dXYsvzyJGIyc0GGWwoKL1Tu3nBTN8^5Z*#%tb2f4?U-XyO7$IOqA%5qz{ zSP7Ge{T*wh(Mp%~uEsTblQ@^5b>Z^Y5jJ}wu6LPA(aX^?3%D+AJ817AjJ=baKNZ(U z(}0k)mn}yk3W0!DI4npuTvJacsXI81>%yDMwy*Vv_nBK319u?d9qd3(($(yLLK?XK zwz8MsM$t}%izV_xK$fF0VpP)ABf2a4%4`~<=tnev`agC{b&6V!f0jU+P~(!n2cV75 zXLr|#BX#s9B^onLKAm6ZinnTc@nnrxHxe#;(4(7AY8&lKTMyIeo`agX%W~$~lC?VFO8CsBra(qieW^i2g3eH`uJ8^P$3}{cg6{UHYDO z?mzqq5^@ZZDf1guXv6g$-6I-=6mM}~tmYg2gFRG{{55D5|9Oti$qfg$=<*3%Irb2< z9!}>Kt^qN0TZ#am_<-&j*9DDNN8zbV%t@T4 z1f);AwO``;Rtpzt30IZPa)pOM_m2061+KRcDf_oogf?$(^qDP2DJY3TA)S+?`>!EY z1H@jA+8p|m{W}Pq9fCD*nZ1-=C`;7tzhtjgAK}v@+N;VY`UDn^Xz%zus_YMuvsZt+ zim-AWVQt_nqT$q7>x(_y8Pgo#h|Z%>mm^Iwk{u4L>ddVRP+YSY(~C9aQi+WTvKP>{ zH-5q_F=Hiah?gr|#eE86kuXyM|IY6s`nCT=nWR>b(m=7M1}-U+9H)uIrCH}=hum({ zYD1ZB8gbSu>P42m&sDOU55atYL{~Zrp{s_VJywXz9?v94r~WJ))KHLp9#zY3{*9X0HG_wWSV7W&6Ta z(qxxj_P7?(BIQ+YEg$>-yc+>m^EvHetf#u45m)~aafvd|(_$TvQV%oei}nTkl5W;!S2A5vrg?{LEJ%Tkof7fAoGF-E{yzl>woMpxRLahXzl%DVk@LYs!?F!E0i z@>zY*4Hl%_l@6Tc?uu(JUVF9ET9)*8;O$F*uvmc`PazkRXGFu*f0CEdeKH%fl;by_ z;8`p}(I-_^fRH@?i;I|Fj99=u9Khu;qFX0=++MwJufd=9Q%3PeIQQn^B(973d3b4t zJ@t?lDB0YErjxn_{i)7)hAYQ6cB(*0CE1o_1=NvGJls)A zR#C>GDyn*0{L2cQN-gqLAf{=zbGF-I6sYKu8R1qTzIhXJ%F4JrbspVAZnwcOtdQ!= z36~AIX@%>~JOI(Fv={S)Cw1HDzx;2)! z(u`B$YK;Ab*Quw@Cm-WNd&1=zGIiu6?d-PXl6T)jJRGD!aPA$UYwnsKFVTCHebGl<;WYz=*fI}>XgVnh$ctUUJc zFp2|$-+%p&aNRelNy*luz!T|U09J!p{vDWji>BJ)HEmLn!D;l3;34#I*m`f~kcU5I zv0i@lhlU_Z-eOJ$mpr&;RM{@X`M$$F{QnZ5WOR|u=LejrMBY^74o9qii)qnGhRJ76 z85AEr51u&6q{g-hQ#_R?KY+b3ArD}G!%(d1MseVIf&;ja=6oHO_;}Buirx9Q&@zWf zuVF8^u|v?qC#A$R@o7>pQtbA?^^a(a{e1SigBKBKMFH2%DT9*RNS0BG5=9CBF}l+)fdosD}sx`*?8TGDw#XDT3nPx$MeWo~NQg zIpr>yZXvD6=uDMR;wV2Gjpnph_H~Ecr2*mr4kK%CfsSAGV0#pL32Xd#wxCXR%lMXa~tQE%ogBj;;gOd;Anc`qnDkMinmA!{QwYc%jz=`@W`3z6e{K zG9@ouL(~CKE)MG}wZzd`7Es}J#wp!}y;6OxqD@=|Mv(+lV@dX@hlc-DgnoVlIPc&h zGDTvaWmX=<&(K4UU~PkdXqUL)X2c0AbO4z$gQt1{7ra*Z!9b|{JB&2^m3 z=}lGg-X~PZE3gJfG2KQJoDv774^NCV{F%?`yz@x*`noTNnoxz8z0xfx;w^Yv|Mwoz z_6B2I?G|+Dhln1feXxRs3y7v}&JvXpPj)P9~d0CSo&ZO)I7?H%lkBDS-coz^`RiNzxX|9)2&sgd;}N zOcr2cjS>#f^vKTD?%C4WI8Pe#5@PI8;PzJYJ+KdNNSCo-918y&Nur^>r3w7Qh;~sEb&X z>(xfs0R ztd+D^y-yEg$2s8Ig#R zem`;@S(@0r3?Z-Do62Nw8{U*VS;@u%V?TLQOJh4}Rx>#mV4nuwKfnv)(%Nn9!%TM) zv_~a$4fC=&Rt;d8T)-~^rbaZd5Bu7Sd9W64x1y#D);ws*0sPW1IIE~FShWv5QW0DX zOHirO-}jySE3=BMOiDdF4|&LnIC0`c-1yFkh#NOD@+Q*eFFpA8I3Vmqi*D%5HDlEG zwJD1|g2`59J8a+`tdnSu5((V<4{_hQvjwi&QBcO&!4Xt$?oclq^Ni0hFD zqm0!yIK8e4xFEHkphj=WacLo|6_`1`b_1cAH1XDMk;0{(k_-88)YbDCt89OnA#@&r zEqrH>L@?uYlGAU}^jhblr9M}DauCQ(5^w_PZ303c(=tWI^q1hK7sW?3zZh(}N-XrB~_oWc8|+lqUw!74WxBATC3o zn~6?{tssSlase{LpZUu@@nl8B<=$mTiYF<;R;OP=kklg_b33w8J&BCclzAX0FV=9K zn4C=SWSC6o>YIe5hYvIWX;JRKt4QeWfWqY_P;DQ;w$|VzO0lraJe1JlDBjHw+A9>O zkW}v=mX*5vI%f@nPS9Q&3s+$Q{LXaBN=TZkUJloehrjTLReL~Kql1#4>}4?C2S~>c z(XnE`#w-rC-qQ>@S~VhrENIM;C*ZASc{hjyWF2l&HEIvPKxC$DRHx#$Jj`bF^0;>H zd3;NG3mDqBDp;Zb6HnOj>=1|Solt#9GpO;+>I|Mf*663g zrRGvoD~-Q*J0sZA0$W*$3);A_XK0ib%vo_8^8}_gKuV?${?xX#L=P8l`zSm6n* z(BLong5%3@?K88>N3pKZ$PTs`R!yuq-@2ft{Pn#IEp=%LLEgN6{|LfRdiLQgE|21N zo9CB3<|A3;CMS=4&%Z2I`77y;Ays2;-d%$Q=#Ti*R}l_I0fBi5$$aoDEq{eFiytUO zdP%+WrBKZHeVCv&h#p6tRgum!a2Z2c`69WwNVvY(L8;Z}`pe!JPy5^W(mO!nonxf+ zHT)VbGrCk6yjDTbH1vJm4Qdc{_3Q5gUhJW6v{v!TH~mqOJzqS4TKx1;KoixPs#N7K zo2sZ8-Q@VvQ5wTFN+G;hl{8OCbrm^n_B$h0ca>et>@VqghHuhe6&CzhU8YO~Ds4$v zei34m;@w9mRZU2F`Kl(>+^6_5$CuV1@eb4a{+HHOOkwCL95H0gNwtd5py@^dQjb3) zwOjrwB#f;Ra$1erwvOtgY(8SmZu>YzbTnO}=C33}mMYfx(yH7&pn3=h>@WnAHo2(r zTK6`LRaRi=GKM7)d$jkVqEeU-Ql^uDz;GRaTYxyI+y;k=y=AQ`TDvc+htpBf)}xAN@SVmx_3*G^JQ_Pzfn;F&K&(j76>2Vy#|kT5k%aW*R{(kI4Okueo7 z=r1kX)PraJReO*Zt^_#aM-!suU)MhF=C$+QqCw7dd3$2wY`S*-)w7lC{xyeQp~8+c z^ay5`hlRpayd_)|y?SEPQM1dG_BWYW&|kVV`_`OPTSS)r$&0#d&N^O7ZNc%SYplK0 zm1YaYvx1jQr>FMgm+{w2HsI`Ho$9Gd%9`f&O0l8<)vmJxBz_!vs^ zm8b02y~VEZ$$GW?Jj}j?H2eB{E6s*>D_pwww|?+3h1IIVL)V@o#!!#iBLr`aKSWs3 zkhtvmt5ZqO;A);F#NHQSs(`>G1Io1MSp9QwgXk{P6zY5;?`$V1-pS}1tsC4A-*^(pl62~j z2E@mBCFg>k*J=TUSG zfBM$HRkO-18MP+4AY4SS#y(-Vv{GD|K*?}GBj~tz%aalrErH;XLKKYbsk{%CwU(jFGWTJP_T4TonN<#$k;cI^mmSnhY>;xuA z^W&mz;=Qea5P!h+0YcFY4joxJIeG+1Pq?CsnAIkqA?Fz(T+zKn!&7a_9LowEE!M3d zB*fW$o&KukLv7$$W7l!D==VJ;{#6TOSY$iHyW59(dI4PYg4@nQZsaSUz@SFEoL*)5 zwY1Ca{Y$v~f5I$TJgwIg^I4h1b%mae;@Ux+uhEVj#nyBCHome|6U(QvQH>gWg^A{UZwA{t`hu@{p3^L*ZHj>$W^y zvqLdS2R=KTH@dAo6G16}TS*bPjBVy}^xXB0fQaM*R~#-ELVT$D)}Y)w zC~>XFp13*?Zr(!Hkag*RuAaZzhq#oxcLaU+1vHH=GU_qNaXlqZYOwrzrwKE3`ppkywaT@e~drFb%iIf+8!Mf zqj?<=?lY?*^;lbPSkGcsauvbv5LfN_D``Ne7U%C~g_WWomiI3tKs^c#S4V<5g5-$Z zDV=(v?LLIkCyJ^gAgmRwH?SQCwMN8+M=e<6gSrjUJ zyrbDe=UO0(C;UyMSu$KN?o6{~7EbqPOPtaW8~nPJRocUQ0STMZDeXocr?VbNs|%JC zZ+FV-G$mh*Ar-Dz-`!m%1@_}zl4S}R++t9} z<&iX8)h(f$1mN0{+d9{5_}2U3Cs~BcaZc79HlF+u1#^?_qfxzvWvv|`@c6@V5{6NV zzkt6nA8sO-LH&sLvncwM0jZkz?RBNKei)eFWSEc>4aNc0?XbFtxO%9qj!So$F>f%v z0F@}T!Oleq6%7|L*GAoNWS#7M{6{BDoY%?z<#x@Q&F{hzBmCz3^i(9u|~YKXQj z4A*)<=^$Ke$Paa^60TM=g`nE4{((nI>kqe`P2&p4nSA{35H@fjqfr;}^#=@bh6N>I zI{2&1Pne;v<&y#Z2aC=Q)w0V`4$V6?bdJF=lziNupROCtEIm*Jjd0t>$H16%bg_lU3|+GVS5q~ zR0I9hmGe-if1)+yM1d1lkLlk%VmiU!x!+zTTYaG7nCj8~?vBTpsm@hKk0|WGF8Zlu zBtZPB!zi78%WM48ZeN)Q)Irq`CDGaEBJag z{wKb)Qn;d~HYaQu0+|W5?s8iJ?dn!ziPaC^zlE@p>HFoW&4- z+BC%U3yA(Pe~nkc+FNO;4<_!};c!!6!jl|UYA=T$2T{o~_>s{1;s~TUzm3TsszqW)c z3m9K(9A&cI<^XAdZgy9f9=Zrv$+0qN!?h9Zq=ZB+{Ye02$rG2KR ze&|`LCYPJ~{AI`{9>3`klALDi;Su?OznHCWjy?rz^r!J-W_|E91IY6;_MAG_$%Yczq*Rxw_~J5?p@~F zp;IVw{?g9x&A={ssEZJcsG+X_95C(vEhRKb)Bhe>kw^IUyX+L_lx84* zz0Hp?j65QYulMt$Z2}JxCXX4w(sPpbZM6Gh1Hif@3%^t0I?vXq$*%${J_F!In2wLX z4^Gt5r*#KxgWJdu64z^4nQzr^v!>E?=C4afbiXKN=npzdK=D1=PW{k6+n5_y%sXSE zsV@qugR`FKNmwiHN1O<(Pv`^u@!LmiHpW|g{CjDxZeIcTl>TaI8e-6l$|ffPIXAcg zl%Kc+laH_J#PnJZb#DE#z!hl|Sog2?r40Hh{^p`MtdzKD%IYjk{3HyJWtSkXC%mz` z4-x!*U4!q+h#!6kB~eq|rTq|zl{g^W%ZQ8q6KMtZ##TU~a-Pq}*V`rd9di_Ya2!zxWt}cYpMcI|Dsrjq_R)+U} z??4(qD%(A1z6#;ir%HWqBlghQ zn;;bI8$0N{`dvtLsXqftdd=elKe&pTjtiCO5~t&vwR7so!Ntl- zh$yEUE2z->y9` zQ`n4v!${jQ{i9cq8Wb|a)vv%S!_Q3T`T@i1p8lGjhO~|OOKqxfJ>fiWq~0fk8LnOf z@+3pSM?-Hacr2`%n~SFWCE1NoW{J7T@M6?a;yFPaIJ0hLi{Y}}tx(ok;p%gqKS4uC z`sKq+l=ZS)#eUP}g#OnTptE?qe0o7#x~}<4EIpA^cCp}QW8S1rQaCC4h9nu@d1TY| zf)%C<>i>Gxuboo;4_^w`DHVNPkwzFKEzc!5)Z;jF9<`7f9yF*+Zsd$A768t#R@fee=-t6|u%70pBt%>8k zsG8Z5P5P?#w5S_akfwr;=hGqB^K56l0Ip)YKZ*j1x2sMuEOEIGzUJ}X@Ib^}BDO&+?>E~O7tNuBx>F^fODb-g70sL#I z*hs6JULDspEH&~>L|a+KpTTuQp&(pcYbj*6Ze|Ea@V~pm^#!&$^dDW!dEn9q;ijE3 z*9c$dO^zRX4lM+OZgs1(`~=ZeV-dD~*P|vbrbO{^nsVi0DTd^~DzfnilTkPqb<;vk zxXRbmxXG6pa@J6D{N+RGtm3RR85e(w;9t;*>O!xil+t~G6A(-g2-o;8&C`(8=vK)$ zxW*YC6&*1?+=J_3$&xr9j!RsN_=~GT&w3hQu;1Gy55kLt**!+sHt&7;SfT-Mk63`~ z$)Wd@tx=2ExB?el*<~M4KOFtz|B_iEnoX3HXDQrdKf_d4z~TV<8O`QRF%Q!+wTQon z3;%OVx7!6S+ZWZQe>=worMA|nd?M;S{RPr$k_+If+1ec$E;{gWpIM~u&`KhAu#$7J zaM=TrMDcBphM1jm9gMG{NehiHdOENPYF)cgRARVd{`z0MZT^DNif%|Z-i7+c5z^9* z1GxJ4)jJSOI6WtSQF^KO9+gDt)q=b5D1corl97ut*lv%)ie9cCvV2Go2v?HNZ~!xT z_H%fJ&(rbtCmGd1IWCMhcV{!pak1~AIly7m92^nXF;XagCmzA-AXf)2TrWwG>^;1i3++wZt?}nrCETCERX(V@_tFtc(gO8L?~{-zdjYL8&)xRuj0fV8j3=J~mtGDN zZ_fDZ#zP?b{?iO0I~Bf>fS`^G{!({KCQrZ_6&)dJBuBaETyv0uEfL$t^e6nq+D1u+ zu(ALWXOk{zxIBiAk#Mar89%;N2)pz`>jtH*y$l!P<>EUCT)EF?{ZM_X(fuAYjo3P) z>b(|Sy_cj!YMzgqnd>@&k$k$XBVdF;` za3wnkNpAAhAq+%YCSUG*ia_1OL+P-W;guD9X0dH&Pf8{~Ve4qi_GH5&B6azocY{mX=&d1wggV+^k4v+= zKMVmv_1zjSD$dfm%AK=WW!mXe{g=n318ALF#g*K_8)`G^ckjkNzl{9V9}-tLDJq7Tn-JeL)q10< zPNpv~=x=8jieXARJ1Aa1^i%n>i5_oN*4F){rl?MjFlG=1{3UF1wBixe&VC|=ZB*vy+fS>!WiXY~V4Pv?^#B)gSy~7q zPp)e1c0h8*RM3aesA^Fmc~Knu7VKnarz>2xp;VQNJ$Yis`J4={NyUOIULXZ-jf0{6 ze?Zu~eMnq=q(y_VM-CfaJ<;Tgs|wc^vTdUUaY3~StI{koUlhlmbC)oYzwp?f(^zAp zwg?T#=n2SzrDyC8xFKYlUl(CqGZAg*C9i=vcVw@m8fMjXnt zm6tNesK~s-@Yiy2A`bLwo6uKEEAU%ED z0#~!I9H-Y9yUGmFP6n;gr%`+80Um#Kstx&CeRYlJ@US9q*%b1eBQ=2b{{@>V9G|Hav6eN?-*c$dXwihd;>uz25-1LsuNk?7TaftO%WbH zyeJ8Sbp{-HM(^18E0Px1a4qI9;2NNc6^Ec*)iS!sdWq{68+GqX;^J)3V?V_HeSp;C z4>rMHmu^5V?C%GRKyfv8gzM7e0qUrAyaQ^fBB=+D=(XGAE3$s5L)r`CdNdjF!ynED z)p*K}O(zickqrkSNQhwAg};*fU!qa@TtzPrsHt|=&c-AiBF zTOLi=&Qp2x8(I}!?jyM{E*SVEu0vML)@muDZCK&D)I)CqK;-ARI4V2eg60~S=r=P| zXOwIf+ZlC|*_4p^Uh0kZ8T zwbB4bpYalDiHmSF<*P{TY|O(BbxHq>!H{FLk@d-wSR1M<)9rw?yPhGeXecxt56ObK z{P6&V_>oY3GP3S*3qtePFTt!3ldK%A{Q|7{D@JSa(juhwv(|4#w1enY*^*TcL9d*9 zEZcB(cy&>NilR97mdeBS12WB&0lB#;_Qz|eZl9A=<*(TMg&Z#SfQDVFBY$x|v|oYB zab>`@D_jojdK8c^s$Swe2p$qPG1)j$9s+CUdTE9Wk0I1{WTAoBaM2h^fK zYC5b9XT$XYua)4>aePH z3ouTc(rB=M*y^>ix|M%%7<(?W?JG7_N$1%Rqkt$8WFkuV{-|iwMNlD#c6T!LQ!4cd z&gfRFUXzHy4JcXp%lXob zYQ27mTkChHqw*t};1(|@+TG4joVfD=NNzvzj6iBvywgDLMrklR6<^(#!#1;2hYBfZ zB#d4f*YI=JS@|o;0_!8i9>Gcy(58D}bAQQrWtXzgNRx8tpaj%^TH-p-bh3f^ovLFp zhj7(+&t`j5SJdbE+kA0%^t<^-S`fflNTg$hPyR4OZm6Fh;Z2Fb5xvGvE>is;}r~qJj~dIbS;ntl_=ItI2U?Xzg$^Q7x>b92%<8?o?v+ z5nFUod>JI=NGnC(DD&}4)OH{@uwbu-OTBOI+LGSfsxyk`qHIQTTJj~v*J;%(E<63+ zV!mZ<8o0Bz>LbHtf%&BBl%S<+;d+h###mbs&QV<)rj=@sJshq&&FZS}PpY3dn*~`= zxMYCoYM6CGa<-s0c52F;CXD#1^Z2O4goMw(hPK%9QixppqavX@MAv-?A$N&#Vx2Wy z1J-;Jmxol>?C};mH^pE1({u%a8Sw^ixntF=NpPi7Und*Nbo+i*@?dPoTN3Sw=-BhQ z3x8GW%;5U_OrOL>G|c(-WFcI(k3HOpR@)G6VsC`Kx;?T&uIV%B;=^t$W42i!vXg&YXDT#J#0R?(_Fpbnh=D zidPY`qIOG{pUQhd!hJ;luI}@0+rx#7##&d6kB|xjwC4XTJ3-v@5bm;dF>>shjB(p` znc^bop$8jv2LbAY5Ff1NGVDFza`y9K65Sdz4aI5dBAHUu{XWBa3Ah59w9oD(94aVW z`W|-lkC5;Fgi0cP!j9MMG9iB`u+7rgREn_rv4mznKscakp#4R9`l!tt>**lx4TXl{ zSBuo(y9GB->^^$x3tZKEQ%9VF+Rrl7Ky)s2&x6%n>JUuiHPiyxK7)u|a7|nlbgx4w zYKrTo@R#r9GShd_pB3rOHB@!_>?{@jEZY3!CVL*;{BsVa{kuiE(K+Bsc9?9v16=#; zGj@7m1cb5YHEb3Ch6k&q`}1){dl_^(522TFx7vtRx<^Mv@)AunhSXq(C*d@E+D{G??kwuWM9VN`zx)t==8sR z<5WmzaP{t&^M<~>bL=v7$_k5xwqBgi3gcp&R6B z_pja~uES8|SF!EzT&o0gaKN<=T%V!OwYnVrqNf{O#Kh8mcmufp_|YMF;&S}?DZ@1c zm+xManeB(JjteGe4q36C!v2eu?W|h9>>*)LIV+VvoQG_0*r^UDXfW26CD-i+*vCdLUN$o${b^ z{2yK+E)KF;N+d{U#V<^|pR;Dohs`ys0Q%;y0l4@R_QU(~4YM8RX%`UKFJH2;Ijzx+ zEMw&Ef0^ZM!jesg{*+8YE;C#%F4FN|aXw7!rdaBTv1W~?g=eJlbrk2S#>gr_iJRKj z?ts(VZ1JrV4_+9C6n=`pdSh(@(_59VGDj3w{V?GTx}{5i$6v`YzIy3EV3tD18{DW<7)z^(U>5In#?ObNAb^Mx~$X(JMs`Ou}27{|ofV)@|p2505`8hN?D}a<#xXfR` zinmc*4w3sKf;U|M1BH8L!4Isj_~_u%~wm{CNS zKvFQyD>W6g-()h$ri5oC+{VB5P~q!6l5Dk5-g~zT78Z)!f465kEmq!)>%V)=RZb zAw|?4lt+>ViHD$rzgZgInU$QKPVNqf>)A5IHcpgEVVU>4+G^0eS+iwRe#9?)2;9R zOGYG@DViSW60Oq~gPR*l%pU}(a(CpF&R&LSnvz2t{E8=B&v$zV!1eh|cd%K9VFI1} z@mY1$G?^WH1o@BRF#j9}V(YcCI_2Y|H|9;#?{R$f^lq-{j2ESTa}to<#b5h`r?L5# z9E>yI;_TjK;6CAOo%InIvB^3drrUUJUd`Jnt?L;gkH4hqhq{e-UT2OdUny2jE;6Dc zT5P!B_!JmC)dhxRhdQB?E9N(~10as#fBJ?$ktQvjcwCAuA@`XFk`rx5x20 ztF0d&Q9o?5AKGP8`Zrb=5|FnDL(VqeAeXMOOxf?WWV%%0dj5^E!I8V@ zykQG8dcS>CUS!2(5O8tb=0^^-@n!FT4aCJyTB37(aQ4%_@>f(&E7-*H$RoAnFMb`+ zwfLN4#FEK-MJl&gnVe-79bbdq2vzWI+J0w0%WLZzE_Eb0B;Mg(?c~E0A8Q1t*#6MaS!vV1QCf>B@^MH)IDZvKLSjFOFVC^c?ElpL%A zSCgz!im3JbM)>T zd~}ZQaFmP!($MeacvRDD9C?Q8&9$vSFiL}`CvuW ziwHda+*On@(zLVkyX62Iev%bgRh)!^e|_?_VCRb62W!w<$6qVj&hjDy_A?{?Itcb_ z(VPoC*jlfc(=Yr)TOLB^q2~6fFMo}}7=8CY85Zn#asc*`M`!F_FNFGW!PT!yT%*Gx z=hS#`Y2#G+^Msc;zVwkoYxu~(lb(DK0-sI&+*qaOCt!wQ#<^11`B)@HfC^ads? z2vJF}K;%(Ja-qbr5(QY~cS}1Y;d!{4tmgFvaos%4U)7Fw`%B@XzlLK>PB(>1>!^oO z3NVLWxNv3pOCuEtbh)Y@Y8PKeuN$xbT$u>E!2{P{l(?F+zu`kgZJ#uG8(DN6bw#+w zsG~N%>bQ12`yp(7OkCeHTwUmYMuSI(42B+o;bM*`zBkEoR^uz7zZ%`6To!$c7HNK5 z;VLrf@njO9G(@l{uAd0kEmT&=rH1kXtt+>Qi~aCWKk+DBdz=#1V~;Qk2*wNyS2;%9 z-2}p%&<|HQecDSLBy@k|vAO-8IvE9cRN~XpG)-82mo;~;FShQz!uywYiCTkluCjy1 zyo7K?!nI3WvElkC!{@`oyar_uAFh=oRSFlzYrtrbFdKSNq?)|RLQSSTn_ z@B&*N!i`>b5?6iRpg*A)y*jzaNW_uWYOd!go`Na+a3QnUaK($^n%pG>v>0EtyXmc> zXmyw~Q9d8O0;TxjDj?jZdhHncIK$04(ZZKy^mb@6_%UM+LXq8<$;L-XU|dkMi8@Pq z5w6^frS2I_Jb7>gl>z=*{jzl(`cGuIJoicCKZd5^DsmBz@z+c^0z|_jx`yPcet0=L zFj*9b*ypT8uh!>^7vq{LcUA)XFeR?jK8k65_qLDF7B;L8aQbrFiAs}FGCW$#`9(HU z^CHi|^|#B~=V$PqGUB?3zZM#eXqp;v<}sO@5U!|yp|#Si7Iu}ts@$*3{bw&#L9gf| zFI9TBP=8i1cN$B#=lE;o8Y*$wgSo5vCKNj_UrCom%khQI{v2H06ngIcUmLCg+fgG= zUbsRE?iO!Ii_k49mzxFdJ={3rtEW`Z9ivOR&dcIz`)U=h+IxQbBCAZEmrP5EKz2Z2 zf$U_GAv~2lr6)Z54=GJDhM+rbd~RcVcP1!9J*X!O;?m+vRp9)*FY6+P@llx+v(B(9 z7M%uY@YmC{$WT&p8+Cn!*&k}e}_^rwtUfy@%~L2#B-urXY$JN!V;vMZ=-3K#ps z(b4o3ZZVnTLeI!?9b%FcuHEenxRA`L9SSb;ZG1iD3OlFuf>9j%6!Bu3S8FE4T*pm*1Fm%Q6O0J=gdJSuy#6`{jw%3GV|CDG)21y({h*P>6LCe zopVO&Z9P}6K&yAJ<}a)u65oOJ=>~#!oFRSNBRDL2O1wn_>u90V?{zq2M{kz6+(wDZ zPC@koEbwjurPBzw0&w#fV4cQ3PhIU4Ts`~w{8|){Nze4!xi4~MwKLwklL6N-0FpFE zG=WI_hj1HOvllbOUv#O$rSGyr#FA`n2Y;>-GNVp<8LoZlvL=4V=ZW7KPPeY6b1M6U zX3}ugs~T!LiATb1xD1e~)Y7JXxC$vL-U=xYs|P-yKV^rv-)A1F(R9XujRRQXstJqC zBJOgEPmYRY9yWdW;ksYDe?gYxq8l{F_9pD7;T8hX7EgX8L>zCH{u=%~ z&#gmfX@QjE%1ohJD(3|T`yK`yK>r4rb<)+)ug)MdL#Z&{g6THtLc7d{t_@paq%*hq{c^tVOvKz03BF#9SOeG;Xq`1dm zhRk1s{TcC#lY_7Z1jb)vRHB(O40a3%Y-L6sBb(1 zu5bHcAv`^1MfMPOdOoFBpPOa=>OVLC)C`R;9RzQ6-}X}~)f6GIBY1oes|12TTx*kU zu>Q2}Q|Nu|ShyCgJSU1&y(7~Ns>=FixtGEwK*%W^bg-k_*dh>CcKithEN6sK;A{T{%RotmIQ?(C( zmD@>j+Ke5a%$QR$yFK3f6$(~IRO~}6Y*gV^b(bLrX2RtPBK*xh<{XVZvp{<1l(;yP zal|udZD|vc?0y&ZnQNG=k-aW`FkP~ie=6IrEU49~DT(D4Tg*4#m}{b44^GFq^jUCv z&TWCDs!r{bYQHz}>Sx5|_I*+1V3jbr&z-0@ zM#QE4-l){UvA-Irtu^|m$>RH>=nrL>)-K?)+6*+@?!)>T>i)R=-=9} z+Ng&rkW#Bt&WHbBmzr6MP(M1LdBUR zw90?cDMfbo76KcDZTfJ9{jy>GkU4_n4j~k^57|)B?{JyrG!_1xay(hqrS~ny8OJ@3 zRrQ@Bna7Y7RAUR#3*vS8tH(m?mD(CuM_KQ1kReL(r}KyQ{VzR|tnPZkq$@?jH9ku7 zWNmyIF5M@R(mzsbRJb0D1I+01(naJ8CW=DE&cUrcp?-&&wjD+;+Ji$lcjKp{*hPiQ zzEAlTlkGzUZybP~>WA>}xYUb^*R#@JF~^g2hj%D!(+soYtI=Ge5~wxY&BPEF zI%|W!%@*HRb-5hED>RNsdyw5mk<4RXrfKR0=+d#zwPWqSE1^$Tge$StQ3|o!*4PMO z_a_Kfxb&DEUyWvQ`5G>rjc!DDIf?2Hf+~y}!$LheW-70YCu2i@A{lS z;JlIJdaKCSjkZy(=luxkr{dB#susmHyszHHtMxL5qz=Xd_GYnMZCCT*c=GR==kYiG z0H*(htBA&@Dbk|YBkFW4L0s3foF54nr-XR(%|h7Q2`FCm{a4N-|94LFm)0Aq9UAk} z_&%&|PbkBzER=$a!wL@IZvS7DGJW&5N2vP0hca<* zVApx)Yq=~h9X;rzxP>OAT}ckTm)m^jxt;iOI+ITy;0$+p1(#-+_5$K-Bv(x z62=Rxd1dQ%rX)V_<#S~-4wfuJPbM(XgCCjsD8W#{V)+nZT9sHOJBBdFMVvKUE+8#j z?%ioz)&}H8t&6|u8H2_vs82p_uWbZMkkn^@{c_%LKYg`d3<%Ru7^wP5O)xL(IL~W+ zq2ZYq(-flFK6G(8Edren;9Q14w>Ev^=QcJdAkB0k{L+e-9INz6ao0+EdOXPGI7K#` zWM$$sh6b%aXq={Vs?6?RTBP)jN)4U#l~+EOD~ZjjPpH#lprZiEbDxVE6)u)GYS^Z6 zkvuz2p>pcWm(D6$`%wq^$Ml^q$~_XUi%43NG5b7g8zE)sV`qT ztIFE1tIu>KD|xM~AkNZ)4`doqhWiz{Uo*AqBV^udoyV;7H=J5_1N$4;N{;?W6Q{ay z)xze?i$AKIDK4E#eZz_V3);YY?n&~6Xh6nh(yWlFHaspAX|A=R7)zW}h<5R($X`y> z3n(`zJ3%#D=hZP=gtKS`TV37`s7c=A+|%33kPtXi##$^&63wp^XgtK#&mEbPg#l4& z>`R2QSgqVJpdDko;UKS$OEWjJ^UIZA0Lj+|%z!HbV~}2tb77Bc3Bz9f+Gv!++nD_y zQLCciAAr~F94g`boZ4Ak(+ajxRXiEP)@T~m7qvzWDATAR2M8XKW`7Bhz*oyVj7a)% z+~`fRGyZb3xLW@WwMuf6zXM)NsNV{ubS}nGe~qeqsLDy*oYlpAa~tRudSv_%%veda z{#Rs)3!8Bs=-9CgESaQwokzSu!45IiY}bYCgugnhuOg>UuCG$C6By1mi~CoLAl=cw)R#>~`5GJ&nYk90M&ly8i{9L!z}b02gH<_$$jl}UGMYR z8VQvCs>G$0Wbgl#gJ>)xCL7gTudU(|hv^I_!5DOrH0S1vR`i`ieQ44vOSJTodo}^D zs0a|#LFO+c&}IfM3kZ8~XZ-94+^$a{1Y_iyTRvwKj;zi*1mZMvN`9KZZ0^a6A?kGs zeo|(W(XSR0q#zg*8PPoA7+vC zq}KV)0IVz`q5A%;zfPR*Wf@WJKxZL(aXg|)X!RPd&Kg^uWB_z|m084P^C1#>>)X!) z*sJ)%M|=pkiOZFb>o)mAj*8?jz1Wr&;R9l1VN? zq)Sxup~hE~R{7%k3SojI^D|jzBm?tl^=RFU18$&SZ)9ttfx0Mf+1(2}2t{gLcb$B| zU%bIKK47B~eJ+6%o^s2f)QCMTe?V!5z=-~8%+7~to>@eO3)i!c1q<;Uv8N6%8I4O^ zZ}`Gr`6`de!G(u_Kt;3qc^1+$vH9z9om~vc4NFNbbl8wNU-0{;)48eH# ztHX+1A+tKC{FNfVC=FI*X_RXDG#AYodFZK~_zlORh~6Gz<7@3F0n!2gx<8u2rB_=! z7IA#tLv+A4x1s=+lqD9sG-XdY@I@ph_wPPQgg)gw0cw2=@#l{bv;#0#sO0PUD2GZDP8FXWM&bJFAv^U z4CF|SXY75Vo8Ka?XRN-2VIR}?TUT?P{Bd9gmoI3JVv1IqAsWtv~J_oKq;x*3~h|#APGOQz>Jf8##@`qXh#wKb-qyov7Z>J z;il5UXjHR;p+__c2v&{|)TkFw@%B2=W%wJ^9?;l0+c}gw6P1Sy=oKQ+n`AAqH~9lF zeDN^8o673uCbQk#>UBl+wlS|(y@Sm1d8)~69j@itXj9G+BOsUacvQnxs=QjgvN%;i zo{YmHWFcH-ZHqIw8ajVKphpnIb;4OPVj$J`H%wB7HHf9`Zw}-9X>G~Q=h6-)yCp3x zu(ZI^0!s@lEwHq}(gI5hEG@9Kz|sOs3oI?Lw7}8=OA9P5u(ZI^0!s@lEwHq}(gI5h zEG@9Kz|sOs3oI?Lw7}8=OA9P5u(ZI^0!s@lEwHq}(gI5hEG@9Kz|sOs3oI?Lw7}8= zOA9P5u(ZI^0!s@lEwHq}(gI5hEG@9Kz|sOs3oI?Lw7}8=OA9P5u(ZI^0!s@lEwHq} z(gI5hEG@9Kz|sOs3oI?Lw7}8=OA9P5u(ZI^0!s@lEwHq}(gI5hEG@9Kz|sOs3oI?L zw7}8=OA9P5u(ZI^0!s@lEwHq}(gI5hEG@9Kz|sOs3oI?Lw7}8=OA9P5u(ZI^0!s@l QEwHq}(gI5hoNa;sAA+>j+yDRo diff --git a/libs/spandsp/test-data/itu/fax/itu8.pbm b/libs/spandsp/test-data/itu/fax/itu8.pbm deleted file mode 100644 index e2b629fee5e5a39a6cdbef604bc7b8ca5ab7020c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513229 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 MRk^7fp=a~;f0@x)a{vGU diff --git a/libs/spandsp/test-data/itu/fax/test1.pbm b/libs/spandsp/test-data/itu/fax/test1.pbm deleted file mode 100644 index 7386383c271fa0815a23ebcc73eff7a5157d940d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 271883 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 XAOR8}fv+q9_m$l;ZWswXn81Gkh`jej diff --git a/libs/spandsp/test-data/itu/fax/test2.pbm b/libs/spandsp/test-data/itu/fax/test2.pbm deleted file mode 100644 index 2158620314e8144cd9055a5cb38c878b0a74bc31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 279213 zcmeFaZHy$xc_tWHS;{P0$*Q8Yu#;wSIw|@r@4>KhG+wEAYE36i!}0;%m46-d!?1Ha z0=0+Lu8LtT0;^U1s-gxqjkBrQWjQsuI{JG2TegEG} zF2Dab|K87uHLWeMw!qo~YYVI`u(rV30&5GbEwHx0+5&3}{Qubk$pt_7e2wo+7P#p4 zOU`t3%VrLn({heRhlcGb(GZHm=`_J};gu!DLIA-8h5ugm4AUEdG>6Mv6Y@gHDZHgw zT+&q`x}pyqU8lzzx=_aiI#LLK^y5%*bP7K2*a-4L+9R@@vv^ce@EIXuL7}!&6-pOk zKNTAa=9L4>t>9}}RyY#k_Yv;LWl~h5Vq>%U;eyQkh!&4d#(G+|= zPi+ytZE6CW-bjRhOOj_LgD+-$4Iw@`6h5gWG~G=Kc>$bM3@*Xb3J%c}e5p`rf~3Qa z65@t`S6&)xBS>3=zDz z&jUUkYAt?4k<3{rh2=aM318(1i2-UF4ct@EiALw6#S^|g#frQVl;PyGQ(QX->4k_d-ENS@BoUPZi3 zEG9+C5gmxv13r@Kn;a&6DK`~Opn;l0vY)33U*F-2y)OXYYlk97p_#KEV5Q;)@Llq{ zRP~m8NnI#rLr4AyhY*XT81S9cqCSm$o=nhNHSqZ=06tig)Zp;F+rT$M{Q@5fyusQr zi%9)r@$r0Xjimck@r)M2E?l2M4A)gr^~j@SsQdbm&r-_0h;gxJS7aP;J6`=qu9V8+f~~ zcq2vl#3xbU9WI6N1wHZRwZHy7)Tm}2oJ~{zia5Xusish@$Vn{YW7roV9XI0}GCmry zL48k!UmbaWqX^&V5bc1EgY6fk;?3)~VqYSgB{W39LR@3UVew^W$A=<9G$T^%hol)e z%whLY(<4-_qSWsQoK0w`G4&f|-tc2V>?xB9uCMC&VD4xY_Cq~*FHy0;_q@R;v@agf zBJB%*2&+?FW2qk>iNZMqTtX?*#=1_`YcI<$h;$ zBra>=OC%#vU{dS}numd?{k4Us52F}oKuIhCODlmX>NZ4FTQocjE*J;Sj_)B2XuGII z!Y3U*?}Z<}B(6wsU&3A_?u>-N z4dWli2~Y8;N9~W!yl78g`VwU+DnjDdJX0o(c4Nyov%vQK_k(jQQk@W;)~*)TC|VK zyvv1lG@VaN9PkvS8QOqNU|BS-oddYI<_KL<-S>Z}h!LXUoQ+}} zA>ktOB+W)c0kr74iu(t68Kn_nF2&~7;t3Xx#5Yip(}}t>AIkLPxw-L11s~_)+785q z>|dp-tk4d_6XIAl&R z5o0vdOq39sWmQ;TG?uFxRn^GpVOBMXgEPhz{-#kib7>Gv*Xp_D*ek_{H7+yiBdwHU z$4CfIC&D+NWt&8me1=hRRV6$}kk*6G!Z)atW7SqHT31f^uqM$kEBWeDh^YzAi44X! zLtj!3+}uo|=p=ma?7GD~ya0Yiv1$f?20NlvqqFpt_}mecoH2ceSXdex_#Q81q&04? zKUZZ{HFA15@}PMZK4Yx`v^ZQ2XQ9|8gt~%H8f!mq-xw%lIiTv%(_*pzrCIn|wmHGT zuHu9*>k5OmVf1pwXW(0WFNyC}gpJ(7?Jo{c39fZj)PWb5B?Y{Inga%3=u=N0mu&QNEQCg>3ix_@7#0(z8v__bNF>EnCA0(xIKw4Pxd8Q22RuhP9lfzX4Tq+?{6h3p!L&p zQ##Xrxq>E88w~*V^Im>NVcowXR!LX~Eft1lLIV2%1SqxkyJ7GtW(J|a@e)3@7`_ad zSi_iu1>!NWdKTaC12UL`@BOqwJ7#>b?M4pYra78Biqy2*STqd<($}Ip`Ws@+Ln*1B zitiEAphax(`FcZQ@wloh_2v7h0=i_eR!ltz#4%KJpQQWZjUh3k4RHzf1-_x!8X7_3 zpF;Eo4;g)uiiM|yFBZPq5WbwmcU2@MJ`#nnso$JlM-ex@Bkm5p_W(WP`+~Td70Nlo z2~JAm+*JFq3R>|`h0==qOE``Rd?+*}d{7a`LUT#2D!xy6##sG35Jd$@yeG728^Q^= zTv9@>Jx|4ViA8Yi7N5k6Z))7qG$;aJdh)L;W&7i@+rbi|>)qF=Sq}%l?BZzWse2k^(tGMNw1Y_mmdECp1c#LU@74 z5aFZtO!k|BuT5|B#?%;yYWUQ?B7Bd?Lq%y&K{~n=o`(|OQ`7NXlQuu$v&WlF;^SB6 z14@s#l*!>+`*C|z`;szkh%Dn&>A9;EBYcXR_!#=9+D|EDr8k%=_(V9Nu0`$7XMAX@ zOco!)S_r72MvK;*fkAY`c=Nfy2ldlr8Q;#4!RN+<8os2+<~@&K?C^PozFdfXgOA$Y zGL%x^ZA{B4bK*iT*)O0l$l>Hj&MrCLTOz68+j9w-5dT=R{Tz0eGOv%ynSrl3OLigQ zHs3IVj#ZvpAKnd5i#+zlv)-aH(xg5q|OC6jIVn_1{SdC@&vi@BtF#sICtTAwO>!oT*arn zk5*-7+#NL{jIWxxnsff}Le-}Py+T^hiM7XFH!ozD4J>qo5~b|yiEa}7eYyF-$G49E z;)`FLRWP4=^{mvn`N`ap5R@$Z%ZDFKIMBii>E2)c({FKP+~Gk?jdRZ&KRii;tS8#h z!~Y+T^LhfsX!=q;QB6uL!#VlRzpSg|F2Jmxn=-G4aP>q`&$?`^J!M3l*+ffxRGc0w zQ_Xey9m{lDv{%JvtLGyw)A-e59bfLmtdIDV)8&}ZqS3U9FO;0UV4aL_yr^#Fyg8n> zbUg1>vf8t8VJ2_vc~y~6$x{X~dJoIk5}{&iwQAmeC1MR%Op+GE7YIMAC|f+ZaSOYF zjAzR$410bkE^-exsv?6HL{y9t4Pk0@VE8s>Ba`0F z_9PD+@5QNX+(sMYZ@24Lb(CD&9L(aFz~{<6x&4U;v#|nA)LjuxBo_V9rs&NH$hg60 z5_xFJMMkmWEa2>CMCj>h=zxb7Uejz z4Nd(O?VPrp0yJ!yBii@@-?guLS_p|SQL~Ulq)+%BVSd?zO!O4jw6m_wstV}>YL1>k zbZAR<6~7^w?Q2}lE4Iq@OLUV2VWt|sl<>XJBsc|D?i4TP^sZ^V+>mSrHV?x2>!#gc zA0JL}9j9`-jFAF+zo$p{ag5ZM{qo4-%LeWy9xFTDF_wGih{uY+DM!A(&6~XTi0EMt z6Q8%)Dee){R$Pu!#rSUa=*9@bOt4>GRB;vo)(!BpVZpO-Q~ zOP;+fH-Hb@{Kz5|f$cJqE5>)DM?)mSOigd3#ltqj_;Q$cw<`k6o5u_Iu^U>rpK9QX zGndI5eMg#bviFSad=24DXu~nCxy|bX1l^pZ`rT|%*$6W=$--A`MD;|}&@k__*y&AL z<{Vz+eU_ynFU^53&0U`GXRd=hwtH7HH|JY~PC(GTa@0C)E=IsnDlCf80AVKXACKFJ z{58~XCVtbq74w}&)2eLZOpi|C*sl%+MV=l2U!GTF2PXWOw=X$F)l-r;yjn&y`ODH+=Zcmy=ktg6&B`zOf zOTe*f2X*w17)Hyz9QZI3l1}DiUu8Bu0KP4B(!3&X5As)l56`bD4XwW*PjZYl2s3R? znWUm<8j(HE;)^3xRYDQAU-(lae43j{D-n1yeE^Z%#^Kq=YvPxEp*9Y2g__kSSOvZz zWGNf{K%wzyg4U!h;xdl6s`#jxXl9@0JSMFK;UjzHHV)4%%i8pW!a>t6k2BjJWuqUc zXqAlbNga$7Y?C%A5S5)=4%uSCviPYFKeCUtza|B#Tz&z1;rL%5%T zbB@E;0=n4Z!_m%3e6Txccc8lcu;ZjvWATZ9YPS}(4UG4@bH!)`Xp#WxvkQmtp;br| zCz}Nev~StV;mhTi)})Nv`YIV? zAv=E_Mvr{ZSX(Z07ZL*wVpq)&b zi(_l_OXr1ep^i2MalOSgr%2piRvq8{#WJmQgYV+m&0#h8HeB?=`KJATN?tf%7LdWW zdtdRX6O3c<`6o!6ds0WAP=vvUIbcbKRmRUdbg7t3O)1HMDf({)k?M4FN{*GY;%Np^ zwiuIEjDi{1^$C!bJ5O&KK5Yv`T2M)sVBhn`*tb}!o~v_U^YL*5mn1RMa+58`TZ!Lw zTDC-3nKCoiVd0vywdXJsK3+D=k_^pVj5v)e@f|+z2ck26HqfpFnm*aq@8&&ddES?V z#C0XzZZTD>ocs#?uD$Zcd^!##6z5hsZeJ(_M;ZJJ3x7{f0?@7WJJ#m{peqqS8KMqHPFKG17 z2j6XjkDAw}Et@=iW^HpDK0PE1eeML&Gk5wme6~rp2wz9zQw)@G#q^Lp3s6}_eIjf> zWWhJc+ddB>(cRC`%L|5JzlO!vC4AI^bDOqG?_Cvqql#j?{5c!~1TDqKAorkplRgY% zi0~Q93yZIkd4<8BxA+q13}va;3T3VoB4y+g1q zK70$O93$)aaH2aWa`dq0iOfWLzL)V;WMRSZ1J>cx;6)9=o%Uc__Dy)w;Ap^K0E+nTiNmhSCJ><<3&-@ z<~dK#|4P}msGOjBGNvA?OzCdearVQ|bbf=2DRQbCR_dB7cLu(xnePG9w|I)8aud>) z;p}Il_uoqm1Z|OAIDGcSknE!3>sbR{RD5PZmPJ>dhYQC24urafpgMfl67E-IY?Qlj z_{QvV(ec&poQ`3?2+<3G&(kLu;sW5CSP)%>djasZ>mza%9WH+B(fbh_J7d%#7<`xN z%zGOvU&XAH>#mCozM2&i61$i4hH3R%$5$J)S^Qp(i#Zu&jNG)}SgwXIA<>#e$MT*n zI@w+GDGKZO2u)U#IzN0-^@@Y;%L`R2*+fFiGdRf2&COKerwv`RDDhTATiUL;i;Y5D zM~+SL&6O`Mg_%k_<@B}1rX+5^qs|LomUoS5>;>*NzKp3*WJkl{i}M=@@TD;OgfHRV znp6DJuab);$mc~eNsVa+ri3?l@N5CdMjCNkp9?_&3l%;Iclq7}XXtakZRFstn0(C& zWtuVyYEB^UbDx%i@EuVsltpc`DMNXfDzyjQyOkK- zdxOEaL0UH93*-h|i;o|5A-Y;>bnID7{(fwiNOA#DS1D6c0*@Apg`yd1U36-~7fNbx zDSjdm=Y+5IVpm*7CGNi1-p;8cL#>Bo#vvXRKOpIXs2N>5tl^^uv1zI`nK~G;hBG;h z?jWZ9yTsR9zGh2Ub(clPAzpw_&$pU*9{qmYq*2V~_DA@Rjs0@RH>oRg8)*)F8t+q} zs;UkAvh66i|0Be8{2~$buc9F;VwnDcZiD+*wtn&a%cQK-ZREhmgcCo9Z1jr7$7w!X z;2UhBhbZQl{>x!}hxt$>u3wwfmANH8OpF*>-{^kt6nwlF7GpB@YjHSjZYk_GCQZH- zyS{Sv13sQR4NM8|9><5r5NM#fYQH!q*)BakvAcOue5K^c3|6Ct7g&6`(LW8J8UVC1 z=~SOxZm`_`DEoO3#FtH*dAsSLI=tMgN_OPjMOl zn}+A(hx&zE*pKnC(YoTMw4*cxR!=RnGP^1IYz|w%byJbW^AF%7G`Xj&fV4guN9Ka( z={LpIK}G*{Ghmqc0oku-5{q#}R)p_Ca06ej*OhXv?a4CcBWxSk{lbSia8Wb?%Q3ks zsDh7zOwPB_d+p^nDkbt{%EYOvnWXhEiWeFn1-^@d%i-`p!yyZE{Ib$X-9I0b03sgp zD3FnJk!YL2TwHv{R_^}6#j~HmSDa@v6TfKgrUP_A@tIZ#khufOepZX!#|TgPsQjb~ zf(CG+gk5qPMd&^SlCs>UaA!R;SEZDqpO<3yHk6db;Y~~%DQ9T7T)4lKREu}DiQfIi zD*rx)6O=7!W>3DWP1N+UWY&3H471{SorDB4YH&(q24Ca;_X+}K2*}WD6GVW|w6?H< zujuDi{GNLS08fdosm+dX^?c9KOcwZeXpHMB^xOj9BUVaX1em}l#6wiaiZ-<-dYEFU zb_vi4h3+T)JQe;3A5&Z)t~*ZFxVC znKFT|g^OZ?kM87mP^~;p+fQ>mdH=9c$qyCyG7;160vi&m+$qK2^LHtH{|I~2w8XE7 zU*!5tarxeZ^$b30e+hPYzpupjo)-8(0oq^6HQTT^838DB(Q7<|Hw&p4lm4&Aru6YTp<(%iSCTa&3de+1@P zgYeb;#zy5!hYtu%T{h5F92L_C$GGRdDoZSO(##6pg~FG+`F)A60D9j7sw_Ffgyq7K z;xUDwj@`JXs~Y;^0E~a6vrvn)ssN%W(}q z%|7ReZ(4b?c&b>RQkTf;(N)I01(ea_IllEao+le;tS-I?KDre+b%0qFzA5*j7Qsih zo7$gNg%9JyI4y#Y@3+Zu4Txt`c+0S+cE0%)@oh^rMLwItTZVN;e4Kq6mT5ePZ%UhT zNfZ8w_*#2^6%qnrS7rrbw z8X@-y4XpK7MZ%N-bWa|@Pe&)_si?s#Hn^K!VYp!C0`Rxqgj0?}CRB{-y{ahXDkTvC zzAZ`I3hn4hJ3*!Bb21`-j`;ke5 z+ut}W!t(`C6*`;1NA}G4v}_+ACt&bbb9p#7HOp@Imw|wfLD5J$pl2++@5*)`d5rbT z>zn?KX*Go`Gl{;~oVf+Ig;a!E$#}mO`*=bjsYzzz;oLlmVtg@{H<)eMbRWq>!naB7 zWt(P|;Xb0?zlPJKX9{8)Z;UKPc%Uw);Tr(oFF;ko3c11aw)bqm3cemtK6*%HR`H>J z4{6nN`#>n+Ux9rC1Zd-*h4G=WD;!;&0-=HLSHMiVl*08Cll^!sF@*$_!XHxOIPZ$i z^?QTfdt!Xi0dfZECh*ZA;*FF(Wm~#>BjkO&P*U zX5${UCm~0gdO{2F5r%TGtML6|FuC!%H)bF+FZrU0Bb&hIOWO2Y&9&t_Puq*|s&xn{))TeSM$B) z@DUskBPj4~3I*N-KD2#44KU5- zVmid!=%Y9sZ;$%az*9(Hgn$gEigA4OZ90Pw;E7m(9X1{F*nWi1e2g=}Yao_FN%$zr z_?`|C@^;md__WB!@%hg?d_6j$+AsF-c;i0RhPK8j8C=C7u4N996K$XlL{8Am_tum~ z^;=Oe=Oq4ipc=;)fMM*%rI@$0cs!*2{^ld9X)`qPMqy${kx>^V;5(YE-!=~0j(@Ch zi(RrGRo!wFASYi8EtI_>yf07oj|d}{T1d}%31fT#p*m~S1iGxoxnB{3&yFHB5ULit zUlG&k&J!Q^`lS!g^s@8BH%<5aa1A~?3fHo!T5S2q8SzOf`8@GW)4jma{wIOYoJ#9Q zrRve8V`sDn|tI{qD2LpMRKm zKfH7?$;QVMb`tpZ=*8XVbzx2?r($(LJh`I)51C#WB$zS;A|7vvj?|$~<|6?@z z$)BR4jz>HH=8I2#`vZFrZoHK0bY680tQN znNlQS<2xziX=Q_`cw@%_>iHDFcd9_<(pvKFQXrsZhG zs>&W#BQwJPXp-Lp3$FkiVu+>0Uc9jczDc#jarpS~?YEx6zDjBMgeaUtZuvRl+d{&< ztKiW6)R1CK$AFc3|ND!$xk;BHt(b2O+QhSY4qrlQLNozfvV;DZoKQ(PFOqeH0@9-$ zO(#hNMW|^%_m?rJ$^iD(4(-u&376#?bR!-3&f1%WA$(F+nNXg?5Bjix&;ao)bLoT~ z#g`}rzwpaSi3UUE=OdSQzY80xTm%8`38wrCO29Yz`|X(XpV{dO^bb@HCL$V6dmH#X z1&cKKhB)DC#aEC*cP!fdT?zA2I$z0L+x?n&Q~{reWK1{O&_>!+1-QM>%>|(|Q4e+~Sfls5pH~4vsP)Ln%z2M0oBA6l+;mHGqfDaGT zG}6yZ4Nu}5H{xATyB7X~t8e5vwp#qKl5-xx$8D9vO=spyZ0P-G#kM0zvILrFP6&lcEpQdlQ z#mDAH{7mHeXxWPKg-4oH0iXHmLrws~CG`#>v4uXmJ2_ztCL~r631yq9{27&<372v=F0frPGf-#ZBAK`X& z%=h(2ity2Q)mA|t!9XI-C{o7lp(Ao&!VfZamI=KAddO7I|x20pTCj$bpl0e1_a-+#CR*v3jb8cen^`R7HiL$R}8hH$)zGdvX* zblHBy6Cv)$iaqoS+$LT&M( zhmh4W{O%*s@{OW?2?vdImUw}ai=68BPnB3kARq(DC7zaLZCK5{L2D+uxD?3TjU z(Y4~sF{Z{odnBpX?=*$xsq|Qi8Dz$o=Mz26el+qq%3XlFGL4YuPx6!^=&WjKtX9J# z436J(iRb0Zs^W4eByPDh*2wJSLi~a>VYrMB^RDwH$?Cn7JbtSGr_3OyijT~wiC3v^ zMDG=uI~(CoP##XQK&s);MXw`Q&G)9!xl#+iyz_!9AkbJ-!;;cMbR8J8z{XhoqD3z{ zzKdqBHJ-Hv))rV>U~Pf51=bc=TVQR0wFTA|SX*FifwcwJ7Fb(gZGp7~))rV>U~Pf5 z1=bc=TVQR0|AZ|NUU2NZ9O?pN+`jkNuy~CqVRy{I!oWJ^_2|8b*(Sv+5^Q{(rpJSauVf(SH zr$%#<$dp|KlTgf(fFU8-~e_}Yg3k($5L*YNqIg1)oElpBv-iQ>OS zA>fPS5Z_#4HXOz4j+@Bi)1oX|2O18Grg4XlgbLZ@X6x^2;s5aP4bnc&HPkhA*O@bWTADB#=cg8_VL9AWbnaF}u-zH9JtGc>kOkVJLp zzv@ePXc_(}cnHCVKi3k$hhN^uqPg&Ne9E*PXrN_)xp=F@hj9+61tIMFn^=B~14z2j z!xFujTLW@=uT!1dmodz-^GOMTT%1h2Gn6@A2rB#z zQ?>z>5$dfG4%<@lH(2rHe{Zm{3w)v*;fqU|2sOgM7ovF)KJ0&JdKfp2@Uw`u3EzNh z*nRRdv|9dgfd%m+^OS8$wmuUxpqqOe4Y+C$#>miti@6X50Jr;iKRG3evk# zO4erkwG+_>KHC1SLwSJ#lp{tHhe*M8gOFI*N~lY16i(+^q|bvdA$)Kwc{;_8Oo@mG zG=yzchN-O)%JRPcrr4q7hYr@==Bq7n=~xNj1lEDL;GXFL4vTAUg_Cr)!{b3!-PaXR6PI>+K6-KHTy zf$1GGJ_^VF3vo9lomm5|FGqmL93!unrFzWp>-Iuv;L zU&0aU5Xn6RgqM(9<|7zNvaLRCNnx8ZQ2o+tZA76=Hv?}EwHeCX;tN}zLK1#`U~O(< zyrl{k)9_J(LQ)jM>1f1+!YD(18@X~SP6i125(fZb9NJ0b@FfL44SfEt+)|#y7vPiJ zDwd4Ti$u8f1tH!6r3v9<{nmbpN`k{agW#b04TmqtA@6a0c?!qumxoAMr%(rDxFq}W zW@Yd<(zG97P5zd|B*qlg^q%+B6N<{}L&874gMk5ol<-|efY@Dlio$Tz4fv+v=fr`T z;+PsyJ3%J;x|$HrXh=efLihv%z70kAHa#PCsSkXiP+K@OWwQ6Y=RCDT`dG6_LMc8D z=~QTRS_EqNq!4$G!Q%!;M}T~Uj}D}lfDwpCQPV%x6r?u;Po$2(c_602VOQdieR;J% z7z6>?Z=?ZIBX{iG^3|xs2bMP)Hh@pTnusC9_LJ1dq!7nsJ2H~6_!RJsV1VremD&^= zTKNBr@O6%0+7szP8C@4K+W!;#60cQm=*=5B@cC$eBlXk~>yQ1t7j}e19Hu_uL(BC$TIg0dJPltYqt^)Eun&Bnmc7*A z!+ZYnZ^h1#@ueZ&@C(s4Cy(T1|8CiW)^&4`_sC(!htBl0AW!RM>EI4#QA1lE|UFeY9a} zYNHp9aHycv-#Rdjhx5;NqHgpJ!q+Bzq_gJ(Uu7XVvc`v$e+%g~+T#6pnWYMRLPH6t zk2)oM)E=J-J?bs!A0NR;-AA___^KgviMFhZv|OGfs4(2>ALj?f9x#t2x!y@=(cB zsH3+n7jZT|9i4(hr2fJw(2w99%5p5gPBV7OL04US6P_ zoC`)HT*UNte4hIy7Yv($<71~M{{;$P!1@KM5ci19w|)`=dEtmJD{m02i`Rb%RdLyS zLGhK-mWydWoZ~EAOnk9}cR}m7#8-w2$QLTmzffo<*6CeXqL)XO90Ko2vn6axE2t@&jeLH5k#|@?dg6`2u!u|#RNnuXE^sP$ zL3|r~CBDlCx-{nWf_lsLy+U1=LU|EAEpUamQ!!GPcL`q;-`1T;@usgtGBbIOgp_3R zIRuT!Tlx`-i}H zN#J|1v*?*yL2lnWCy^!Akk5w?+iw`Ua_2iXgaw;#e{;y&9gJPU__`Rke{d@rxakpk z7AkvD%I31)){)h_wZB)CFxa8+&58L>RJ`Wx{UGQK+$;WggU~PX&K*!qoPqPx#7hBH zmNB?W*`A)j7Y{b9zQ!{_FL!T#;M0_$8-)VE?iDO}F1At-@sjKPJQ56!NjG-(q;!^_D zHL`-A<8W#-9@N=5zSliv<#S4M2h*+eWSf4f=kYcL$(UTZXcXH27KvFQ@YIJS!T{x{ zg3rQwsKlrH5c8#xjh9$r=VKcHF>XI>ct9Gl*${}KWC&zbmN*!Z+d(EvNXHz=|Nar} zy}-OqB$Q25T?8y_yl<;5dw$OsIf_c^8L-g@F;Yb?S6+qyZQtgNXzLq5$Fg+^Kl&2k zM-%i%$3;ItH&93;QWaN3OALS5(`XW3!@OFYvv#&xMpk&;)4UlS%DfVqy_v89lEEkN z2}Qs(#Q50488bBYnt*Maq2%Zy4!#mT6Q5F~38ye_fByb0>_uV6>Fc3PZh()?w=6zH zP|Ya`!{iF>!k3yNpqyT5S0X6ak~4cA2j8;CVM9Tcd~-^YikO<54CU?b@q2a@6$cNh z>=K76_@Ian2D?xxYNGqp^NE0Z1NP(B2n}a$H}I%h^13`Wask7mQfw1K$UE383)qWQ z2E!4-{LnxI`whDAgCRAvOTKm!FVY68Ol=Kg4i}$Yht>1Cq|e9fI z0T>ZHI{-JaRa*>op`?!dzCb_40>%9k{`RtE&FcmHVfwr-?lUMe88P|^VIg%pf%iAkObND+A{cX z^m%szpJcVBSWV%a@b&FC#jSyeZ)n$ez?XCf4qw#KpRnl$ANE1`hGop}0beG@+l94< zF=Kxd+H%4t8bek*j?cR-nGbwvH|^S95ZSXhk__h)Dnuh(kQkq}f05PUlf>aIG|=X4 zrGv9g>9Y? zRY+pKoDen)WD%ied-DX%aN$nVUnHIqkVwy`$e>Ot2kZu85-c0yShfz$L8W01s%f=I zHDQjhgp8UZ*RA23A~4CS4g+~L`7HP{9yzMoOgOTRm`=?DsS#^;)eIJ9O_K?YE7dCcC46Fqv!|yX+m-u zbDTG`C~8)A98_wC7}S zFU9V4>o_a--+Wl!bV_~ixe7k<4;f!ayJYM4{_Kvl!DeUo^JkiCjj5gzebJM}&=z>l zyL%Zl=`#3gy@V9>(pR-r6g~1vIQ?W`1hINGRa{8dxGd4)y6p7`y=vRd(9 zm)A^|w_-0A>Q9`?mN+cW40sMO9bYV7O>K@i{%?GDFUu)eu^)@LEKDx+|t@hzMw zK{>l{A_G1auP2t3ZvKfsc`fGT&*V33=LEjDouVzxAq>kI0@#F^qsB!LxAuu*|5eQa z-1L6~ccjO!Wo_CSJ$vT>S9$Z^;o2fjZRSOc zm5{qs0zMjFa0B=OtJnWL@MZQ|3TKhrmFMuW<#By#&jW;ZRpcwD$sILsaF3~ruj#Wf zL;+2JGzVM4pTx&0qQBwBP2Vt9;x=5ft30%mV zi%=PNLGXd^naAyeAa!Azi)L9Iz0+ zt&`dV@|5AM!0jevE$)AC{QNU!TY2yZAM+6gzUSL~5MQAkd&%UfW_;d$%bjj4X$RK~dr4T0yqL|Yt+z{Sp+Q5THz=sas;14OEzaO=%l}mg=QKr?9qG68= zLW5T`e=g1`3<_GU0$ z`zcaq@U;gNh6Msog+mJCggg-5?m=iGsB>zmKBi&Ff=~X0niBftSn{O{o!RH}mFXXh z@ApDYI#Ggcdlc(Y;coLN*pKn`EItwdrN(2|9!Z6>bZ`t`X3c;SD)`I@Y%3f0>Zrrw zIU?In+M=uY>?pl7s7gkM554DdSQg(beXHiv`TSmxx4m2`gikJ) zb)j6vQuBp!nXy88GFvFy62kas=MwEapfTTjcE-b)C1A|Vas&H$OPkuPj_WgXP=e3+ zZeh4RQEUZ?Lthq?m0)gsLZZuiz<1t+uS8N&hUUhH3t61Fz2{uU^YigdJXxH>(5B|0 zjD&DnstuI$WL!YTS56oUja+a}`{gMzoHM@A;7e$JI5-s_O*~4pJ> zusrk5eE4W8-c>*2gAJD$m&$`YC4}lBf@fB@r&Ly&K43y1}?8P>-bOXc*2U0pANk1%wZvm!mO!sG!U# z;spj$Pzk~lpBlXv2~oNYYu4~V!VnDo(p%J%Ts3!7@6V+o2KE2tXbfLc!55+rP;w49 zFd;wKqV2p@9iK6cuVG{QpffehuEEkuJv}t|rZiV0bDBGbudrVqEeSn?l2cd!zNev! z@MQu9brjfTq4+8qCSXV*OIdt)2U6f@7NmNHNqjl$yMdYIS+Q5R8ab`9dTe#uq9iNK_rDK}Y#Cg$$KY zqXy$TAil+CW#;top=FY6(=b*Nk8Y+#7x+-9w~JVUCzp^6B^-(Q0nQ_Q$L)^E4hxIi z1mWU=81-Go9!;#JF2p7Swq8YeM^j={%z~j1UniGB{HEyMK=?Ma#sLDr=Zn`EAIY%c zeRRtef1~rUrNT7b-1<{;>JRWjj zmg7myNp}9*ca4Ma#UZ`~zAMF(_=%^z0|6`Kjqj5DW`VD#5S39XLI6So!F!lO{0`1_ zXuD!NZ~ft5rcQv_l~n1eGM^+iqq67t=92%-`ADhhm=y&}?&!G_{#|F(>pc(D{! zi<&R+@oFN8fw?U-5`xalLOk}YFPlC$N)iSoG2t_xGjC!(6h(*R0DwVy)!5We{jMJRtygeV5b$>axKFCcv17U>ajuKI0FmE`+~XEuoHyyMP1#3`i16ijmlYb&=I9*++ztlKh40ESx}>~C^RV101im)# z?aEih;E*)+yyp)|JHJFTEb(!>P%swZ!`InK!N-FE@S&6Jb5?M&gz&{ag1|@bWd>|Z zc8EEX4q{%S;_vZ0h1s?h^a3vgzJ1s)*M^5rl{3LEZ*8G|BdT9t_P~_D+a-MFf^NI1 zlBR%x?vOQ!Bz`b2-z(swq$MDr)A9Y55%-^KQ^%^}^YJzBAMCysYEo1oRMiU@>wpjD zz?ZBP>erVL$g!e?;SG`~8jSZ@;PZvNdH1kCJu4vqKFRi@dh%2wI?6~`p)Uiy427pD4nb+~ zZTxzHPlMkH!U&z}CW5o*;})MppTZk;M^5f}AEUuv(x^3qFfsL77*#Hjd8i)IN1{VA z4t0_&YIevjigTCvpx>>0P`UlRvvkC3b z`;1BUB`HCP&4FQH8XYycLQLG?`_HuKXfzDw`3m^FTX-w{viD{Slkpj}9ih7)iFdp} z>HY}8geBkdK8x;o3cYF4%>v1=+8tHo>oPMM0_qnasGa5%Vav9>*Lp%;_GIgahBw6p zKJn?Hc*kcc&DVWb!P{bciu4%EiZnzY38>@ph?HqIRe5V$kufud*YaM$`~&zN+^-7O z!h{d>4t9M}Ob|GJno}GC$`0L;$r-s!yK_yFS9$vweX}R1BhAVrXnhq3mBU1an4h{% zR71m|iEv#ye${uXB{O;1O1Ou!&gETj43ksp4nMms@x^Grw$<0=PK9c0uwbx<{xu*JQ`2D>L=)A41&Eyp9NUJ$)>e*X@T!vIIUly2w86EZXE)LG`Gw zOgz+{4b{_&*vjxV#fX)Xa`kJJ?y#4e$jV&P{v1Bk&Jy)o z1tY7Gm4zKXC_EcJ*F9H;%qW_LFIlvlnZxsTI@bW3VaCw z(66MdIz=hj_cl}vO+a%I@fFsXitn7-e^KZHfk}KhE-vZ{R6Tl6V;M?IY9;0q_-e`b zCQ?`^nmQ4OEMbP)Is#V>vj>Ls0j z;bg6%&$$Ej$CEuny~Pfx0_QU&;8gD;K4pPH+oIojjKh(t&GKS5x0ED?V6M{t%VhtDT` z`@lDBQo|#BvMU;Rv?0=sqbT_GJ)itOF_V z{Z1&FVtYev5nj|guQ5b0lyIh!9mYBB&qhBQ9fnxVxGbSmhYx;Nd`E^mG7z7ZtPu8l z`Vwv{4!O(?5xxw3xR(zqUXx?Ns#C?M6HZwkA12QYVU#dFtPi3m-&>|Y;QQ;VqS?_L z1+Yhf@2WJ3v)m~+JeJ3YQw8IbB5Q~=6%T7X0VvKNG7ev(Em;i|;A`NoKMR=Un;VQZ zq2=-6VDS)8V35lhAFC~{NK|KZ`}?Wq#xYeZbXH`g_`0~s4Sb#u8u$jL%o1Pt6@I=u z3(8df6nw=c&eRMiF%!Zk6!0nF(?+zYU$xBnch&eJkx49jQ|Ot%Lsa0)I6B>t)7h2W zr9e?3C2P)5CUH`G68J(z4~I;yDHfPeH+y`Z0%i(pLg91<&aMU@%{kqe_G{B+Yg{^> z=`;n*6xQ^-6I@C7o)Vr}DqxeVBkV*D%QzihR%R_4Ov#!rMBCeT#fOCWrmAE(9bdO> zqm_In=!}(>Df2X#Qo0iIni=r@+o3yQRFaksI(!ucOXF*_2;V?fbe%b9pLyfbaCtWD(sZzB>u!i{tzZ_}uCM(lig9-jGUsqeIdd4=^b@g9#S9mvXvv ziSNJS1CCXCCVcZ)t(38bu=B){Uxs)qdyf7wyAR2P*Ep6E=NW=6h}7)ai^G=+#iH** z3omXyFy}m-oRwppkeXGB!#BXJgXn$t6ko<=Hu?{0Ow6W|!>5J0DBmP}_`f%#xR}P~ zBUo8Cy+nskS$us0mrs{HGq*?mwNa{}_udfmzki7~7nn+fuaCPA61O5qU{&~R%eQ5+ zYK*HNkQ!IyM0{4j+f7JGyxZ9FMG<$B2;Y{(QnTPmMXBkE>{lB?*-B8}e_~%_ZcW51 z5zSkniST7hWXzs$X#Bf!?BBxLIAs!(mDKN4eB1Hemo2_Ws5D=MlHQK>ut2PCa3mVy z@p)(TyuhtG!^zKx&(xp8$CnC*CB#R%&wQS%REX{nr8Qv2ZLHYF3a?rC_ywEn{htra z%K^xAR($51>dvfu4d?L1-OHa9LZT3n(m)Z22j%lvjqS_+%yTNP^8qOi-tqq^%E$N= z2bOfqTbdE_OP??g}%ymY)gz7&m12}Sk-K3ZFz$f7I4g$6H zVFi5V!OqhCgC2dL9NwlgAru+yDoXv2A|?^$ta^mi0vn|z%=KvAISVeBD#DAd>I+$-K0E)>4r7?QRRRzK!O;bP#k8* zFv_?Kg;c-vjXfB9N95m>(KV@D;)1>}7~fNr4fRW&FTO$N4^Ni;gV+`y2aPiepXseQ zaRA>Xk^ewNcbCS84^L9TyHuhv7C>5j2U2N9VmiVE9B#BMP~~7lQJkYVDr^ zp8`IQo4v(H?;X>86?OANMJ1SWI8<|{C(U}O)(NYmPp+zBTJpNr1IXU_bE zlnHEq*5X4A1jO1`*~S_0p=QZEm{$pfpChgs7vXYTr1XpSP_pns@)s;V(`bQDW|-cq zs>}l6Cc3QCRMp|jijo=l&@3;cY#ag6~=+keLLZU3`lK~$=v_wKd5ZndWd#zl^hGQ6fH#*ue*bf!qGhgQnk0^}>oCvp<^fm$oalPmwxd43XGE(jHxE;P zNciFjC~AUp1_r73UcBzrl{V~bniMxZjXJ}GEHF^Ec4FK%{M3u)D?aH2J`!IYLA{!W zuPo%)M^jVzpuw9aVLyeP_`g)*$I%Xhn8dgIhEmgxsvmmV`^?*W$|WXr3dFS7#r@9) zu$|J|4WXF#qhs_F?|*1t=jbFpbea{???(Hv_rgA|l`IXKm`3zM7Zt%TVSA9qzAi?{ zYsaz5yb z(>LnTv&H;Y_q{cIVcvbxZ1!Rmhx_>8hWBjidQp(Ym+%lYIk7$}1XmDfw9@z1#^!dO zUh`!|bBNmr0k#TwvS98ElRv@B(PsT6F0MrDe;(}|qY;3b;=>peS4geoeKmZoJh@hO zUMh%gb9m21Pbyn#IMN?{TRa?YXkrA-9bS}eoR{EL+J?<>7B5bIvxZM(`D5t774js` z*3U&sSzh>K-u2>pG-m+5owDo8E!fdYt;&m&kJc}Vvh1;1{bGuYHuhYUDOV)-3)-ND zC@?V-LDU6Sv}EMKgRtw+;iKIH8B_I)!CurugdRj`MRbnuf@=P zX|DjBfXCP_xys=e zbPs)Rq_FSc#%Y5_6;WP|oOc*w{Y}w!)i|}Z9&Qv=DX&J(JB-3YZgaB>+9)dD$RNwT zqeGl(8<-kTP(HzNjM*tpVs*avd7-9j%j@i%ZV5I7ad8)hw$vKb1P$#k7KYl`-`ds z8&qCV2grEt)bQzfA)O(59q&a~+)ktjUx2=2S^oA@z}NF$MqFLjVVdUq%BG#Ghv%X> z0PBQ@a1r58)6l`JYEreJl;q!&RpE zL@OtJolrg|P4V9E{C(WddeW_Sg42kQwLX`zZ7||Uwh7%Hj5X2E?3vn0JmXs%fdsKEK0C|2lxg( zk#-+F6`w!MokFW*Iq%bi&wu{ftHor+lU=Po76S`JY?*QfvG>zi#ay8HDCz9$rVLD27SXe%3fyXwKdrip|GzJBKr+iadp!4v!H zWQqAwpZVhJn~{i~yj9{8sZ<|_{nFw#d>gAz+8dhA)VWc+H9SRq@WgF(ipX5a1O0lx zh0mPsmF*8FSM<`rd^eGm^Z-5xHH8P{Od|qcq2P(y8>p3(#e&=VReTUQy1w^<%jXG= zM`~EJtsMuir$`r`IqqG;YO@OYhc{Fux^(a(KTs$#dcXTvBR0qO6yqyZ`a^!1p=3-8 zb;V(g9Sc>9FB#eXONpG(Mw$IRRMY*codEcBO7`EX39Sg<-!1CZY46cU9lO}v{*!k< zUz1%CzEIY*E+6^u<@%i$_rBTk8dsb1SJSs;RpUj&C*pcDy?FTQ9X2lp{Hj&&W0>}z zFR7tc*0M{b3xp~IlFe1(Q{aSh?81Hl-K!A2QeIFQbssnq+Jv|r2DE+ueWdGq)e#&( zc7}hX3?6#pK+u z#f0IIt_kk}c_);y`z4p?DODSq!{+wHBOfQbTHimRn#wC+e^=XeF{X4sio3sbw(xT;abj8=nWdx#^^^;dQUp9&mW&~Fsz>&->mB7aHo+5)yuh{73G1IK3DGw ze{Q5GLUYKtqO!o_YBP?ic!E}NZ}2@;8)MD+-t~mGFBvYJzs4<`&_&<}(K+LDz2YCs zYBQo~H7?aN_JZvKk@s3FqGhNB1(9zzJug_R4dhN8y~0(H!5SoB_&*7CalgxNwt`l5 zBnkpQueQfR!)gLpsOA*O*oFuvhvObTO`<|f9WY0J~9_BHBO6w`;4tR%dq?=SSor_4E5D7^b+Cnu#1_2K9EwMRM%_w`22 zJgvClzhMQ*a~t`e(>=m4bsGvjP!vk|6jn&Yw^g*Umu?*vDG0RCdq))p@1{y|vidnt zpSq^R@12G6{)X6)BGlcEh<5gpojShS=vSHeReOJ->g<6&1`D(&UlmPyfs^HybyO|$$*cmxuM zLtnSChI}{+fvMZ>tmL!uJ%uq&Zj${5{4qkSFqPNd7I*=?qeB(NZ|~|^1)&$=Qi<0G z%shr!c~9iy41uF2eEgL|PY&smjE*kLXYi;=wKjB!*8>msluH=*w={CC9AARE;}_z5 zm7_HgQ1NE7(yktpSMaEA80}z-gWi?fZ^&_6F1~~Bu&$mIe**0W7XB;#T#`5R#Ou{L z`(ttoZy~?c`OYpU7ycN!hh8>eWeE2c{{7;g*t*BHuFpWdzRXit2+TFN!KgRN?A zzjSL$;uD&FZFqKa^p!8*tDZ?*(%Jk^(zDh0;oSplx4YkaNRu|NeBFnlPu~6EZ4ri} zmtZ+8S5w5R6ULp<7cr*0y>aWQXNr9X&-n+vc>h3&2VUt7G%4dwTx#7Oz5N0{fHWFS zv)qF}e26=&qHN`T_A>X`Lf#$V({XoyR|)Txc0M3=)%hl(gRR|ToX3VAD+i52g6h=n zn?0WGY`|=8@3zD`i8$T&R4imWONn2UZiMmL$R~!iW5_%4w}sNavFHW*Midj7_whMIer$ef6a9d^h#DexJqDzi9Q@EB(G9GWx;O;Hdl@r-UMe{E1VMOWXz_rUXc2`In^iprP`;iD|)M})5&M@%_a{5Tf->7!D#vatKLip7Ah ze{NVR<&>ak@EXVWC&6|s_Tuea#D5i}U+Y#7;d4Zl*h+(8W&A@SZIP3D!q*$Sg8NYT z;(PH5@L?*tUu`D9dM{|}SQf>|Twu~Wpg7~BNpOYki0Ih6)%jd3F8?sf?-9O=^?dad zT^+^=FwqV8sG+L0=KZ&_^Sbw3Cym7AgDA5f1+U;g@1U>tg!pCA`*p(CxPiMYy4sDs zm*q~&d;SveJ$}&2?vec}2OVnQYl`-7D8l#K7&7u(m1J+Yi@Q^=-bmZx`d%wPJii`W zDYP04@)vMxsuf(**xj@78t@GOxFq=o&KtK6316eP^-W!-+?!COe=NJLZjcRdo5Oz= zpXTDvs+WZi@tXea;l{D}ognV`CI23UHnft182D1`l^yOeK2<3@RG3b6=p*gfs^)h8 zUwiKtBS~`JiA7WtE1PC*SM9AK=4zW$Ns*THAV4`*?(tf%J!ye;+I~tbF7!EPZhsEv!e()M5$Xu-; z%CL@Gdz6pGV{^*CFCsECGApwxtGcSE@6g{&XGDDQ#TUQ&;%`PqMta(pdwVe+DGxa|&*!5x-)IHlYJhj7zi}9gx z9D3p#@y4DOZ$XVNti?pE;v+`q{1nBt{hL-aPzQJ zWbn;d)r=XBVWpRB9!#C=h8*+FbEtg-+H*X1Q)%DNgE9}X*5O&%MF$TkO8tQyC?m(+ zkkhdzR->-P-qe!LhQ(89e_B6A=Y3rOU;Zl`gk2K8uHInZbByykuuEo|4mUL$_@s}| zRI-@$k}NN*pUS6aJKB?SaddmYZl1ivU(STj=K;7OR%;D)aBD$e+bp5_?Z|H1jM#7t z2CY)#bK?W{rKcbEv}rj`Oeh)=&EsHx(#p>%aM5czI)+ZVStIH&dNm(?3HNhu2eX6$ ziG(ONz+y}d?*67a>eGA6h)4;00^v1J3;AgatGyc`gYQqZ)z!wz1v~W!toDcR$DXqG)dlpM?FUxDa*OQ|tvi#XQ8SyY}!=oMt27 z!y^9~7JcI<6<}f#q3CKUG*7@rRR4H~cfILPDzT2MC1YPE%TQKb_B6XMUPI|t;iD>v zhvwfxg_SW{D2ObUQs2JmX7IIn;Z1>5WDQqq#-3NeN39c!qQHj}N)rfqyq!bk~ zD&NB~3@#(}fTBw8md7y-W7Lu}c^2?r&v=*9*O1OdLrM*+O&QMLg#9MR^!Y6z*c+yK2!rq5ZaB91 zs5vV9SrGa;i*MNNhEPO{g*YCKNq9qa;rwNB?)qoDk9U89OzE3*JV7U2#J4jM_i=iJ z#YX@jivESZiJ+gu4*|t^0WSn7s;1&pNhZ!>>0JgeS0vlD(i{`Z zp|IZ_P0f+YH^ujnklzllJIz=M(|d#ObvhW4t6L@^+INWA1=kW<@cGMxzS#pW6H|e1 z{CuP-IkHh0Fi?Mb6MQ5p$Jb`zZkOK{DLz< zHi_&SFlDhW0TXhH8?(g6 zCurWV0oq4VY3MVU5$Ue57_XhF8s(-=#Hnau>!VwRYo zxrDj*96s7ok{~^y0zS!jg8q*_vwGjYrGOlhHv^Z_o6_OnwtqC7*4UYz!fnexRi$ahcJwr|i%noJmpO(P^*h|@i& zRWK!I1A{cp#oWM|Z*SS$HNHk9)5sJb%2J1T+P*b>48;dR3DZpnAx$Z!dAuc*AaGc} zy{7eV2>v0)Tk3f>PgIvYe3XHviy@g$nke_wVlLJ>Xw+&p3GMU3V$=pgC>>@$^pNE) zGqt(Tw24e26CjTS?%#lGTTLNq0|Ar{+a-{we2$1UN0fUVJ}X?nmv2)2#?RE8vWAQU zEveJProuvkLPlxKAv{8*A>U10AX8%Y^kSb>O4^rR#s7&}g3_V;i2_wNMEV_-5m|LL zg+Pi1DKO`1Vy;CP)-)29@UgdRlvU$XPTKUCT3{3rVB(F;9_9W*G-niV1{ZK$zyQ?a!b$B^4>r?9} z*@vDUSgN3Ge37aulXLJkyo7rWB-KePpBYq(J`!%t zMy8J48Izqwwz6;+u-< zXKELVk{0B2RhG0>LsdmwEKeglS(RnLI+p;SX&aUJ#GMZ9dVR!XCI_+-#I5cnz(-pL zSX7A*yGK-Y#07HA*cMf1xN`~cnYlqchYx$g6vH8Za}kRf8-E-|ySmKQu2R0(Cse|B zj9q<8so_jWEmf2W;H3jq@szT~OPykGirqs#RUU6yk574NS1A_BzFdV5@4ahJBW>#| zY3Wpg|jL&gjrAmL0jmj1IqVUt!t&ECk^5K=H0wux$P$;2XZAV)HZ2omV z8%F6CiiojaXCsO#<~83Dxa5U~T}+ej?0Llrdk$9#q;q_2X(KD}(KbGhx*5Jawe1Z& zq0HOQeDIX;Wo2LDQxX^t(RmK-h`4yJKX1R1_1o6K(79)m(6!cng@_W4?Di+ET)95_ zDFuAp$VTpXU&SyS?<*r#BFE<$wgAJ**=uARXT>^v#kOWrl=1Dj9Ck{F(J`KV!N6w7 z+=mKqZr5)mE~PL=?!tM@wG!gs z)shp9ouAeC=!Zs-vV>E=iZn=rn(B#1oC$<*H0Qzn4uADKEEXs&$p#}U&NS(k3E6XF2h z8NG5=Z9jn;p-IfpvFRZO^iH0ozH}a0u73_6|EdVtgx`n_K2BeCp6@1XTXL#GuCFwY5KYJ8p66OPLorO4}d5mM(%6#T&~dD^gaC^5ePE1@7y&VkQ#tfb}mRFRVr*Ys2Pj3qdWSEK56 z`ar;@dl>Q1x=P~*Q#Rps>(V==)DorP9;NukCg@*w(7Q0oC?(&|QmqvEH2SLoO>a=} zm>s|OjKzl#nn6csUV%@OFk>HA#=$$KhNQXnlqOd@xQ6F0reF8Rv;sbn&BYRK|^6u}I4WG((AXysLqhl_4VhTo_fUT5_F`asmZ>^NB{5 z^&@TE#`sXWrrn!VbSdELqDnQTej(*tDrq@xYw-d4BA>JgaO?OHMyX#d3%R7##7|M@ z4+|;hq$10ij*NRynm*Xb3VfztPi(Zg7IMi3H&39}TSz%46&X(Yy^5$(7#(4mOdqDp z+%$ZU{CetL?v`6bF@-Io6rbPa=5j*ie&-`rjbglid7vK7rKn}lPpzlOMDdC)q&^K| z$fT8Z0b{`wPc*h^01%j z>9V8VTGR*90e{p>1Qa#FSStv`Y)%X+SYKb|nyPYggn&;#iG7@c!SJRjI6Xb>p-EvF6q4+YfceEJ?hShSW z^A@T)vYM;YDR_1Cid=qMo4d}^v^muhk*BV5rb0zm57#hyQH38mRcsHntY)e-GNRf~ zu*|QAYgF2LrS}!iz?^0w;cGL1dK&lw1Rl7Ug^pMlyH2Er(U9)YoX?ei zmdmV^x7mHhK4J0kP802ogqkSIWVH27%nCU-dlrrp%zyV#84bSYusls>X_PfmZJ4yt z$L&)ndo&-N_N0eE)Fu0!5S-##+;wk2%ptvG;HW%HKOY);ya!|f0w-}&geN2%-hI* zb@wsnz-sXw8hqIN6FOA~W2S*`8esXAo&`3mdWXkR^{VA@eA~7e=v6}(m)6RaX zS@{Y)Dx0PX8@dt6rPXRajZ9hMj(VCMzaykMbMLX)odiXj(A3{P%Wu+txyE(?q*;Yb zm2H3zPsE;QH$q{nc<*5^!)MP2Z-UQEBk^#5VyCu^U^c}E-R~*PsfI=?pQQNAV{Jq< z!Z&~*`#=5}Am&F78h!Pb#`x@${m!9Pr3VSRm4w>0wP+)J>3z(fJf!V0jc5gYbSPYa z!Iwy5kAzSYnq*1CSYxfoq+51rj?XM=2QOQN8qa`u0(=;YEobxBBT{Mb*-BNFgUp#` zHxs@kO2o;2EE$u3M3+@bE>D0Ki8^(c1YM=7NF#F|_T-|vS$rs8vYi*3%Qf;XONo6< z{B``Ht(!+WbxJ)w24C7vHKT;kCnOEw)WFq z@eNh2SXQ&o!3`7+Hpl3*n9#S-9s$CqaW}?Ajkv7gug~r&Jl-GJuBl!N@@=#35%BQ@ zUp(M-k`uvUfA9fE|JC47#`8N%YGkXC z9_)4Y_C8pG??Au7-@S9j1{wz)4+A=GJSV+Xd{6Wq90ortRH!`b)HlFO*0VdWppl@P z9_*S=sHAcJ^8}qUGoNq2`a7#kyyQu)-+6E(9-pZazZ`s%-3X{A1+UVU4@u)(M)`fJ z&Um@U$Jfu<4Sh$~Re-Il82lF#3>?r3d^=!xP!JXH<(-o*DG9*v@tI_#hLkj-{a9mX zvrV!f0nPpdEr_&DcE^b?JIMk%^I6Xz$?%Pc6Vb&$Yq+>F+BwuszCBM{WCZ>krTC^4 z=Gt)?gHMH72vZ%I;WMHLf;9db;gd`<;9J}|qf9XKJ5{s`KP6Wk>;~#UrEDM#l6@D_ zZOl6)4cbKf%?Q^K{#LM`20m{izezlIfrzH>sj&Hj9A=!X;^y%10pBhbps(R;Aow0R z@aa*CPf%8Dgsy1E_}ni9ZvoNcsHLQFXHzS*hnQg&3w%R7+8AKd>JCqUu=sR@GB>+g^fGi*XLUYxs}rX;N9yc%>|S(9(*grmgm1jt5dq-~ zG~QTx3Gw1ok^Pd$sDnbCCaQM@r#@;45x!xKOjP2Njh-cZ68P{=0nX7t%C3I z8Suq>EkUp3k2}LX!Ee)h4qsqDLix(sl&VX!@?~cYwr|jvUh3+f|2xP}_Iq*~$DO?? z8p=-;J9rT8QvJj9vcsNJoIU>*-fWSy&ZH^9GP;)5taMPHPr%iWm-Nq6>nstz9UaH* z9<6B~C^mR;9L#Vxn$U`~)&f>UVE~_I5M55#oo#8L>V)~dJEVRA37tj)U!U+%n47Im zt%>*<|8oihpA@ti68KOc^ix(KyuDLL?~C_!U7XF-!Y3Md@FP=tULgm0~?K3}s*=?1CG(s{O6M{BZ9qE*shec0u( z4nD3|$!k4X@lBgVb7R~ERkz?B8AEO2FkD+^p%;89y(`I_~kMR6}IsLZ7$CUMAd|d5F2t68n39?@B zxIq9qrwy4bnOjK(=B<-iiKlbTYRInEhmqOw0j##GsS(}+8ygm|-9@lbjc$%N-(bIp zaoxrPE|zZ`t4XjH8;WbFb)aArA+Ts$Nqm6AcvRSDfyK9-MdQl#YXjQ!Y(vr8pFS_?cpI;ngdE_uuzN^_PydS@jqjc){zjU5W3IvHY166S;Nz_I zQ8g5|UA^*(SwarKtHW+8g<}cnSVO#~dOJh& zr}f7YgYWpvH!#I-fQHcFRja(HiFw2)B2a_bonxDmv<_X3SBk$noapgD18R#2+Dx=T zfRpZ)Xo)i*KWMQZbb+@bOnEFH7h$9MPZ_(8;12 z72pH`(;mpd&KuZ`JR!D394C0u+~U)0qmu+lZ3Fnw1mLk`Iy^c!*F1wniJ7;aXfrAZ zLF2s1f^Qv?Bpm~LB=IB=gs|EmKB!Ca1s*zu&;bSi=9oeJ7!nU8@}daORMF67kmB*4ZpR{yU7lh3O>lDV*S~r2|1t z2KbV_o}x_z!1t;mjv;HmZiijN4q6Xi8oxoeg?6jipRm~CyQiG)zHz(kT2CLN3&FeD z-aZA3?^-bYB{Yjrn>OpxZQ7xJZiKl<9Dht>-{|YgWsu?9P5uP7wB}4RxA>kAlcxhF zuO-{Whpo1XzCjen1KkPK>$-$*5d7&+(OFdD-r!;$fHsQ-z&0mIxm< z3AdjXv)8Ne0V4j-aE4%vB$fDzziC~BQ9BtpJFLWLw;L=pb5N%-t(^#tCsDcO%H zCQL8$vjj~WNh+ipW(pn06kjC7TO@vwDF74?4ktFHYOWjlmeh^rwV?$1U}54u(1z4%N)KoT0Np8X4*~_z8iR30I{nPFNxA$*{te>_GN#V({mUZ0kS7{|jf6{9jqk9F?UHV2ae~Vn+wwdq%|et?{>Z-FH$?m5VxqiJoLBjm#%=4w5ts z7jt3s*+Ln7FjEV;)66&}F`LjnQhy_J6}~Ui-na=1em;BncAAv`+1s^S=B*6j3ucK8 zj2P82(1E%7mytk7<8N%ZK0Yv-;2RHS4)y_%9^?PN_aDLc{#~Q6?gD%*s_=$niqC~T zXVgJ^(HSGme8xlj)R)GJ1&h26pRor=E0puXV)i!%-jXeNq|4l+TSg4D`z`ic>6czZy-5(`2 z_FGi!Z?_FTqq+rrGS8&o1HP$;&-OA-qNh7J&9QeYPhfs-9weWLkEb>Gih{+^JMI28 z*w0W4eWff$XCc|;?|23(;A0Hy3AX}oV5r15n5=QD^u2cPVUDlfesNd$1(;;OjYlx7 zM9Z94h3{@JsVMe5O||chcJNm@zI{KFLV~#4>joKzCz;oHger!I#UO=v{1{$1s-#8r z@4IcBu;|KHuouuDR#QLt^We=as*KO8nMTGb%;e$WcYAe55HG^_fR;)!e7{$VFXU72 z?Pae0tl=+(OVyKv`Q6>RslXz9_X%I06hOu4$vtg+^B1a7hZ%bgUy?-`k1Pf$#3!|H zzb?Xe?`7Z%ZU4u9YB%uDD=$t+k(nyVlqy_Oil!j&$qF`Di}2|)M2GJA( zy*YfPny<^r5gvEvtX?5iW{vs=Ur^?k!%Mo>V){xTSUOZ?t&PGhnjI`lS_H5}@0@u_ zejmMf)y#K^u7=So{q{=X19MY=`@gvf-=g~05Z-)?Sd_35-_w%`()^lc-Y{vEYy@Aj z2v8}G3UZF(nFjBZ5=;9fngd*lZxoz1lCnaT^8h;tYz^Q33iz&7$y$7EiIbm8w2AU% z#SXBPLn&D54Q;H$r`Zz)X|$G&ly5<4UBFc>8Vu*i;=}vXpU9$w!ccU9_@Z_qFh1U5(&RnK5O^MIzix1r;uEIBwrhu;-1fYCjGifh5_2tGQhX}K z7uct+qxlZIlyXDCsGpvKGOE((@a5GFH&rBeQTT$XjBSop=+gR!ZXmVaF8gJYl-1%J z=MK(vv=Y8+?C%nYXyZsK6^gUR)Xhb`WLCaucZ>yJY9W?isdJOep6=nXQ{~8JvmqSj z1i2L75sEgLq&F9v#8Rc}2-sf0y+SP!KB2tj=f43yd||t?Gq2UMZUmnE@3K!W!PgJ+ zRL9*Y+$v)JU~${Co*q_a zCB6Q|2+)Vg(e5t*A4+xn6-A%$PE5{~7uXKlw>%?*jWxvHJMiD$vZd z;~G^G_|oyWg=bEve|t1J!1$(XlB~oQuhfYH6`wq%f`lz-LS`N+oC+F$QMS7T4*y4v zy`Gb9qI+1E9H@9QQ0RRZbbkgPZpIA_&fr|b&jC0T@yK%5ywbXTA8Bjx?X#XpdJ3(0 ze?biQ9vpeT%l#m+?s>B2>VJkL!v(GnoeCS#TdT zDoQR6&EtE8&czJ*L;kH|N@;>Z?V6@tEZ$a8ba803IJy{XtAxj+{tx)r9{;+>g;$!O zPBX^4T0}8v4LmwDURw_F2*_ePjQS7y@jo6-%fv1QFv4gE)K;^r2;-a z0sEzVJnEk^!4ez(*z5Ps{1eGd1DnHVYwMt5|Ky6}ZEM!AXOt!5=+i|NRJj`fE%wHxnV^iA|YvDf|Tm1c`0v zc%q@a>Sta|s>O$&3WPJ%#o6o|RN%93u8Plg{bT@RG5k&W5bt&|5E@Y7OZX z4gUVIJ=K3j`)Ok}{v(Y&UzGpQfGF8-ERqg;_nxLW>|dlC^prYOBL)~z>giynOyt1r zJss7H&d1mV*WQVy6+}>IMT+(tif;lRWQdNZ17$qs^4O~yn<47jhY=Bpak9(5pZOYi zlmXPmPqb%38<6GtcjI&@TJJf01MQb)kBqX~R>@HVSg8nCrd5W>((adc-Ad7ZgZo4A z@OiFnDt8BJ14cgH+WacThZ?m2pAcvKp>X!2L%VY__#)sN<-8@n-(M2%N8`&z6vPWq zI>zg4u9GR1?})KCFy%XO&Ef{7NC`C$dlm6kZIW`9x@+LWv>@5vqgLo@dZB!gH4Ma0 zT>Crp5d@5#(L?e8LJjGQ4dqCTtB9O#2i@8kb-O7(O>9Srb!V>KjvU)KLi6tvzRq=@ zyU_png|Wp*^WG<>Ewj#e@Z+Zu2YVRO&ZQ0~asD7@gx#EKQDV<*^=gFNhqqnNB{S)AukIcmizSZ$z!rsN`dJ|cs+2~Xy zCJ-|9ms|{uV>W07s`nG%)1}zj;2+h-%txSnF~I^pJo;qM>kJ=<*OClalKM+-*9?cP zAQA84abcZQDG_78KF6tN5I#kFxM(%y4|P_)79aIJ+ROk78k7s6YT|#(%(j9bxZbBA zSs55sa;urZhZ=|fPduPc0F>~Jk!T)YI?hwoBz$H_49<>Jbry5n=J+tJP4O8mGRLQg zfiMR?f|=7n_703RFABSrqOm_~$fYZM_)QI|_lv2H1jGM~oEL>|iQ_>+5uaBz&2W>> zwt_T?OIhnQ$A|LK7&~K;tFFMOWldK40vbLG}<``SYhj$tEu+0v$ z(llK)p~!3G@uV={vk>id`}ofAC8-YkevXEQ5+c`3Y@qJCb$rNJhWIL|hX!L7k;k!& zsw?n0@v7L(@Z_Edf*{xB?vFf99+&x?krhvzcows9kHk8p_(86=2|jx#&zKf+mA*F5 zWCh>2!>9H`2{w_-&^6;qMZNT;UVMdVSShhVW=zu)FBj)sgl{%;KVsC~#}r|^G%U4* zLz~?KeEC~9a&M4q7aay*ukWM0++4u5fW^7ThgEkZi_@$cyT`SkgeNxC2;YGd_7!Z} z-(`hNFxfZMs9!5R1aV0>>va9ayj=Cx`?Wl)#Xg)eQzdYT@KwQExV4}%!M2z+1KDs} z`K_u~sLB*u?{_P6tzeeAzY2**%PMw%j}}X1?nx#0@-Srulqz0@*oCm%fLqAx^5EnC z+$zJUGvA~3nDI6$p}0(KM$zK#!_V0TK!@`(^*O+I{3<=U%T}ct-n^A;zO5h@Cll5W zra=-UX&yCWUK)L&uKNo5jT<=cQqkc^AS|U`8j=T!umn>qMb7^6;4eCCFiVJYN$C2S z0U|UU`n>FAqXPn#KbB$X1mAEk!KJ(&beZ}V&pdek=V+9AE~%?8DXtWjOg)#>z0CM_ zV6#he=TT99A$Y?I{-t1{XTdj`>51CqB;0An?D&%7d+YMz3&?)=Y4h;qB!lnu!oI{y z1oUs%V`RTKE-Ai)GltK{#MldTIm`F>1|9_i-}sWYkI{j}Cod^JdSymq?6|D>XnwCz z_vq-*%SgC=gY5=D7hOhp<`MN6I}b1I>;TU)ByNr_ExvtQte1865?sDJ-$Fa6-2+jO zdUSyW&r=^AsH>c>EO2FkD+^p%;K~A57Pzv&zlj#OcFBL#<-Fa@jCM&M*JSua=DVDp zZSSu?@2|eB_nYbO>R;0Jm=xb-UC&DK=}Wrao8qGv<1aDslV)!UJgT3-#SR`TT_!57 z6SYKmnKnCNpG0wQPV0#n%f6S0I>iC4b?_}LTV5h6;p^bF(aVgl-8)m4YKGM**1z`g z>~i5NwU4&Acew^&@oM3N4sG;)m#TdEj9u4xd%bk{7+yz8iulHP@DckoHm~6v8lA(y zH-XbPesbmo`}$da3D7)X?`2`^LE3p{s+`y%dfgiyJw1ESk z^>PL>M!^TXjhkNtymX|%MJ*gTd}Ev{L>nX+`{N`B!veIMBGHE00k(3xjkU$dEre)K zB1npv!#7ZdF@LdZ33NRQk_)@9OYyNlX|wsIwqn_c82BdmSJ$rRf7kgq)+&rPA6R@w zoh;WcbVIhrq4jWTNK_9mg8DWSX&eWZq2EjEmuugE(=j3tY)LevM~V-bJAC}1K}Fy! zKAqxIHe%b?h>)b)a?-j7C=MT5sv*2^Yb~Y`B>TB>$Hs2)>hRedJbcz#1N3x;Q1S+! zffb?tT@*gEf|l016d$ZrYM*GfKEC9_@QqMb*`~S_-wrS1iwgMAelEm*I1|p`OJC8Xv`uA@~8MZabHq}eERU9WpN zz~XcLUkX4u#0DR|v}CNA#%|Fa&EZ34GEilFJy+s@W=>a5+s_uE8Px_~3I<(`Avw@# zSK~P9Gs?~sH5epzA@~xQitIOs?@v>Fd}=2M`UBU3U@$#s9+wlwU+LKbv{Rr7F{YfsxcAQ`aTgan1d;|7p6O$uPcF&CGn5ocu5JC9T zpJbR@yWns$7XLWgbT6}v+`!cBW(cJO*O{>lZ~KS)d@*A|~E z|L)O(B%6o|*+8g6rzu&W@mOV%WIy@?rQ@FsZQ+Vq#Xmrq8A_a6<+vMBilUkrkq15c zw(BA3&z6KVWx1TZx@S+tU7loZ3Bs2ighO?!30)*Uzn^V7XY$H4_OLejX)DXDgU`!E zQeE68c|F`ZbEf0rHo-x+P>KtaQOeWi?W=h4a=NeKW7r=V2NoidU3vSgRBC;JHVf6AiHUiCLIJ}BYG4D zY%%~G7<7;3~Icd@8gBH6cF44`{>zh=5(*rc(Ggd+DE(&-*JN6#2NN#nC%*FUvq{J z#=CHQvHATDpEiNG({cE;vDv}Uuv@fm)5quA*hr)oUnu3R>)I_4MSR`Bmaou;pW#Ek ze%5n!QMvsTb1$9&9F-GKQj~V%ZyH+UN)uVa$5jXKM6nd##K_Qo)I!^y!#A;p7U^D& zzL#+kU!c6Gg$;S24eNm9l$kg+3 z8mz4vsX*qAjL+e-fjDG(7sg|IiQ&8bx*etoA3m7vi11OiZA5fJmN<6)T}7R8;2M0^ zz6h;Zz9aK)MBHZ*_!4$lz}F(P#Ow)NEdd`vL|f7*_|#}5qlnFN4gv;Wll>|tX?}@~ zx0e`aggU2~!#8D<1R?Z)bir>XW5(>dq5x5fuf={`z?Ya+#vYUfg9_Qg(9~^UnEpwBMiR!O=el@vWKfE z-0z)Q_6Q15h8Ew++wSY#0~^^2@o7ZaRmia~G3CnbrjguS9;vJ}GUrN>4aS#!za zQ@O>ijP`~dm*#Ll_#%r>VTZM`pL^Z7h3)PtdW@Y+@Ktm~vbHO(57xW`V1Y-Gx?O#nc3_^9c9*zIe>+g2d5 zAG!fe{-zX$!@U%rltp}@v6C}X3$Lq;<6ZV3WQu91Z%bUzlUaP3Sxg}!hDG=b-Amv- zQ}ryq(*zNXX=gAE(ymHUX7rZ1v)`V<=Tx;c(=qUUm%6$!m~D*<@U;w*tXX9EB%-Mf z65&(ZAdBzzl>AMp8+=P>r(9Zm5t@O4T)-zZQ++h-H@duUYJH%P#{&C7TZRvxQU_Ul zFaHDbH>EcEw8Y^XS$tqvd|lsuB4G+$H+!ushUOKNfQAUnx@h8HUs_d^DG*zdaMJmX z^zj+L6I$xv8}_EONKjgQ{USb>p%^nQQC?r`w)W9C8*5P4xQBQ?A$tcJTw^41Nt+$k z$e-a8{Hr4W4TxGo79Wlf07>M8YsfX)ga*Ud&-H&IWcP?S>2_W)AYi{E%}v!3{}p32 z-$8VaFG3(4F>-vIf0Zjig3XBVNpq}1h7Sjqxgs$54y+=v%givCbb|*5gqZM&wD>xI z$nblf(IlDWP5q10b0 z1^XolNt!g|A$%!V*&*cy?J1_0DVxNW5bVdblL=9}z$YH26~yRC@i`$9w$;Hfaloi@< z@t!fwV+B`QSvN!?z~8nU*U?nrE3`E$y|t@!npHUmYOx@6nq;>QJ2a!V;a%iKy3EvE zruKXUfP)FqQ%`M+nG@SGBeMGQ@-5}pvn^1ZCfRJJB(dFKWYynOHQAtlHX}*)CTES@ zmf7#t;X}TX@^-D7ypMuDqv~^&6qS!s^@3ZBad+`s%;9{hSL$-lmzBA*_Ens7gz;5v z#83T|Pv~MV6_xR2CZN9WDjFU(>+$EZW6gxFCZscK9wq z8Smq<5qplYrzZAJM!p!NKz#q=WQ8kLM%x3@l zaeL`FFbt(+xAC#$kiV)((|vQI?H->^@azqb7S<$lg2TJ4{oCeM^?xz1#oRiz)qF&e z6L)pOUjA^xLh)fEd~EP__&>r>GNgvGI{h;;Trt@XXMa3<|7DMNeCP!hc;oIp$zFb9 z!ggArCb?@YMpq+%4y%~dP~4Km0v&~@zw=WZ%#l7~D8wY}=gKl3K5-yje^!vF2*m9d zBlgu#$84t)k6k?BQ#rnpDJqoYEdJ@)C=V5Vn(-e#^NSCwma%SQeBX_j`qdElDR?`4Yi;7#kb$L2cI;?H^tt8ecWwyMrmW%#b5$_9rm;W zzUK7SY|(lFs)|QDpKewxahvryo)=&bR+e7qA?=32LNYyiXiEH#XUQU2VI!@5!)s4B z#D|qIfDk){$pB8AUK!u9L8odVl0r0`u=9uC!TRkBP0JTUFBvJJ)ERx~Axf7ft2|>Z z^9)F!_#ArV(%AF948C2q^Rb8U4IebeXEwPwRckwVT1ccdE>w>b{8<(~@JGP>V9d&Q zhVbdTZ%Fs(grb(v3YDx@(={8DXt;E{Fm-=$SSSfxmu?vZ3&$)F@812YR7_K31KI>W zXDf+;sD<+6A(QO;F7GgA7-&sp;VRUu_sY#kNzGIPY$VdWlGQ3qAD02&UgyJ_1$%hF z{Du>!0mEG2ZcDZwYe8M0=PQcgg?&x6`_kqy^${Iaugbv?$I{Y5+ zeRlT`eus_zo@NoT8_)*urMXB6d@R`y@!^5!HuWc%LP|45Ga#9Mirw!VewL1WMGd$p z63XQyr84+1F-yj<-=6q(LOU-&8NQR3;ujbTSmXNVbf3e?T9~}4x*`&j$~j@|mWL0wix-KH zC12LVJ)skW56w12JK%3p!J?zt1wLt>?V1KdObm78Y@1U1u_R8$dx1hPgZg)5@d+gq z0Cd?kR8481v=v4a40pJj(1x+)ONLLzQg+ezq2eXOaS7jz{e3E5BF(z8gMD`wjW3C> z>(&q`(A&}0qCOfe{R4H_r+`nA*Wklm(atr~b6eInubKUH{BKbkNB|5qkL+h%I9M?G zjV~g`kVg5oMGFOfA>`pR`5Am^&Q#Ap9oGKj=M6rt*$52Oz+vT$C`oUYa(q^=u29ce zr~Mby9O6^O?iqpBcxO~0xp`KGPg>o&A`7l~pbWm(+riHiW`wLIFWP=111y7EfT<{? zVZU~p-Baz~5m_%t5nH7U&}cz66o;zUieNO{|93vp#jN3CD8siXJBdgLwjv|c?gSYB zwnwl;PL1%9IN_5fUAJrZADh4yF0{0ok;A7mMx6%}F(FN4`&zq2z2rG4T9kIz-BB7D zhi|kffr&$3$fcE{*NL{+e0R*C9Ux9E02aj zw?!&fydu85+VM`VWWzqc0Rta(wvw{YbTJicM80a`XedVL>(%ia;QE_$fNuvSETPuI z2EL9h?kuN5Ns6@gZm)%$WjUK}EyP?Zf)9%uAk3RO?*2Ai`l!Z7!kec9(+qRHuwNhl zBJ^%gXkw#=rTFaX3nl}^Pg{@ppA-T+F|jsJ?hP%s<_G--Uu5w8Q$_g^J}`+SS~fLq zTcRJ*#5=$ee!|-QVML*glTey;rXO1~_{bCyCd>bWf`^{gc3cCZ+jJUfU5)#DKltCi z`^@bBeE9F6e)NA`lJLf9*O|r|1L_fu;NUO#e-u0hpD;c)#yfLQf#vYA!9V}uFIaFJ z4Zh!!;5VdI9uv`ux}miG4^c^p#%*CX5D3&rB6CZ0a2ugt5@W+@bXjG# z6LY81!zXR~Abe;Ec;B@5ffX9>bj(MNg(+p*>$Na9#cf@;-w2u!>ZbN@kVK~Vq!Why zMiyW1U4t*eYKBuN`(1WZqkOfU?@^D}G588Sj?+}@ge%}1Ia!`Kbp~Hd^$!m#+O1t$ zGR^QwtQsT?k3!8O2)46}6?}uwmUk_pV#F$sdPnY;3+;3OpGKRA48C2$*Y5zIDL#n^ zov=}W$5BMxPrnR&d$>IwnsCF*b$`COEDiN%pmb=U_Dk=_MHo0Z+r?YCGTsHgF#)^@ zwjR@M`kyKUS@(H78Wkb?3N^`8Q4g!6X$n`0m0`gb(lFCcxL_{GGoK0lXsM@LBO*w;jcz%fGG>*_>iF z7&VtJNfJIz@2mk|*u|ow!Na_uy!yup=B4YY#I+Ae!zh;Qq3;%hq{>{^<_oM@nM|M zyMo2LiIG4LE*a`&W_)i=t;K{DGLp+LkDpGK3t5Rp_)zWeerKSKq@ZDsDVvI}ROuXX z_AvD}atEYpCCZA~w;wd@`&wcSkdEkNh@4*6xqq22UM5f#pH@05Z|w;bltui_EXpfg z@XTH~K_TJQ!G!r2&T=M=#HsVsmJiZ+?86t-d zA+opjT5w*wj9|s3tsRrAaq)M8AC#J2Dg7rIPg5hN@arNH?a~~NTyv!v-xtsmYL?hA z)MtZ_49#iZ-@G17d;p)xJG3N8w zfeJ(X^zK~$HwW0sItNcLRL=2)?fU6i_qxvUbu^}~CkjdUZ6@eUDBLp>(6l>D zy{WsTt8e9t2T0-Ji$@5fb=-s#nHW4Kl8>vF!582dzpm`Ey=x8L4aS=RDRsuFFLh<= zsdih15!=HTDI~yR(_g}gRkG6>a`p$K$MF-$ex2Q&Ae7zyjeYh)wPKGeWfs7XE0HXP zOTiZIyL0mJN#gbeOW*)s*ory!$^RDW9N}x@?sq76_CGts&B-zv%^A&0p*??vw{@I& zTo2!0GKqq<`v&`E3UeN=doIYi5K$lCBQ*vxxK4sx~D^&xT6wDa7_9B zYJ2Z`5)%`NJ<_)EJmhWG7|pt zEDVECt>}+(&H^8ujaVks3`cXeO(U#Zi_eGSb&F|g4{XY+bLoj~nQ~6razx<1x^_sl8PK3JDV-iC2+`BP8H=V5&OAZVl7|Z8q(y`)PuEG z&!2NspTH4AIgN8~>XWJG94;DRk@6i6MLvaefmQ6sD)2=G@eKt6U9D&Yc1@H?P=QaH zh-{$En@ZnBtm9-4OiPJ1!t_^13-HY)IS;<7PI;g$HaN8;=VKDbvVE90Us*CR&1>>F zvFA5l^nwS;iueQ)m{dl?96rNc^D-)@!vhqW4QcS{uZ{}k8{CE1apGiMA3-qj*KypH z9jbYSk=SbZvSL!Mh_Ck=(q{OmdVoUQGyxy}&v$A@V9BK`8GCPD=AL3xy&}GAQ_T5h z2`*p5-$Sc3+@U=k{r9MQO%k5r14qJr<)ruUEb@ zVd9u{6$oqiG*Hl!>%w|{L5Ku=#xbOMl3)enbNm~cV*Yxh`ZraC8}7C7{U^%Y8jv=R zFo)vEODBxo*B-y@E#iYDmxo7qy@UTRluCS0(=+sl(f>8=_od3Vk6ApnaebhaF1{JP z7@q>ZcPBq)t&snd1foGgH5>myqc!o#8hkgf--fHx2^M?;MHy65!G5wQZza=TY z`w5lWuV3+`ibNKYVC?T|yhS(nNK3?T@fj9S-XMITCMC=99kL+~#dz-Ls)eP4n9{T< zk^SFjWrNcA)W%`C$t!{df9-SO=hL_NS$yy09l~d_DlFS)(gphwK6NGzbPIb5Ej}w4 z7$?k9HTGcCVZ6sr-keYI->T@~-dmHg;5xFgdS0m5zZ|kZV(PF3gFVr)rFo5#j9j|D zb60R^@3I)E_vi8P4>TV99NnFW|2&aaqpna~u-~x%MJh~8D6W6s$oh9RrM|L4R|PA^ z@GU+_ZtRxg(D%KoiFXiV`>Z6N9gD3mzZUV0j~%|`(27iQNlX*`Kr=r*p2jMycXw{n zp;~K2-u)reO7dy^o2LT4!DMFe&5Nze8M#JZv>&XeoJJh_z<{rJ#x>WD=Q~Aw`hJ$s z7h2!1>CIeF5uZr=EX4Hj_h*ydLp;{g@Rq57ug6X{j8E-aWPyLr&Cp+K9|+wL@ABpN zkcRu|&h5vZL5r_=`-^V~X3#{V-fx+6cZ}TZ%7LZ(a2My2ud^fln2A zCRD~(7HO~3YO^1i*{`S;Z$RlHCwSOjhz~Wkn%2UXbpl*fzRHKU0CX`s@gNTFt0K>Y zB<5k@17Eu$788VQ^r(!kVU8T1t3k2lTK+sfbgsSEtCUF#Y#yJ3yR#NPmlNvQGwv>? zkax(nDlia`Lw7$`jF4m^-+t5|5&8HAiD9jL*~j+tLdW7XgyNnmD;tmZ%Pa~@yAFgF z=K!VnOuwpd+pE1>VoE{1S3{bxXVZbQkRt5-q!6aSK{Cf8MuIzAp3oy*y!1&lhfkI8 z@mof&$t9`T2HM@5*D*jo6@=$~F+0)o_-N+F$bPE0oZYJVp%uD?uDNB|#dy(>lHN38 zcZ~gP0jKu!@WH;OksFo0stQ$|Sy0V}GAL|F$zUQ;^~ip9Bro98n7%19aPLM=;q2|B zhN?@Gf~Kj8a>-{he4&X+@tKgp*Frh5(DEk-XM@Uqps3Y`_T01Cs<@`S$f=T zM>`7VgaF^OcNFk-+3#R)(=565YiFkEcuMNL5;{!$E^Qhb&BKHZXNY+&F}b{*K0U8JU*Vld7;K$ zj-=i};G77S+W`t0G|hWJ+KhU+w9f~F&WTeoT0 z4@EbW{hgbEIEj*eKYmt?+B@HjP6bvtTaUBfQGE7ub}+etCf3Ua;QK0jQB(EjmIFTa8TB@8vJEuwJ;C|` zzy2b-HtZ8V9GpX0U`jymq>mW8H%r)`;_sq}@bxfB1wJ$p*7-Y_|6zrk?O?nmdZ&_$o>^Q;w`wB5`V0C+$?#Pf8`8VIHxshVZ9V6P%#bmuV=O!w2;lQFpl#1u#m7UE`-} zK{8X-tET0cv=owQgzOh?J+_Z;=OQkz+6_0ZsJ zbRGTFzK3ZM1O(FQhSkt4s8J@DPPChhnSozH~2-o{k@{5D+JC!w!c@}3hxZy{(ZXZdeui(L zS_0-oH|^KcG;ITyV`+!&?HfrkJ#3JoB;w)2xkpi}gb$yI#sCO>GzzRi246Y^Bo^mN zYQnsH@gN?ry5am#*e|k5t}!m49r&o=*C2~;jf82E(A^&)jB}B2EV0=Nhg)_-z(++3 zd~0^lg39+i6y`OH4jgZ>87V}aGjqN@Qca%|S+dED#42e6_%glSTZ9kq9D#$^7>RE# z_Vh60CEiLT#Ql}z=Y;*)Ux)C)c=!vH>5yIQnvDZ`c;`7>&p|^kE%2q}j^T6oOj)N< zE4lpZH&&9L6Lt;3@H;JA>vADisO#fn)Ai~_2EoVI6=A1}DkPW-L>|X4E04X< zTgYi{6Pz10<~lz=*M;f}k^6;Evp@mgToQ*5onVooVz6Oo z&t{2T=fjTJRY}$-AO!ryay;;{mGD6vPk(7?RQz01;+05NOH)mziC{gxyq~GoP{sB8 z(W>|go~+=3b*yp09}Wdc$u(Cq9RrzrPl~!>X(n^9aX0aV^1w#k$!b(FIzfE)H;D z)9>>;Hn_@_C#y(XSy`Ec>jZq*ZU--KS<3MN_WvC6+YYabZsLffiBwTW7K1KiZ$GfM z+NbS0hPn|sdpLL;kne`J;Q zEjv-BpRDDG>jU+I#m7dL7ko>Pfo}wS@jcajX`Q;Bs$a#GnQ#C=%!~?}3hyC;a8hc= zdWs%p6o+^nQ#tHuPq&P~1zcb?M>5BkXu}i0 zhtJuD;dQi>QAD#}RDz480=`b55}57O*)IT;7LQqfjA}VD3%|L!F9>FyA&_;t)IQkh zO@%9M_@pjJvA$F?9Y;*W1zrmHM5s0LeiJo~2=hPSL!*sUA0_-qD90z!SSL3%?m7aV;L%j(I^D0L|IS+T8iwSDSydWpX7ucMsQ??YO9_QNj zp-S8>2XlPxIGS$OOkFQs0`SQ2r8qKtb~P-kcrO0Y<0~M@*4HqvF$fE>hO^a6R=(*v z70pU>dZ2T^!N*U^2F(Sw;mh#l?Lv9^e9H4%`-xo8i`$xam}(AG>dQPS!?_mUM;;MA zo}_buh4}b$z$Z({w;0UqM=z_{d~_+hw8tj5N&*4N}McGxAC|X-|=jc zr1;`KS0{U8cA$~nuDF9M@J(^6j?dFvFu791dQ~EWJBsSqy-7c~cd|cbQX@oPqhsvp z37?8ih|gnRFy-?G?SE09{D!t?JkYK-#y$~?*E*ee$4zoB4y1=K4*oC3 zTf-g}A`kWH?`ylhhI5sH=2zk%Y<163((G+2)-;UUhYH3Pyk(A;?o=ID@ zu|T;ae)oDJ?<;M~_ZB03!+u+*x5XC;&%4{@8vDa&0ad7{M)H(SxCKNe4Zd+7wXk}^ zx?Q;AOnsn$uY$UZOMYxr~|9cz{nCWH$9kttT$M?{!LU7(xe z8{z|<+-xAvvRCj~d=X7sA1ywK4-jU^jK@qDG<)))2|XHoQ4!L7NVCD;I&L~v&kJpj z6D?6K@VV(!q@Q{&(2bVl1$@a8k*!8YOSFsGzgi;kXrp=ZX!F0y{mKGY7Pzv&l?ARW qaAkpiEiDjTa@1G&&R0NJ_Pes*`7Ch0)K~TI-)#Gx@7G;ba3xKx%pL=k=e+wJ&v<1uH;`KDXW$DivMG}CM1Do2l%D5_{L*DpB;|?xibyFv&lCBj z%jQYS6A3)gk0)c`i3FZV;E4pDNI**9Xv^g=FURMU%l;(y6A3(#z!M3angm)|E$?L| zZY0h0EYC@8shggZTBg|q!N*gpw4KzX4JDYKnIS)Wx*?3zW=w~5oYd6mG&N~M2_|FK zhMKC>jOnudjDkBEX~{`Wa&*;L(@W(upib!i({;etPa`mnS*CSNE7xSa;W@pu`k-@9 zoez3&oW}S1Ht-od>jLA4(%3f^pTXxab_V{RuJfEU`3Fup#to!ejZ$KQ014S#!^=wLDM#o^Ss_XbRB;C_^`qqZx(+w#ZU8BQ<$ z!`H>SMe;d6HC4Yu@?QZQF(Z9uJ{{s6;}52v20jkW8^E_++94JzOa3>y zm)KN@XU+^$9Jk1|*j@fg_l7^A44LuP7O@GG7IXP$zxDGzAA}d%#%H+v*Z2NP#J6R5 zY{zh~{ok`Yxo(5u@_um+&0@HkPQDybHGJl8@CnETJY2_ z&83v|KRa?w)nW$M)3zaIM_zNlA{t3^8_0YHpKr|A$@VZsByhcJ$^gtAgD7@;JkL2k z3v9bFEAaa<+wu2f&JG&^ieNMOb}%6d=hN&6A`V2PEBPy((ZRY5PTiUWqiox zaclnc_7AK-GncF%Y?;s8twEC@d;8C__stbMD@-7`i7O9V^JjPeCFi=?Vxin7^SWqa zFT&rCs9TdLzq>!Vc>RIJ!aJJv`Ao;|#S2O37WgM^KeXnECQG?i`|LG7FpXQ>FE&|} zDxQ$pbX|?_tjyPw+Z58f8>~qZ%Hyb=_K$K7`v#ut$Iq5Hy?n^L5Bm^KSk52T{{Cz) zUjOb(K1hsn`X#1e!Qi;lAG+YRJll_WRG-fSKEE>fJC?q1|CopIseECE@M!dy4gLXC zDxKpWYWy|5`NA~eCjAPG>SE#=3xkXO&j|=CXoLkfC==wTHT$`*_So z?s3cb&i%jV9vVwF*|*>?OamQfcF()!UAuJ2yCP+s!RM=gMusv;CIkDjG@QQKS&iC9 zz~?Pm#+&z<+Xws7Y3+-<&j$?5=|x9HUl`mSSaGNz%=jseEY`R zcf_4D$MCGaaUyQGm~1&dGT7}mTgGLx2YFMSvA}$N%T3K&Ai)F>7-&vg;cFXx$;U0v z?02Al1)nzuzH`f#@rF6b8vfSej-$4F(s9*b*{eF}xW2jX^Npqa<_zTb8bmXG#WNOz zn9pSAR{ME;op-SjKM8h=LdgEW3B5&*rgLs~sb$WEeL1^?{vF!D*M7}`@ptW;mND=3 z#i|pA0UMon&Uv|f`+XAu91bwX;S43?L_Gw2-X+Ui2%9lj9F5p$GM`+0^PJ~;&g`=1 z%!M+v4lVas@LjvSZ(I&`(e%3fnDO8Wn54+{CXrWqPM|-^InObG4~lgb!!Gc-lS}P$ zU`(9ZrALk{1ZyoO^O-xi4fe(IE}LRVrZ{V9E@n!)<@6>FdOqt+G%KZ4ksUo6earz> zVV`m)&Vb!#Q|r&*YG)2Y_4zJ&7FeRxIyx(Bu@dJRxCtN6ZX>=Im+V5ATHt7Si+Fhe z`N#eYrIq9cxA^QLES+|YjQOLp>dY5AzY`S)J~2|FFq=NNGP2Y^&guImp6{*>;5eVH zYOZ*#Wrw-`{a;!CfRB&dPsNRT?yFuYK7p0s-h0p6dEotR#)f-r;=La?kn1}zTqTde zMz5-2&wb5fe@n?w$lJM}fS47PJ^;(Qy6CalQ$eCT)}I6{$duIOv4DMk-1@Q1xsdJVcF0G7r5@?u*q?_c*vNGUE_&WlP}!+3mUfEz>^ZjsaYY* z6${e~oqBwR=b}bvbu^4JX9hZsxUxAr$jp?RXxzr5W9Il_6r{kE1wwXdwk|(Wy?x~&91}X-cgXvaKqhLKZ1s{YQt&9_atAh zhV&R*SspXAe_*+I{bzDvB&s-gk;8;8?%i{%l=jQOmH8a=bqJ5i5q^oLfNub3y*k=4 zU~u(jaHZ7&xitYsOifmD=6T_=bOJ?t;*aj+WzkfR$1#2R%z>*!p2fJZ)sC(|m7KZW z7L09hLnCaXz#{!BhmxD#_JK3A!CWWEI<)dB+_;sI+7|0=m$zOdGV ziGqhjIJVw_ObVYEY>4NWgu^-u9JBaZiRBFex=@mO)|Dk}BgQeHbZ|ReaUjnVC0NG0 zpE3Tdw2Dlprz8#TUWS_{h|f`W10kmecc_#CWxQE@{v-bhwRO14*SUXb8QnY=x#8_N zWj7TfYVc+CZz|se@tL=sC4TC8=5*dwPiy813slKv@gFA3_l}jiwvNwsyNWsh>0X}vQoBMq%|vgO{8Go?%jsJ zoyX@^=F8HL)Jo4YqQ8f0lV1tGSe?&1U1hlfJ)5V$)%$lp^zj!zrPFJ0Ph5cLC z_{&-!5I)NRNl9m*^$SGh+2=a)8wHK(hg3fKz?+(XeSB>;R2xEm!l!<5ql+@;%P$_g zxL|H*w>Y1AjYs(WC&Z%0cIf(rSLSOK=X;Sy092_+|LT0CE8>dseEY@uURC(8`m!F@ z-$wZg>&L@%K4M>5TK{f9erS(*jQeGMe8u$_@sa-BV~T9WE16_{U)}x{=Zl_y6`~`2 z%44-6^;GyQ#};k-t|XsZdHfZ(fBVc1=`{JRuYZg49jJRgL_fBnfBWi6dkgt`#rYbv z&&Bmu*&`dmhCOoY8-Hc^qD8@Iw7|2@cJM_a8+~qZ6a|E5+xQ+moFl$%&|d|p=e_4D zL17NL8n&98-)yyJ?kxZ%O&o?NvCjO{}jJ`R(WOHMst>m4>l5Rer7ZfU~`?$lT^Xn4Wo8lix=8Qpeve z8@T9HPH6vbgs(OEpKm&*gGhn^c_94oRQL?Jw@cag^jmYTW zPowt5R%^!ofG^>|yGqUrYn^{H_$0&cC*XNp!Gqg@>s%k?@iFFao_O9z|LE4u4_6Y` zQTX81+S8fe6bA4ebX>yLjalmlwJpJ7O zAG$n`;lO7&i#)zM^RJB>OAVxNR2%>2Ht-$bM;_Gkc)VPveiW2nA8vA_xGw;oqo%dM zAR@Pc{ynDG6fr<|8~Eld-A43@{5Eub6iWz{)Mb_$Mt;h-sr7*ZVR4qc(t9#YyMVYcDK0Ln})%nPs(e$$^C%?w{ zis}b!j`J*dM@^*bgBtSNe!i)C=Ba+Socyr;t0li?_|S=I^KW(iDB8dC9Qmz_ug40> z&wv{q95J8(nLl>vTDH3U3i7cWKEqLYPl4~-HRQL;>d5b9hZ&1WSA2X32|*PIW8WAV z9LK1k?EZx>kyM`FdTf@oKLv5O;mz~^)%(hu|84hE?Az>X<>ZIv5382^()cj;2cs-S zQg;JEuDkg9(z;kjep7ZP>M9F%Nju)-pT6P!7RK|;ktS%D{o7%|t`Yj=v0*+`cS^t* z!3Vff-8|e1_H+Cxds@xklS{eRib?Wf_k~a(V%s)It zA#e5Qa}cr2enUHZ{$*AjK8%wRT81At#bOFWIr>|R?}k8HO;W&u=+$x*vLqdI_-gep zPim0HS+G7GsHd=+t=P`^g|CQ=Tt1mK6kc$q@jB@5&dZQ{0Vn>g%U^}JPb;slx>?J1 zzd`ZWg6p@dDj)XGG5q)N{JZeh&&Nk#g3s;$&J2SEp*ehyN^#$S`Au;TAFZ7azKNv^ zy2rW`iE(vqJnig%?4I}CnfH~>-9I4q<=NYH_#DxH`7VJkE;Pzq{|#!aUkZ*t@x}s= zd8m)fA7p+T)L1_^#Fs5Uqk8|cEU~C!%9bDHQ%kY~1FlFaJ6^10CSUgW+cj9LSR;C_ z!u>nMOFUdtHXqy}UO%6(f2l5yZv*nH(ZBHdrS;42C`*y@mE{YPm7!E{)kj6aR9`ue%B{YΜPan^Pq%+H^tYh= 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 diff --git a/libs/spandsp/test-data/itu/fax/test4.pbm b/libs/spandsp/test-data/itu/fax/test4.pbm deleted file mode 100644 index 1ab36c3e86bf2caa958b2fdf95d0ad0285ec3121..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 279213 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